3 * Copyright (C) 2007 EDIT
4 * European Distributed Institute of Taxonomy
5 * http://www.e-taxonomy.eu
7 * The contents of this file are subject to the Mozilla Public License Version 1.1
8 * See LICENSE.TXT at the top of this package for the full license terms.
11 package eu
.etaxonomy
.taxeditor
.model
;
13 import java
.util
.ArrayList
;
14 import java
.util
.Collections
;
15 import java
.util
.Comparator
;
16 import java
.util
.HashMap
;
17 import java
.util
.List
;
20 import java
.util
.UUID
;
22 import org
.joda
.time
.DateTime
;
24 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
25 import eu
.etaxonomy
.cdm
.model
.common
.Annotation
;
26 import eu
.etaxonomy
.cdm
.model
.common
.IAnnotatableEntity
;
27 import eu
.etaxonomy
.cdm
.model
.common
.Marker
;
28 import eu
.etaxonomy
.cdm
.model
.common
.User
;
29 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
30 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
31 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
32 import eu
.etaxonomy
.cdm
.model
.description
.FeatureNode
;
33 import eu
.etaxonomy
.cdm
.model
.description
.FeatureTree
;
34 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
37 * This class is a simple container to allow generation of a datastructure that
38 * describes a feature tree according to a specific description element, i.e a tree
39 * structure that halds only the {@link FeatureNode}s that are relevant for a specific
40 * {@link TaxonDescription} as well as the {@link DescriptionElementBase} at the leaf level.
42 * This kind of datastructure is needed by interface elements such as viewers and greatly simplify
43 * the handling of {@link FeatureTree}s in conjunction with {@link TaxonDescription}s.
46 * @created Sep 20, 2010
49 public class FeatureNodeContainer
implements IAnnotatableEntity
{
51 /** Constant <code>comparator</code> */
52 public static Comparator
<DescriptionElementBase
> comparator
= new Comparator
<DescriptionElementBase
>() {
55 public int compare(DescriptionElementBase o1
, DescriptionElementBase o2
) {
56 return DescriptionHelper
.getLabel(o1
).compareTo(DescriptionHelper
.getLabel(o2
));
60 private FeatureNode featureNode
;
61 private List
<FeatureNodeContainer
> children
= new ArrayList
<FeatureNodeContainer
>();
62 private List
<DescriptionElementBase
> descriptionElements
= new ArrayList
<DescriptionElementBase
>();
65 private DescriptionBase description
;
70 private FeatureNodeContainer(DescriptionBase description
) {
71 this.description
= description
;
76 * Traverses the given {@link FeatureNode} and computes a FeatureNodeContainer branch if the
77 * given {@link TaxonDescription} has elements for the given feature node or any of its children
78 * or null if there are no elements.
80 * @param description a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
81 * @param featureTree a {@link eu.etaxonomy.cdm.model.description.FeatureTree} object.
82 * @return a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
84 public static FeatureNodeContainer
CreateTree(FeatureTree featureTree
, DescriptionBase description
){
86 List
<FeatureNode
> children
= featureTree
.getRootChildren();
88 FeatureNodeContainer root
= new FeatureNodeContainer(description
);
90 for(FeatureNode featureNode
: children
){
91 FeatureNodeContainer branch
= findLeaves(featureNode
, description
);
93 root
.addChild(branch
);
102 * Recursively traverse a branch of a feature tree and check if there are
108 private static FeatureNodeContainer
findLeaves(FeatureNode featureNode
, DescriptionBase description
) {
109 if(featureNode
.isLeaf()){
110 return buildLeaf(featureNode
, description
);
112 for(FeatureNode childNode
: featureNode
.getChildren()){
113 return findLeaves(childNode
, description
);
119 private static FeatureNodeContainer
buildLeaf(FeatureNode featureNode
, DescriptionBase description
){
120 List
<DescriptionElementBase
> elements
= getDescriptionsElementsForFeature(description
, featureNode
.getFeature());
121 if(elements
.isEmpty()){
124 FeatureNodeContainer container
= new FeatureNodeContainer(description
);
125 container
.setFeatureNode(featureNode
);
126 container
.setDescriptionElements(elements
);
128 return container
.buildBranch(null);
132 private FeatureNodeContainer
buildBranch(Map
<FeatureNode
, FeatureNodeContainer
> featureNodeMap
){
133 FeatureNode parentFeatureNode
= getFeatureNode().getParent();
135 if(parentFeatureNode
!= null && parentFeatureNode
.getFeature() != null){
136 if(featureNodeMap
== null){
137 featureNodeMap
= new HashMap
<FeatureNode
, FeatureNodeContainer
>();
140 // reuse parent container if it exists
141 FeatureNodeContainer parentContainer
= featureNodeMap
.get(parentFeatureNode
);
142 // create a new container if necessary
143 if(parentContainer
== null){
144 parentContainer
= new FeatureNodeContainer(getDescription());
145 parentContainer
.setFeatureNode(parentFeatureNode
);
146 featureNodeMap
.put(parentFeatureNode
, parentContainer
);
149 parentContainer
.addChild(this);
151 return parentContainer
.buildBranch(featureNodeMap
);
157 * <p>Getter for the field <code>children</code>.</p>
159 * @return a {@link java.util.List} object.
161 public List
<FeatureNodeContainer
> getChildren() {
166 * Sets the list of children of this containers children
168 * @param children a {@link java.util.List} object.
169 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
171 public void setChildren(List
<FeatureNodeContainer
> children
) {
172 if(descriptionElements
.isEmpty()){
173 this.children
= children
;
175 throw new IllegalStateException("Container may not have a description element set when setting children.");
180 * Adds a child container to the list of this containers children
182 * @param container a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
183 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
185 public void addChild(FeatureNodeContainer container
){
186 if(descriptionElements
.isEmpty()){
187 children
.add(container
);
189 throw new IllegalStateException("Container may not have a description element set when adding children.");
194 * If {@link #isLeaf()} is true, i.e. this container should have elements, returns the list of description elements.
196 * @return a {@link java.util.List} object.
198 public List
<DescriptionElementBase
> getDescriptionElements() {
199 return descriptionElements
;
203 * Cumulates description elements for <code>this</code> container as well as child feature nodes recursively,
204 * thus returning a list of description elements for the branch of the feature tree starting with <code>this</code>
207 * @return a {@link java.util.List} object.
209 public List
<DescriptionElementBase
> getDescriptionElementsForEntireBranch(){
210 return getDescriptionElementsRecursively(new ArrayList
<DescriptionElementBase
>());
213 private List
<DescriptionElementBase
> getDescriptionElementsRecursively(List
<DescriptionElementBase
> descriptionElements
){
215 descriptionElements
.addAll(getDescriptionElements());
217 for(FeatureNodeContainer container
: getChildren()){
218 container
.getDescriptionElementsRecursively(descriptionElements
);
221 return descriptionElements
;
225 * <p>getFeatureNodeContainerForDescriptionElement</p>
227 * @param descriptionElement a {@link eu.etaxonomy.cdm.model.description.DescriptionElementBase} object.
228 * @return a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
230 public FeatureNodeContainer
getFeatureNodeContainerForDescriptionElement (DescriptionElementBase descriptionElement
) {
231 List
<FeatureNodeContainer
> leafs
= getLeafs();
233 for(FeatureNodeContainer container
: leafs
){
234 if(container
.getDescriptionElements().contains(descriptionElement
)){
241 private List
<FeatureNodeContainer
> getLeafs(){
242 List
<FeatureNodeContainer
> leafs
= new ArrayList
<FeatureNodeContainer
>();
247 for(FeatureNodeContainer container
: getChildren()){
248 leafs
.addAll(container
.getLeafs());
255 * Set the description element
257 * @throws java.lang.IllegalStateException when <code>this</code> container contains child container.
258 * @param descriptionElements a {@link java.util.List} object.
260 public void setDescriptionElements(List
<DescriptionElementBase
> descriptionElements
) {
261 if(children
.isEmpty()){
262 this.descriptionElements
= descriptionElements
;
264 throw new IllegalStateException("Container may not contain child container when adding description elements.");
269 * If the container is a leaf, it will hold a description element and no child containers
273 public boolean isLeaf(){
274 return ! descriptionElements
.isEmpty() && children
.isEmpty();
277 private static List
<DescriptionElementBase
> getDescriptionsElementsForFeature(
278 DescriptionBase description
, Feature feature
) {
279 List
<DescriptionElementBase
> featureElements
= new ArrayList
<DescriptionElementBase
>();
281 Set
<DescriptionElementBase
> elements
= description
.getElements();
282 if (elements
!= null) {
283 for (DescriptionElementBase element
: elements
) {
284 Feature elementFeature
= (Feature
) HibernateProxyHelper
.deproxy(element
.getFeature());
286 if (feature
.equals(elementFeature
)) {
287 featureElements
.add(element
);
292 if(featureElements
.size() != 0){
293 Collections
.sort(featureElements
, comparator
);
296 return featureElements
;
300 * <p>Setter for the field <code>featureNode</code>.</p>
302 * @param featureNode a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
304 public void setFeatureNode(FeatureNode featureNode
) {
305 this.featureNode
= featureNode
;
309 * <p>Getter for the field <code>featureNode</code>.</p>
311 * @return a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
313 public FeatureNode
getFeatureNode() {
320 * @return a {@link eu.etaxonomy.cdm.model.description.Feature} object.
322 public Feature
getFeature(){
323 return featureNode
.getFeature();
327 * <p>Getter for the field <code>description</code>.</p>
329 * @return a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
331 public DescriptionBase
getDescription(){
338 ************** NOT USED ****************
341 public User
getUpdatedBy() {return null;}
345 public void setUpdatedBy(User updatedBy
) {}
349 public DateTime
getUpdated() {return null;}
353 public void setUpdated(DateTime updated
) {}
357 public int getId() {return 0;}
361 public void setId(int id
) {}
365 public UUID
getUuid() {return null;}
369 public void setUuid(UUID uuid
) {}
373 public DateTime
getCreated() {return null;}
377 public void setCreated(DateTime created
) {}
381 public User
getCreatedBy() {return null;}
385 public void setCreatedBy(User createdBy
) {}
389 public Set
<Annotation
> getAnnotations() {return null;}
393 public void addAnnotation(Annotation annotation
) {}
397 public void removeAnnotation(Annotation annotation
) {}
401 public Set
<Marker
> getMarkers() { return null; }
405 public void addMarker(Marker marker
) {}
409 public void removeMarker(Marker marker
) {}