Project

General

Profile

Download (9.29 KB) Statistics
| Branch: | Tag: | Revision:
1
// $Id$
2
/**
3
* Copyright (C) 2007 EDIT
4
* European Distributed Institute of Taxonomy
5
* http://www.e-taxonomy.eu
6
*
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.
9
*/
10

    
11
package eu.etaxonomy.taxeditor.model;
12

    
13
import java.util.ArrayList;
14
import java.util.List;
15

    
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;
23

    
24
/**
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.
29
 *
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.
32
 *
33
 * @author n.hoffmann
34
 * @created Sep 20, 2010
35
 * @version 1.0
36
 */
37
public class FeatureNodeContainer{
38

    
39

    
40

    
41
	private FeatureNodeContainer parent;
42

    
43

    
44

    
45
	private FeatureNode featureNode;
46
	private List<FeatureNodeContainer> children = new ArrayList<FeatureNodeContainer>();
47
	private List<DescriptionElementBase> descriptionElements = new ArrayList<DescriptionElementBase>();
48

    
49
	private FeatureNodeContainerTree containerTree;
50

    
51

    
52
	/**
53
	 * @param description
54
	 */
55
	protected FeatureNodeContainer(FeatureNodeContainerTree containerTree) {
56
		this.containerTree = containerTree;
57
		this.containerTree.addContainer(this);
58
	}
59

    
60

    
61
	/**
62
	 * Recursively traverse a branch of a feature tree and check if there are
63
	 *
64
	 * @param featureNode
65
	 * @param description
66
	 * @return
67
	 */
68
	protected void findLeaves(FeatureNode featureNode) {
69
		if(featureNode.isLeaf()){
70
			buildLeaf(featureNode);
71
		}else{
72
			for(FeatureNode childNode : featureNode.getChildNodes()){
73
				findLeaves(childNode);
74
			}
75
		}
76
	}
77

    
78
	/**
79
	 *
80
	 * @param featureNode
81
	 * @param description
82
	 * @return
83
	 */
84
	private void buildLeaf(FeatureNode featureNode){
85
		if(featureNode.getFeature() == null){
86
			throw new IllegalArgumentException("The given feature node does not have a feature.");
87
		}
88

    
89
		Feature feature = (Feature) HibernateProxyHelper.deproxy(featureNode.getFeature());
90

    
91
		// get feature node container for the given feature
92
		FeatureNodeContainer container = containerTree.getFeatureNodeContainer(feature);
93

    
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){
99
				container.remove();
100
			}
101
		}
102
		// there are description elements
103
		else{
104
			if(container == null){
105
				container = new FeatureNodeContainer(containerTree);
106
				container.setFeatureNode(featureNode);
107
				// build the branch up to root level
108
				container.buildBranch();
109
			}
110
			// add description elements to the feature node container
111
			container.setDescriptionElements(elements);
112
		}
113
	}
114

    
115
	/**
116
	 *
117
	 */
118
	private void remove() {
119
		if(getParent() != null){
120
			if(getParent().getChildren().size() == 1){
121
				getParent().remove();
122
			}
123
			getParent().removeChild(this);
124
		}
125
	}
126

    
127

    
128
	/**
129
	 * @param featureNodeContainer
130
	 */
131
	private void removeChild(FeatureNodeContainer featureNodeContainer) {
132
		children.remove(featureNodeContainer);
133
	}
134

    
135

    
136
	/**
137
	 * Recursively
138
	 *
139
	 * @param featureNodeMap
140
	 * @return
141
	 */
142
	private void buildBranch(){
143
		if(getParent() == null){
144
			FeatureNode parentFeatureNode = getFeatureNode().getParent();
145

    
146
			if(parentFeatureNode.isRoot()){
147
				containerTree.getRoot().addChild(this);
148
			}else{
149
				FeatureNodeContainer parentContainer = containerTree.getFeatureNodeContainer(parentFeatureNode);
150
				if(parentContainer == null){
151
					parentContainer = new FeatureNodeContainer(containerTree);
152
					parentContainer.setFeatureNode(parentFeatureNode);
153
				}
154

    
155
				parentContainer.addChild(this);
156

    
157
				parentContainer.buildBranch();
158

    
159
			}
160
		}
161
	}
162

    
163
	/**
164
	 * <p>Getter for the field <code>children</code>.</p>
165
	 *
166
	 * @return a {@link java.util.List} object.
167
	 */
168
	public List<FeatureNodeContainer> getChildren() {
169
		return children;
170
	}
171

    
172
	/**
173
	 * Sets the list of children of this containers children
174
	 *
175
	 * @param children a {@link java.util.List} object.
176
	 *  @throws java.lang.IllegalStateException when <code>this</code> container contains a description element.
177
	 */
178
	public void setChildren(List<FeatureNodeContainer> children) {
179
		if(descriptionElements.isEmpty()){
180
			this.children = children;
181
		}else{
182
			throw new IllegalStateException("Container may not have a description element set when setting children.");
183
		}
184
	}
185

    
186
	/**
187
	 * Adds a child container to the list of this containers children
188
	 *
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.
191
	 */
192
	public void addChild(FeatureNodeContainer container){
193
		if(descriptionElements.isEmpty()){
194
			children.add(container);
195
			container.setParent(this);
196
		}else{
197
			throw new IllegalStateException("Container may not have a description element set when adding children.");
198
		}
199
	}
200

    
201
	public void addDescriptionElement(DescriptionElementBase descriptionElement){
202
		descriptionElements.add(descriptionElement);
203
	}
204

    
205
	public void removeDescriptionElement(DescriptionElementBase descriptionElement){
206
		descriptionElements.remove(descriptionElement);
207
	}
208

    
209
	/**
210
	 * If {@link #isLeaf()} is true, i.e. this container should have elements, returns the list of description elements.
211
	 *
212
	 * @return a {@link java.util.List} object.
213
	 */
214
	public List<DescriptionElementBase> getDescriptionElements() {
215
		return descriptionElements;
216
	}
217

    
218
	/**
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>
221
	 * node.
222
	 *
223
	 * @return a {@link java.util.List} object.
224
	 */
225
	public List<DescriptionElementBase> getDescriptionElementsForEntireBranch(){
226
		return getDescriptionElementsRecursively(new ArrayList<DescriptionElementBase>());
227
	}
228

    
229
	private List<DescriptionElementBase> getDescriptionElementsRecursively(List<DescriptionElementBase> descriptionElements){
230
		if(isLeaf()){
231
			descriptionElements.addAll(getDescriptionElements());
232
		}else{
233
			for(FeatureNodeContainer container : getChildren()){
234
				container.getDescriptionElementsRecursively(descriptionElements);
235
			}
236
		}
237
		return descriptionElements;
238
	}
239

    
240
	protected List<FeatureNodeContainer> getLeafs(){
241
		List<FeatureNodeContainer> leafs = new ArrayList<FeatureNodeContainer>();
242

    
243
		if(isLeaf()){
244
			leafs.add(this);
245
		}else{
246
			for(FeatureNodeContainer container : getChildren()){
247
				leafs.addAll(container.getLeafs());
248
			}
249
		}
250
		return leafs;
251
	}
252

    
253
	/**
254
	 * Set the description element
255
	 *
256
	 * @throws java.lang.IllegalStateException when <code>this</code> container contains child container.
257
	 * @param descriptionElements a {@link java.util.List} object.
258
	 */
259
	public void setDescriptionElements(List<DescriptionElementBase> descriptionElements) {
260
		if(children.isEmpty()){
261
			this.descriptionElements = descriptionElements;
262
		}else{
263
			throw new IllegalStateException("Container may not contain child container when adding description elements.");
264
		}
265
	}
266

    
267
	/**
268
	 * If the container is a leaf, it will hold a description element and no child containers
269
	 *
270
	 * @return a boolean.
271
	 */
272
	public boolean isLeaf(){
273
		return ! descriptionElements.isEmpty() && children.isEmpty();
274
	}
275

    
276
	/**
277
	 * <p>Setter for the field <code>featureNode</code>.</p>
278
	 *
279
	 * @param featureNode a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
280
	 */
281
	public void setFeatureNode(FeatureNode featureNode) {
282
		this.featureNode = featureNode;
283
	}
284

    
285
	/**
286
	 * <p>Getter for the field <code>featureNode</code>.</p>
287
	 *
288
	 * @return a {@link eu.etaxonomy.cdm.model.description.FeatureNode} object.
289
	 */
290
	public FeatureNode getFeatureNode() {
291
		return featureNode;
292
	}
293

    
294
	/**
295
	 * <p>getFeature</p>
296
	 *
297
	 * @return a {@link eu.etaxonomy.cdm.model.description.Feature} object.
298
	 */
299
	public Feature getFeature(){
300
		if(featureNode != null){
301
			return featureNode.getFeature();
302
		}
303
		return null;
304
	}
305

    
306
	/**
307
	 * <p>Getter for the field <code>description</code>.</p>
308
	 *
309
	 * @return a {@link eu.etaxonomy.cdm.model.description.DescriptionBase} object.
310
	 */
311
	public DescriptionBase getDescription(){
312
		return containerTree.getDescription();
313
	}
314

    
315
	public FeatureNodeContainerTree getContainerTree(){
316
		return containerTree;
317
	}
318

    
319

    
320
	/**
321
	 *
322
	 */
323
	public void clear() {
324
		children.clear();
325
		descriptionElements.clear();
326
	}
327

    
328

    
329
	/**
330
	 * @return
331
	 */
332
	public boolean isEmpty() {
333
		return children.isEmpty() && descriptionElements.isEmpty();
334
	}
335

    
336
	/**
337
	 * @return the parent
338
	 */
339
	public FeatureNodeContainer getParent() {
340
		return parent;
341
	}
342

    
343

    
344
	/**
345
	 * @param parent the parent to set
346
	 */
347
	public void setParent(FeatureNodeContainer parent) {
348
		this.parent = parent;
349
	}
350
}
(12-12/37)