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
.List
;
19 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
20 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
21 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
22 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
23 import eu
.etaxonomy
.cdm
.model
.description
.FeatureNode
;
24 import eu
.etaxonomy
.cdm
.model
.description
.FeatureTree
;
25 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
28 * This class is a simple container to allow generation of a datastructure that
29 * describes a feature tree according to a specific description element, i.e a tree
30 * structure that halds only the {@link FeatureNode}s that are relevant for a specific
31 * {@link TaxonDescription} as well as the {@link DescriptionElementBase} at the leaf level.
33 * This kind of datastructure is needed by interface elements such as viewers and greatly simplify
34 * the handling of {@link FeatureTree}s in conjunction with {@link TaxonDescription}s.
37 * @created Sep 20, 2010
40 public class FeatureNodeContainer
{
44 private FeatureNodeContainer parent
;
48 private FeatureNode featureNode
;
49 private List
<FeatureNodeContainer
> children
= new ArrayList
<FeatureNodeContainer
>();
50 private List
<DescriptionElementBase
> descriptionElements
= new ArrayList
<DescriptionElementBase
>();
52 private FeatureNodeContainerTree containerTree
;
58 protected FeatureNodeContainer(FeatureNodeContainerTree containerTree
) {
59 this.containerTree
= containerTree
;
60 this.containerTree
.addContainer(this);
65 * Recursively traverse a branch of a feature tree and check if there are
71 protected void findLeaves(FeatureNode featureNode
) {
72 if(featureNode
.isLeaf()){
73 buildLeaf(featureNode
);
75 for(FeatureNode childNode
: featureNode
.getChildren()){
76 findLeaves(childNode
);
87 private void buildLeaf(FeatureNode featureNode
){
88 // get feature node container for the given feature
89 FeatureNodeContainer container
= containerTree
.getFeatureNodeContainerByFeature(featureNode
.getFeature());
91 // get description elements for the given feature
92 List
<DescriptionElementBase
> elements
= containerTree
.getDescriptionsElementsForFeature(featureNode
.getFeature());
93 // no description elements, so we should also remove the feature node container
94 if(elements
.isEmpty()){
95 if(container
!= null){
99 // there are description elements
101 if(container
== null){
102 container
= new FeatureNodeContainer(containerTree
);
103 container
.setFeatureNode(featureNode
);
104 // build the branch up to root level
105 container
.buildBranch();
107 // add description elements to the feature node container
108 container
.setDescriptionElements(elements
);
115 private void remove() {
116 if(getParent() != null){
117 if(getParent().getChildren().size() == 1){
118 getParent().remove();
120 getParent().removeChild(this);
126 * @param featureNodeContainer
128 private void removeChild(FeatureNodeContainer featureNodeContainer
) {
129 children
.remove(featureNodeContainer
);
136 * @param featureNodeMap
139 private void buildBranch(){
140 if(getParent() == null){
141 FeatureNode parentFeatureNode
= getFeatureNode().getParent();
143 if(parentFeatureNode
.isRoot()){
144 containerTree
.getRoot().addChild(this);
146 FeatureNodeContainer parentContainer
= new FeatureNodeContainer(containerTree
);
147 parentContainer
.setFeatureNode(parentFeatureNode
);
149 parentContainer
.addChild(this);
151 parentContainer
.buildBranch();
158 * <p>Getter for the field <code>children</code>.</p>
160 * @return a {@link java.util.List} object.
162 public List
<FeatureNodeContainer
> getChildren() {
167 * Sets the list of children of this containers children
169 * @param children a {@link java.util.List} object.
170 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
172 public void setChildren(List
<FeatureNodeContainer
> children
) {
173 if(descriptionElements
.isEmpty()){
174 this.children
= children
;
176 throw new IllegalStateException("Container may not have a description element set when setting children.");
181 * Adds a child container to the list of this containers children
183 * @param container a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
184 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
186 public void addChild(FeatureNodeContainer container
){
187 if(descriptionElements
.isEmpty()){
188 children
.add(container
);
189 container
.setParent(this);
191 throw new IllegalStateException("Container may not have a description element set when adding children.");
195 public void addDescriptionElement(DescriptionElementBase descriptionElement
){
196 descriptionElements
.add(descriptionElement
);
199 public void removeDescriptionElement(DescriptionElementBase descriptionElement
){
200 descriptionElements
.remove(descriptionElement
);
204 * If {@link #isLeaf()} is true, i.e. this container should have elements, returns the list of description elements.
206 * @return a {@link java.util.List} object.
208 public List
<DescriptionElementBase
> getDescriptionElements() {
209 return descriptionElements
;
213 * Cumulates description elements for <code>this</code> container as well as child feature nodes recursively,
214 * thus returning a list of description elements for the branch of the feature tree starting with <code>this</code>
217 * @return a {@link java.util.List} object.
219 public List
<DescriptionElementBase
> getDescriptionElementsForEntireBranch(){
220 return getDescriptionElementsRecursively(new ArrayList
<DescriptionElementBase
>());
223 private List
<DescriptionElementBase
> getDescriptionElementsRecursively(List
<DescriptionElementBase
> descriptionElements
){
225 descriptionElements
.addAll(getDescriptionElements());
227 for(FeatureNodeContainer container
: getChildren()){
228 container
.getDescriptionElementsRecursively(descriptionElements
);
231 return descriptionElements
;
234 protected List
<FeatureNodeContainer
> getLeafs(){
235 List
<FeatureNodeContainer
> leafs
= new ArrayList
<FeatureNodeContainer
>();
240 for(FeatureNodeContainer container
: getChildren()){
241 leafs
.addAll(container
.getLeafs());
248 * Set the description element
250 * @throws java.lang.IllegalStateException when <code>this</code> container contains child container.
251 * @param descriptionElements a {@link java.util.List} object.
253 public void setDescriptionElements(List
<DescriptionElementBase
> descriptionElements
) {
254 if(children
.isEmpty()){
255 this.descriptionElements
= descriptionElements
;
257 throw new IllegalStateException("Container may not contain child container when adding description elements.");
262 * If the container is a leaf, it will hold a description element and no child containers
266 public boolean isLeaf(){
267 return ! descriptionElements
.isEmpty() && children
.isEmpty();
271 * <p>Setter for the field <code>featureNode</code>.</p>
273 * @param featureNode a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
275 public void setFeatureNode(FeatureNode featureNode
) {
276 this.featureNode
= featureNode
;
280 * <p>Getter for the field <code>featureNode</code>.</p>
282 * @return a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
284 public FeatureNode
getFeatureNode() {
291 * @return a {@link eu.etaxonomy.cdm.model.description.Feature} object.
293 public Feature
getFeature(){
294 if(featureNode
!= null){
295 return featureNode
.getFeature();
301 * <p>Getter for the field <code>description</code>.</p>
303 * @return a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
305 public DescriptionBase
getDescription(){
306 return containerTree
.getDescription();
309 public FeatureNodeContainerTree
getContainerTree(){
310 return containerTree
;
317 public void clear() {
319 descriptionElements
.clear();
326 public boolean isEmpty() {
327 return children
.isEmpty() && descriptionElements
.isEmpty();
333 public FeatureNodeContainer
getParent() {
339 * @param parent the parent to set
341 public void setParent(FeatureNodeContainer parent
) {
342 this.parent
= parent
;