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
.List
;
16 import eu
.etaxonomy
.cdm
.hibernate
.HibernateProxyHelper
;
17 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionBase
;
18 import eu
.etaxonomy
.cdm
.model
.description
.DescriptionElementBase
;
19 import eu
.etaxonomy
.cdm
.model
.description
.Feature
;
20 import eu
.etaxonomy
.cdm
.model
.description
.FeatureNode
;
21 import eu
.etaxonomy
.cdm
.model
.description
.FeatureTree
;
22 import eu
.etaxonomy
.cdm
.model
.description
.TaxonDescription
;
25 * This class is a simple container to allow generation of a datastructure that
26 * describes a feature tree according to a specific description element, i.e a tree
27 * structure that halds only the {@link FeatureNode}s that are relevant for a specific
28 * {@link TaxonDescription} as well as the {@link DescriptionElementBase} at the leaf level.
30 * This kind of datastructure is needed by interface elements such as viewers and greatly simplify
31 * the handling of {@link FeatureTree}s in conjunction with {@link TaxonDescription}s.
34 * @created Sep 20, 2010
37 public class FeatureNodeContainer
{
41 private FeatureNodeContainer parent
;
45 private FeatureNode featureNode
;
46 private List
<FeatureNodeContainer
> children
= new ArrayList
<FeatureNodeContainer
>();
47 private List
<DescriptionElementBase
> descriptionElements
= new ArrayList
<DescriptionElementBase
>();
49 private FeatureNodeContainerTree containerTree
;
55 protected FeatureNodeContainer(FeatureNodeContainerTree containerTree
) {
56 this.containerTree
= containerTree
;
57 this.containerTree
.addContainer(this);
62 * Recursively traverse a branch of a feature tree and check if there are
68 protected void findLeaves(FeatureNode featureNode
) {
69 if(featureNode
.isLeaf()){
70 buildLeaf(featureNode
);
72 for(FeatureNode childNode
: featureNode
.getChildNodes()){
73 findLeaves(childNode
);
84 private void buildLeaf(FeatureNode featureNode
){
85 if(featureNode
.getFeature() == null){
86 throw new IllegalArgumentException("The given feature node does not have a feature.");
89 Feature feature
= (Feature
) HibernateProxyHelper
.deproxy(featureNode
.getFeature());
91 // get feature node container for the given feature
92 FeatureNodeContainer container
= containerTree
.getFeatureNodeContainer(feature
);
94 // get description elements for the given feature
95 List
<DescriptionElementBase
> elements
= containerTree
.getDescriptionsElementsForFeature(feature
);
96 // no description elements, so we should also remove the feature node container
97 if(elements
.isEmpty()){
98 if(container
!= null){
102 // there are description elements
104 if(container
== null){
105 container
= new FeatureNodeContainer(containerTree
);
106 container
.setFeatureNode(featureNode
);
107 // build the branch up to root level
108 container
.buildBranch();
110 // add description elements to the feature node container
111 container
.setDescriptionElements(elements
);
118 private void remove() {
119 if(getParent() != null){
120 if(getParent().getChildren().size() == 1){
121 getParent().remove();
123 getParent().removeChild(this);
129 * @param featureNodeContainer
131 private void removeChild(FeatureNodeContainer featureNodeContainer
) {
132 children
.remove(featureNodeContainer
);
139 * @param featureNodeMap
142 private void buildBranch(){
143 if(getParent() == null){
144 FeatureNode parentFeatureNode
= getFeatureNode().getParent();
146 if(parentFeatureNode
.isRoot()){
147 containerTree
.getRoot().addChild(this);
149 FeatureNodeContainer parentContainer
= containerTree
.getFeatureNodeContainer(parentFeatureNode
);
150 if(parentContainer
== null){
151 parentContainer
= new FeatureNodeContainer(containerTree
);
152 parentContainer
.setFeatureNode(parentFeatureNode
);
155 parentContainer
.addChild(this);
157 parentContainer
.buildBranch();
164 * <p>Getter for the field <code>children</code>.</p>
166 * @return a {@link java.util.List} object.
168 public List
<FeatureNodeContainer
> getChildren() {
173 * Sets the list of children of this containers children
175 * @param children a {@link java.util.List} object.
176 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
178 public void setChildren(List
<FeatureNodeContainer
> children
) {
179 if(descriptionElements
.isEmpty()){
180 this.children
= children
;
182 throw new IllegalStateException("Container may not have a description element set when setting children.");
187 * Adds a child container to the list of this containers children
189 * @param container a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
190 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
192 public void addChild(FeatureNodeContainer container
){
193 if(descriptionElements
.isEmpty()){
194 children
.add(container
);
195 container
.setParent(this);
197 throw new IllegalStateException("Container may not have a description element set when adding children.");
201 public void addDescriptionElement(DescriptionElementBase descriptionElement
){
202 descriptionElements
.add(descriptionElement
);
205 public void removeDescriptionElement(DescriptionElementBase descriptionElement
){
206 descriptionElements
.remove(descriptionElement
);
210 * If {@link #isLeaf()} is true, i.e. this container should have elements, returns the list of description elements.
212 * @return a {@link java.util.List} object.
214 public List
<DescriptionElementBase
> getDescriptionElements() {
215 return descriptionElements
;
219 * Cumulates description elements for <code>this</code> container as well as child feature nodes recursively,
220 * thus returning a list of description elements for the branch of the feature tree starting with <code>this</code>
223 * @return a {@link java.util.List} object.
225 public List
<DescriptionElementBase
> getDescriptionElementsForEntireBranch(){
226 return getDescriptionElementsRecursively(new ArrayList
<DescriptionElementBase
>());
229 private List
<DescriptionElementBase
> getDescriptionElementsRecursively(List
<DescriptionElementBase
> descriptionElements
){
231 descriptionElements
.addAll(getDescriptionElements());
233 for(FeatureNodeContainer container
: getChildren()){
234 container
.getDescriptionElementsRecursively(descriptionElements
);
237 return descriptionElements
;
240 protected List
<FeatureNodeContainer
> getLeafs(){
241 List
<FeatureNodeContainer
> leafs
= new ArrayList
<FeatureNodeContainer
>();
246 for(FeatureNodeContainer container
: getChildren()){
247 leafs
.addAll(container
.getLeafs());
254 * Set the description element
256 * @throws java.lang.IllegalStateException when <code>this</code> container contains child container.
257 * @param descriptionElements a {@link java.util.List} object.
259 public void setDescriptionElements(List
<DescriptionElementBase
> descriptionElements
) {
260 if(children
.isEmpty()){
261 this.descriptionElements
= descriptionElements
;
263 throw new IllegalStateException("Container may not contain child container when adding description elements.");
268 * If the container is a leaf, it will hold a description element and no child containers
272 public boolean isLeaf(){
273 return ! descriptionElements
.isEmpty() && children
.isEmpty();
277 * <p>Setter for the field <code>featureNode</code>.</p>
279 * @param featureNode a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
281 public void setFeatureNode(FeatureNode featureNode
) {
282 this.featureNode
= featureNode
;
286 * <p>Getter for the field <code>featureNode</code>.</p>
288 * @return a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
290 public FeatureNode
getFeatureNode() {
297 * @return a {@link eu.etaxonomy.cdm.model.description.Feature} object.
299 public Feature
getFeature(){
300 if(featureNode
!= null){
301 return featureNode
.getFeature();
307 * <p>Getter for the field <code>description</code>.</p>
309 * @return a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
311 public DescriptionBase
getDescription(){
312 return containerTree
.getDescription();
315 public FeatureNodeContainerTree
getContainerTree(){
316 return containerTree
;
323 public void clear() {
325 descriptionElements
.clear();
332 public boolean isEmpty() {
333 return children
.isEmpty() && descriptionElements
.isEmpty();
339 public FeatureNodeContainer
getParent() {
345 * @param parent the parent to set
347 public void setParent(FeatureNodeContainer parent
) {
348 this.parent
= parent
;