Project

General

Profile

Download (9.28 KB) Statistics
| Branch: | Tag: | Revision:
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
}
(15-15/41)