Massive refactoring of the methodology in former class UiUtils
[taxeditor.git] / eclipseprojects / eu.etaxonomy.taxeditor / src / eu / etaxonomy / taxeditor / model / CdmSessionDataRepository.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.model;
11
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;
17 import java.util.Map;
18 import java.util.Set;
19 import java.util.SortedSet;
20 import java.util.UUID;
21
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;
30
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;
45
46 /**
47 * @author p.ciardelli
48 * @created 17.12.2008
49 * @version 1.0
50 */
51 public class CdmSessionDataRepository implements ICdmSessionDataRepository {
52 private static final Logger logger = Logger
53 .getLogger(CdmSessionDataRepository.class);
54
55 private static ICdmSessionDataRepository repository;
56
57 /**
58 * This map of taxa to their taxonomic children is used by
59 * NameTreeContentProvider's getChildren method.
60 *
61 * key = taxon, value = key's child taxa Note that a map can have a key ==
62 * null, i.e. no parent taxon
63 */
64 private HashMap<Taxon, Set<Taxon>> taxonomicChildrenMap;
65
66 private CdmApplicationController applicationController;
67
68 private IObservableSet observableTaxonSet;
69
70 private List<ICdmTaxonSetListener> listeners;
71
72 private TermVocabulary<Feature> features;
73
74 private SortedSet<Rank> ranks;
75
76 private TermVocabulary<NomenclaturalStatusType> nomStatus;
77
78 private SortedSet<NameRelationshipType> nameRelationshipTypes;
79
80 public static ICdmSessionDataRepository getDefault() {
81
82 if (repository == null) {
83 repository = new CdmSessionDataRepository();
84 }
85
86
87 return repository;
88 }
89
90 private CdmSessionDataRepository() {
91 getObservableTaxa().addSetChangeListener(new observableTaxaListener());
92 }
93
94 @Override
95 public void clearAllData() {
96 clearTaxonData();
97 clearNonTaxonData();
98 }
99
100 @Override
101 public void clearTaxonData() {
102 removeAllTaxa();
103
104 // Clear "recent names" list
105 RecentNamesView.clearRecentNames();
106 }
107
108 @Override
109 public void clearNonTaxonData() {
110 features = null;
111 ranks = null;
112 nomStatus = null;
113
114 // Parser is also transaction-, and therefore session-, dependent
115 CdmParserController.clearNonViralNameParser();
116 }
117
118 @Override
119 public void setApplicationController(CdmApplicationController applicationController) {
120 this.applicationController = applicationController;
121 }
122
123 private Map<Taxon, Set<Taxon>> getTaxonomicChildrenMap() {
124 if (taxonomicChildrenMap == null) {
125 taxonomicChildrenMap = new HashMap<Taxon, Set<Taxon>>();
126 }
127 return taxonomicChildrenMap;
128 }
129
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.");
134 }
135 return applicationController;
136 }
137
138 @Override
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"));
143 }
144
145 @Override
146 public Set<Taxon> getRootTaxa() {
147 return getTaxonomicChildren(null);
148 }
149
150 @Override
151 public Set<Taxon> getTaxonomicChildren(Taxon parentTaxon) {
152
153 // Check whether the map contains children for parentTaxon
154 if (!getTaxonomicChildrenMap().containsKey(parentTaxon)) {
155
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>();
159
160 // Root taxa have parentTaxon = NULL
161 if (parentTaxon == null) {
162
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));
168
169 } else {
170
171 // Get children from taxon
172 childTaxa.addAll(parentTaxon.getTaxonomicChildren());
173 }
174
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) {
178
179 // Some imports resulted in NULL child taxa
180 if (taxon == null) {
181 if (parentTaxon == null) {
182 logger.warn("NULL taxon in root taxa.");
183 } else {
184 logger.warn("Taxon " + parentTaxon.toString() + " has a NULL child taxon.");
185 }
186 nullTaxa.add(taxon);
187 } else {
188
189 // Add the taxon to internal collections
190 addTaxonIntern(taxon);
191 }
192 }
193 childTaxa.removeAll(nullTaxa);
194
195 // Put the new set in the parent-children map
196 getTaxonomicChildrenMap().put(parentTaxon, childTaxa);
197 }
198 return getTaxonomicChildrenMap().get(parentTaxon);
199 }
200
201 private void addTaxonIntern(Taxon taxon) {
202
203 // Add it to the transaction
204 CdmTransactionController.addTaxonToTransaction(taxon);
205
206 // Remove then re-add session taxon
207 getObservableTaxa().add(taxon);
208 }
209
210 @Override
211 public void addTaxon(Taxon taxon) {
212
213 // Add taxon to its parent's child map
214 Taxon parentTaxon = taxon.getTaxonomicParent();
215 getTaxonomicChildren(parentTaxon).add(taxon);
216
217 // Add taxon to internal collections
218 addTaxonIntern(taxon);
219 }
220
221 @Override
222 public IObservableSet getObservableTaxa() {
223 if (observableTaxonSet == null) {
224 Realm realm = SWTObservables.getRealm(Display.getDefault());
225 observableTaxonSet = new WritableSet(realm);
226 }
227 return observableTaxonSet;
228 }
229
230 @Override
231 public boolean deleteTaxon(Taxon taxon) {
232
233 // Remove taxon from repository collections
234 removeTaxon(taxon);
235
236 // If taxon has been saved before, delete it from the data source
237 if (isInPersistentDataSource(taxon)) {
238 getApplicationController().getTaxonService().removeTaxon(taxon);
239 }
240
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);
245 }
246
247 return true;
248 }
249
250 private boolean isInPersistentDataSource(Taxon taxon) {
251 UUID taxonUuid = taxon.getUuid();
252 if (getApplicationController().getTaxonService()
253 .getTaxonByUuid(taxonUuid) != null) {
254 return true;
255 } else {
256 return false;
257 }
258 }
259
260 @Override
261 public void removeTaxon(Taxon taxon) {
262
263 // Remove from session taxa
264 getObservableTaxa().remove(taxon);
265
266 // Recursively remove all children, children's children, etc.
267 clearTaxonomicChildren(taxon);
268
269 // Remove from parent and from parent's child map
270 Taxon parentTaxon = taxon.getTaxonomicParent();
271 if (parentTaxon != null) {
272 removeTaxonomicChild(taxon, parentTaxon);
273 }
274
275 // Remove from recent names list
276 RecentNamesView.removeRecentName(taxon);
277 }
278
279 private void removeTaxonomicChild(Taxon taxon, Taxon parentTaxon) {
280 parentTaxon.removeTaxonomicChild(taxon);
281 getTaxonomicChildren(parentTaxon).remove(taxon);
282 }
283
284 private void clearTaxonomicChildren(Taxon taxon) {
285 Set<Taxon> children = getTaxonomicChildren(taxon);
286 if (children != null) {
287 for (Taxon child : children) {
288 clearTaxonomicChildren(child);
289 }
290 getTaxonomicChildrenMap().remove(taxon);
291 getObservableTaxa().removeAll(children);
292 }
293 }
294
295 @Override
296 public Collection<Taxon> getAllTaxa() {
297 return getObservableTaxa();
298 }
299
300 @Override
301 public void removeAllTaxa() {
302 taxonomicChildrenMap.clear();
303 observableTaxonSet.clear();
304 }
305
306
307 @Override
308 public boolean saveTaxon(Taxon taxon) {
309
310 // If this is not in the list of observable taxa, add
311 if (!isInRepository(taxon)) {
312 addTaxon(taxon);
313 }
314
315 // Save taxon to CDM layer
316 CdmUtil.getTaxonService().saveTaxon(taxon);
317
318 // Notify taxon listeners in case name has been updated -
319 // updates editor view tab and recent names
320 taxon.firePropertyChange("name", null, null);
321
322 return true;
323 }
324
325 private boolean isInRepository(Taxon taxon) {
326 return observableTaxonSet.contains(taxon);
327 }
328
329 @Override
330 public void setTaxonomicParent(Taxon taxon, Taxon newParentTaxon) {
331
332 // Get old taxonomic parent
333 Taxon oldParentTaxon = taxon.getTaxonomicParent();
334
335 // Set new taxonomic parent
336 taxon.setTaxonomicParent(newParentTaxon, null, null);
337
338 // Update child taxa collection
339 getTaxonomicChildren(oldParentTaxon).remove(taxon);
340 getTaxonomicChildren(newParentTaxon).add(taxon);
341
342 // Notify listeners that taxon has moved
343 if (listeners != null) {
344 for (ICdmTaxonSetListener listener : listeners) {
345 listener.taxonMoved(taxon, newParentTaxon);
346 }
347 }
348 }
349
350 @Override
351 public TermVocabulary<Feature> getFeatures() {
352 if (features == null) {
353 features = getApplicationController().getDescriptionService().
354 getDefaultFeatureVocabulary();
355 }
356 return features;
357 }
358
359 @Override
360 public SortedSet<Rank> getRanks() {
361 if (ranks == null) {
362
363 OrderedTermVocabulary<Rank> rankVocabulary =
364 getApplicationController().getNameService().getRankVocabulary();
365 ranks = rankVocabulary.getOrderedTerms(null);
366 }
367 return ranks;
368 }
369
370 @Override
371 public TermVocabulary<NomenclaturalStatusType> getNomStatus() {
372 if (nomStatus == null) {
373 nomStatus = getApplicationController().getNameService()
374 .getStatusTypeVocabulary();
375 }
376 return nomStatus;
377 }
378
379 @Override
380 public SortedSet<NameRelationshipType> getNameRelationshipTypes() {
381 if (nameRelationshipTypes == null) {
382 TermVocabulary<NameRelationshipType> nameRelationshipTypesUnsorted =
383 getApplicationController().getNameService()
384 .getNameRelationshipTypeVocabulary();
385
386 // Add all terms manually to transaction
387 ITermService termService = getApplicationController().getTermService();
388 for (NameRelationshipType type : nameRelationshipTypesUnsorted) {
389 termService.saveTerm(type);
390 }
391
392 // Get sorted list of types
393 nameRelationshipTypes = nameRelationshipTypesUnsorted.
394 getTermsOrderedByLabels(Language.DEFAULT());
395 }
396 return nameRelationshipTypes;
397 }
398
399 @Override
400 public void addTaxonSetListener(ICdmTaxonSetListener listener) {
401
402 if (listeners == null) {
403 listeners = new ArrayList<ICdmTaxonSetListener>();
404 }
405 listeners.add(listener);
406 }
407
408 class observableTaxaListener implements ISetChangeListener {
409 @Override
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();
414
415 if (listeners != null) {
416 for (ICdmTaxonSetListener listener : listeners) {
417
418 if (additions.size() > 0) {
419 listener.taxaAdded(additions);
420 }
421
422 if (removals.size() > 0) {
423 listener.taxaRemoved(removals);
424 }
425 }
426 }
427 }
428 }
429 }
430 }