ref #6190 removing svn property place holder in first line of code - java files
[taxeditor.git] / eu.etaxonomy.taxeditor.store / src / main / java / eu / etaxonomy / taxeditor / model / FeatureNodeContainer.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.List;
14
15 import eu.etaxonomy.cdm.hibernate.HibernateProxyHelper;
16 import eu.etaxonomy.cdm.model.description.DescriptionBase;
17 import eu.etaxonomy.cdm.model.description.DescriptionElementBase;
18 import eu.etaxonomy.cdm.model.description.Feature;
19 import eu.etaxonomy.cdm.model.description.FeatureNode;
20 import eu.etaxonomy.cdm.model.description.FeatureTree;
21 import eu.etaxonomy.cdm.model.description.TaxonDescription;
22
23 /**
24 * This class is a simple container to allow generation of a datastructure that
25 * describes a feature tree according to a specific description element, i.e a tree
26 * structure that halds only the {@link FeatureNode}s that are relevant for a specific
27 * {@link TaxonDescription} as well as the {@link DescriptionElementBase} at the leaf level.
28 *
29 * This kind of datastructure is needed by interface elements such as viewers and greatly simplify
30 * the handling of {@link FeatureTree}s in conjunction with {@link TaxonDescription}s.
31 *
32 * @author n.hoffmann
33 * @created Sep 20, 2010
34 * @version 1.0
35 */
36 public class FeatureNodeContainer{
37
38
39
40 private FeatureNodeContainer parent;
41
42
43
44 private FeatureNode featureNode;
45 private List<FeatureNodeContainer> children = new ArrayList<FeatureNodeContainer>();
46 private List<DescriptionElementBase> descriptionElements = new ArrayList<DescriptionElementBase>();
47
48 private FeatureNodeContainerTree containerTree;
49
50
51 /**
52 * @param description
53 */
54 protected FeatureNodeContainer(FeatureNodeContainerTree containerTree) {
55 this.containerTree = containerTree;
56 this.containerTree.addContainer(this);
57 }
58
59
60 /**
61 * Recursively traverse a branch of a feature tree and check if there are
62 *
63 * @param featureNode
64 * @param description
65 * @return
66 */
67 protected void findLeaves(FeatureNode featureNode) {
68 if(featureNode.isLeaf()){
69 buildLeaf(featureNode);
70 }else{
71 for(FeatureNode childNode : featureNode.getChildNodes()){
72 findLeaves(childNode);
73 }
74 }
75 }
76
77 /**
78 *
79 * @param featureNode
80 * @param description
81 * @return
82 */
83 private void buildLeaf(FeatureNode featureNode){
84 if(featureNode.getFeature() == null){
85 throw new IllegalArgumentException("The given feature node does not have a feature.");
86 }
87
88 Feature feature = (Feature) HibernateProxyHelper.deproxy(featureNode.getFeature());
89
90 // get feature node container for the given feature
91 FeatureNodeContainer container = containerTree.getFeatureNodeContainer(feature);
92
93 // get description elements for the given feature
94 List<DescriptionElementBase> elements = containerTree.getDescriptionsElementsForFeature(feature);
95 // no description elements, so we should also remove the feature node container
96 if(elements.isEmpty()){
97 if(container != null){
98 container.remove();
99 }
100 }
101 // there are description elements
102 else{
103 if(container == null){
104 container = new FeatureNodeContainer(containerTree);
105 container.setFeatureNode(featureNode);
106 // build the branch up to root level
107 container.buildBranch();
108 }
109 // add description elements to the feature node container
110 container.setDescriptionElements(elements);
111 }
112 }
113
114 /**
115 *
116 */
117 private void remove() {
118 if(getParent() != null){
119 if(getParent().getChildren().size() == 1){
120 getParent().remove();
121 }
122 getParent().removeChild(this);
123 }
124 }
125
126
127 /**
128 * @param featureNodeContainer
129 */
130 private void removeChild(FeatureNodeContainer featureNodeContainer) {
131 children.remove(featureNodeContainer);
132 }
133
134
135 /**
136 * Recursively
137 *
138 * @param featureNodeMap
139 * @return
140 */
141 private void buildBranch(){
142 if(getParent() == null){
143 FeatureNode parentFeatureNode = getFeatureNode().getParent();
144
145 if(parentFeatureNode.isRoot()){
146 containerTree.getRoot().addChild(this);
147 }else{
148 FeatureNodeContainer parentContainer = containerTree.getFeatureNodeContainer(parentFeatureNode);
149 if(parentContainer == null){
150 parentContainer = new FeatureNodeContainer(containerTree);
151 parentContainer.setFeatureNode(parentFeatureNode);
152 }
153
154 parentContainer.addChild(this);
155
156 parentContainer.buildBranch();
157
158 }
159 }
160 }
161
162 /**
163 * <p>Getter for the field <code>children</code>.</p>
164 *
165 * @return a {@link java.util.List} object.
166 */
167 public List<FeatureNodeContainer> getChildren() {
168 return children;
169 }
170
171 /**
172 * Sets the list of children of this containers children
173 *
174 * @param children a {@link java.util.List} object.
175 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
176 */
177 public void setChildren(List<FeatureNodeContainer> children) {
178 if(descriptionElements.isEmpty()){
179 this.children = children;
180 }else{
181 throw new IllegalStateException("Container may not have a description element set when setting children.");
182 }
183 }
184
185 /**
186 * Adds a child container to the list of this containers children
187 *
188 * @param container a {@link eu.etaxonomy.taxeditor.model.FeatureNodeContainer} object.
189 * @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
190 */
191 public void addChild(FeatureNodeContainer container){
192 if(descriptionElements.isEmpty()){
193 children.add(container);
194 container.setParent(this);
195 }else{
196 throw new IllegalStateException("Container may not have a description element set when adding children.");
197 }
198 }
199
200 public void addDescriptionElement(DescriptionElementBase descriptionElement){
201 descriptionElements.add(descriptionElement);
202 }
203
204 public void removeDescriptionElement(DescriptionElementBase descriptionElement){
205 descriptionElements.remove(descriptionElement);
206 }
207
208 /**
209 * If {@link #isLeaf()} is true, i.e. this container should have elements, returns the list of description elements.
210 *
211 * @return a {@link java.util.List} object.
212 */
213 public List<DescriptionElementBase> getDescriptionElements() {
214 return descriptionElements;
215 }
216
217 /**
218 * Cumulates description elements for <code>this</code> container as well as child feature nodes recursively,
219 * thus returning a list of description elements for the branch of the feature tree starting with <code>this</code>
220 * node.
221 *
222 * @return a {@link java.util.List} object.
223 */
224 public List<DescriptionElementBase> getDescriptionElementsForEntireBranch(){
225 return getDescriptionElementsRecursively(new ArrayList<DescriptionElementBase>());
226 }
227
228 private List<DescriptionElementBase> getDescriptionElementsRecursively(List<DescriptionElementBase> descriptionElements){
229 if(isLeaf()){
230 descriptionElements.addAll(getDescriptionElements());
231 }else{
232 for(FeatureNodeContainer container : getChildren()){
233 container.getDescriptionElementsRecursively(descriptionElements);
234 }
235 }
236 return descriptionElements;
237 }
238
239 protected List<FeatureNodeContainer> getLeafs(){
240 List<FeatureNodeContainer> leafs = new ArrayList<FeatureNodeContainer>();
241
242 if(isLeaf()){
243 leafs.add(this);
244 }else{
245 for(FeatureNodeContainer container : getChildren()){
246 leafs.addAll(container.getLeafs());
247 }
248 }
249 return leafs;
250 }
251
252 /**
253 * Set the description element
254 *
255 * @throws java.lang.IllegalStateException when <code>this</code> container contains child container.
256 * @param descriptionElements a {@link java.util.List} object.
257 */
258 public void setDescriptionElements(List<DescriptionElementBase> descriptionElements) {
259 if(children.isEmpty()){
260 this.descriptionElements = descriptionElements;
261 }else{
262 throw new IllegalStateException("Container may not contain child container when adding description elements.");
263 }
264 }
265
266 /**
267 * If the container is a leaf, it will hold a description element and no child containers
268 *
269 * @return a boolean.
270 */
271 public boolean isLeaf(){
272 return ! descriptionElements.isEmpty() && children.isEmpty();
273 }
274
275 /**
276 * <p>Setter for the field <code>featureNode</code>.</p>
277 *
278 * @param featureNode a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
279 */
280 public void setFeatureNode(FeatureNode featureNode) {
281 this.featureNode = featureNode;
282 }
283
284 /**
285 * <p>Getter for the field <code>featureNode</code>.</p>
286 *
287 * @return a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
288 */
289 public FeatureNode getFeatureNode() {
290 return featureNode;
291 }
292
293 /**
294 * <p>getFeature</p>
295 *
296 * @return a {@link eu.etaxonomy.cdm.model.description.Feature} object.
297 */
298 public Feature getFeature(){
299 if(featureNode != null){
300 return featureNode.getFeature();
301 }
302 return null;
303 }
304
305 /**
306 * <p>Getter for the field <code>description</code>.</p>
307 *
308 * @return a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
309 */
310 public DescriptionBase getDescription(){
311 return containerTree.getDescription();
312 }
313
314 public FeatureNodeContainerTree getContainerTree(){
315 return containerTree;
316 }
317
318
319 /**
320 *
321 */
322 public void clear() {
323 children.clear();
324 descriptionElements.clear();
325 }
326
327
328 /**
329 * @return
330 */
331 public boolean isEmpty() {
332 return children.isEmpty() && descriptionElements.isEmpty();
333 }
334
335 /**
336 * @return the parent
337 */
338 public FeatureNodeContainer getParent() {
339 return parent;
340 }
341
342
343 /**
344 * @param parent the parent to set
345 */
346 public void setParent(FeatureNodeContainer parent) {
347 this.parent = parent;
348 }
349 }