Project

General

Profile

Download (20.7 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.cdm.model.description;
11

    
12
import java.util.ArrayList;
13
import java.util.HashSet;
14
import java.util.List;
15
import java.util.Set;
16

    
17
import javax.persistence.Column;
18
import javax.persistence.Entity;
19
import javax.persistence.FetchType;
20
import javax.persistence.Index;
21
import javax.persistence.JoinColumn;
22
import javax.persistence.JoinTable;
23
import javax.persistence.ManyToMany;
24
import javax.persistence.ManyToOne;
25
import javax.persistence.OneToMany;
26
import javax.persistence.OrderBy;
27
import javax.persistence.OrderColumn;
28
import javax.persistence.Table;
29
import javax.persistence.Transient;
30
import javax.validation.constraints.NotNull;
31
import javax.xml.bind.annotation.XmlAccessType;
32
import javax.xml.bind.annotation.XmlAccessorType;
33
import javax.xml.bind.annotation.XmlAttribute;
34
import javax.xml.bind.annotation.XmlElement;
35
import javax.xml.bind.annotation.XmlElementWrapper;
36
import javax.xml.bind.annotation.XmlIDREF;
37
import javax.xml.bind.annotation.XmlRootElement;
38
import javax.xml.bind.annotation.XmlSchemaType;
39
import javax.xml.bind.annotation.XmlType;
40

    
41
import org.apache.log4j.Logger;
42
import org.hibernate.annotations.Cascade;
43
import org.hibernate.annotations.CascadeType;
44
import org.hibernate.annotations.Type;
45
import org.hibernate.envers.Audited;
46

    
47
import eu.etaxonomy.cdm.hibernate.HHH_9751_Util;
48
import eu.etaxonomy.cdm.model.common.CdmBase;
49
import eu.etaxonomy.cdm.model.common.ITreeNode;
50
import eu.etaxonomy.cdm.model.common.VersionableEntity;
51
import eu.etaxonomy.cdm.model.term.DefinedTermBase;
52
import eu.etaxonomy.cdm.model.term.IHasTermType;
53
import eu.etaxonomy.cdm.model.term.TermType;
54

    
55
/**
56
 * The class for tree nodes within a {@link FeatureTree feature tree} structure.
57
 * Feature nodes are the elementary components of such a tree since they might
58
 * be related to other nodes as a parent or as a child. A feature node belongs
59
 * at most to one feature tree. It cannot have more than one parent node but
60
 * may have several child nodes. Parent/child relations are bidirectional:
61
 * a node N1 is the parent of a node N2 if and only if the node N2 is a child of
62
 * the node N1.
63
 *
64
 * @author  m.doering
65
 * @since 08-Nov-2007 13:06:16
66
 */
67
@SuppressWarnings("serial")
68
@XmlAccessorType(XmlAccessType.FIELD)
69
@XmlType(name = "FeatureNode", propOrder = {
70
		"featureTree",
71
		"termType",
72
		"feature",
73
		"parent",
74
		"treeIndex",
75
		"sortIndex",
76
		"children",
77
		"onlyApplicableIf",
78
		"inapplicableIf"
79
})
80
@XmlRootElement(name = "FeatureNode")
81
@Entity
82
@Audited
83
@Table(name="FeatureNode", indexes = { @Index(name = "featureNodeTreeIndex", columnList = "treeIndex") })
84
public class FeatureNode <T extends DefinedTermBase> extends VersionableEntity
85
            implements ITreeNode<FeatureNode<T>>, IHasTermType, Cloneable {
86
	private static final Logger logger = Logger.getLogger(FeatureNode.class);
87

    
88
    //This is the main key a node belongs to. Although other keys may also reference
89
	//<code>this</code> node, a node usually belongs to a given key.
90
	@XmlElement(name = "FeatureTree")
91
    @XmlIDREF
92
    @XmlSchemaType(name = "IDREF")
93
    @ManyToOne(fetch = FetchType.LAZY, targetEntity=FeatureTree.class)
94
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE}) //TODO this usage is incorrect, needed only for OneToMany, check why it is here, can it be removed??
95
	 //TODO Val #3379
96
//    @NotNull
97
	private FeatureTree<T> featureTree;
98

    
99
    /**
100
     * The {@link TermType type} of this term node.
101
     * Must be the same type as for the {@link FeatureTree term collection}
102
     * this node belongs to and as the term type of the term this node links to.
103
     */
104
    @XmlAttribute(name ="TermType")
105
    @Column(name="termType")
106
    @NotNull
107
    @Type(type = "eu.etaxonomy.cdm.hibernate.EnumUserType",
108
        parameters = {@org.hibernate.annotations.Parameter(name  = "enumClass", value = "eu.etaxonomy.cdm.model.common.TermType")}
109
    )
110
    @Audited
111
    private TermType termType;
112

    
113
    @XmlElement(name = "Feature")
114
    @XmlIDREF
115
    @XmlSchemaType(name = "IDREF")
116
    @ManyToOne(fetch = FetchType.LAZY, targetEntity=DefinedTermBase.class)
117
	private T feature;
118

    
119
    @XmlElement(name = "Parent")
120
    @XmlIDREF
121
    @XmlSchemaType(name = "IDREF")
122
    @ManyToOne(fetch = FetchType.LAZY, targetEntity=FeatureNode.class)
123
    @Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})
124
	@JoinColumn(name="parent_id")
125
	private FeatureNode<T> parent;
126

    
127

    
128
    @XmlElement(name = "treeIndex")
129
    @Column(length=255)
130
    private String treeIndex;
131

    
132
    @XmlElementWrapper(name = "Children")
133
    @XmlElement(name = "Child")
134
    //see https://dev.e-taxonomy.eu/trac/ticket/3722
135
    @OrderColumn(name="sortIndex")
136
    @OrderBy("sortIndex")
137
	@OneToMany(fetch = FetchType.LAZY, mappedBy="parent", targetEntity=FeatureNode.class)
138
	@Cascade({CascadeType.SAVE_UPDATE, CascadeType.MERGE})
139
	private List<FeatureNode<T>> children = new ArrayList<>();
140

    
141
    //see https://dev.e-taxonomy.eu/trac/ticket/3722
142
    private Integer sortIndex;
143

    
144
	@XmlElementWrapper(name = "OnlyApplicableIf")
145
	@XmlElement(name = "OnlyApplicableIf")
146
	@XmlIDREF
147
	@XmlSchemaType(name="IDREF")
148
	@ManyToMany(fetch = FetchType.LAZY)
149
//	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})  remove cascade #5755
150
	@JoinTable(name="FeatureNode_DefinedTermBase_OnlyApplicable")
151
	private final Set<State> onlyApplicableIf = new HashSet<>();
152

    
153
	@XmlElementWrapper(name = "InapplicableIf")
154
	@XmlElement(name = "InapplicableIf")
155
	@XmlIDREF
156
	@XmlSchemaType(name="IDREF")
157
	@ManyToMany(fetch = FetchType.LAZY)
158
//	@Cascade({CascadeType.SAVE_UPDATE,CascadeType.MERGE})  remove cascade #5755
159
	@JoinTable(name="FeatureNode_DefinedTermBase_InapplicableIf")
160
	private final Set<State> inapplicableIf = new HashSet<>();
161

    
162
// ***************************** FACTORY *********************************/
163

    
164
	/**
165
     * Creates a new empty term node instance.
166
     *
167
     * @see #NewInstance(Feature)
168
     */
169
    public static <T extends DefinedTermBase<T>> FeatureNode<T> NewInstance(TermType termType){
170
        return new FeatureNode<>(termType);
171
    }
172

    
173
	/**
174
	 * Creates a new empty feature node instance.
175
	 *
176
	 * @see #NewInstance(Feature)
177
	 */
178
	public static FeatureNode<Feature> NewInstance(){
179
		return new FeatureNode<>(TermType.Feature);
180
	}
181

    
182
	/**
183
	 * Creates a new feature node instance only with the given {@link DefinedTermBase term}
184
	 * (without parent and children). The termType of the feature node is the termType of
185
	 * the given term
186
	 *
187
	 * @param	term	the term assigned to the new feature node
188
	 * @see 			#NewInstance()
189
	 */
190
	public static <T extends DefinedTermBase<T>> FeatureNode<T> NewInstance(T term){
191
	    FeatureNode<T> result = new FeatureNode<>(term.getTermType());
192
	    result.setTerm(term);
193
	    return result;
194
	}
195

    
196
// ******************** CONSTRUCTOR ***************************************/
197

    
198
	//TODO needed?
199
    @Deprecated
200
    protected FeatureNode(){}
201

    
202
	/**
203
	 * Class constructor: creates a new empty feature node instance.
204
	 */
205
	protected FeatureNode(TermType termType) {
206
	    this.termType = termType;
207
	    IHasTermType.checkTermTypeNull(this);
208
	}
209

    
210
    @Override
211
    public TermType getTermType() {
212
        return termType;
213
    }
214

    
215
//*************************** TREE ************************************/
216

    
217
	public FeatureTree<T> getFeatureTree() {
218
		return featureTree;
219
	}
220

    
221
	protected void setFeatureTree(FeatureTree<T> featureTree) {
222
		checkTermType(featureTree);
223
	    this.featureTree = featureTree;
224
	}
225

    
226
//** ********************** FEATURE ******************************/
227

    
228
	/**
229
     * Returns the {@link Feature feature} <i>this</i> feature node is based on.
230
     */
231
    public T getTerm() {
232
        return CdmBase.deproxy(feature);
233
    }
234
    /**
235
     * @see #getFeature()
236
     */
237
    public void setTerm(T term) {
238
        checkTermType(term);
239
        this.feature = term;
240
    }
241

    
242
//** ********************** PARENT ******************************/
243

    
244
	/**
245
	 * Returns the feature node <i>this</i> feature node is a child of.
246
	 *
247
	 * @see	#getChildNodes()
248
	 */
249
	@Override
250
    public FeatureNode<T> getParent() {
251
		return parent;
252
	}
253
	/**
254
	 * Assigns the given feature node as the parent of <i>this</i> feature node.
255
	 * Due to bidirectionality this method must also add <i>this</i> feature node
256
	 * to the list of children of the given parent.
257
	 *
258
	 * @param	parent	the feature node to be set as parent
259
	 * @see				#getParent()
260
	 */
261
	protected void setParent(FeatureNode<T> parent) {
262
		checkTermType(parent);
263
	    this.parent = parent;
264
	}
265

    
266
//** ********************** CHILDREN ******************************/
267

    
268

    
269
	/**
270
	 * @deprecated for internal use only.
271
	 */
272
	//see #4278 , #4200
273
	@Deprecated
274
    protected void setSortIndex(Integer sortIndex) {
275
		this.sortIndex = sortIndex;
276
	}
277

    
278
	/**
279
	 * Returns the (ordered) list of feature nodes which are children nodes of
280
	 * <i>this</i> feature node.
281
	 */
282
	@Override
283
    public List<FeatureNode<T>> getChildNodes() {
284
	    return children;
285
	}
286

    
287
	/**
288
	 * Adds the given feature node at the end of the list of children of
289
	 * <i>this</i> feature node. Due to bidirectionality this method must also
290
	 * assign <i>this</i> feature node as the parent of the given child.
291
	 *
292
	 * @param	child	the feature node to be added
293
	 * @see				#getChildNodes()
294
	 * @see				#setChildren(List)
295
	 * @see				#addChild(FeatureNode, int)
296
	 * @see				#removeChild(FeatureNode)
297
	 * @see				#removeChild(int)
298
	 */
299
	public void addChild(FeatureNode<T> child){
300
		addChild(child, children.size());
301
	}
302
	/**
303
	 * Inserts the given feature node in the list of children of <i>this</i> feature node
304
	 * at the given (index + 1) position. If the given index is out of bounds
305
	 * an exception will arise.<BR>
306
	 * Due to bidirectionality this method must also assign <i>this</i> feature node
307
	 * as the parent of the given child.
308
	 *
309
	 * @param	child	the feature node to be added
310
	 * @param	index	the integer indicating the position at which the child
311
	 * 					should be added
312
	 * @see				#getChildNodes()
313
	 * @see				#setChildren(List)
314
	 * @see				#addChild(FeatureNode)
315
	 * @see				#removeChild(FeatureNode)
316
	 * @see				#removeChild(int)
317
	 */
318
	public void addChild(FeatureNode<T> child, int index){
319
	    checkTermType(child);
320
	    List<FeatureNode<T>> children = this.getChildNodes();
321
		if (index < 0 || index > children.size() + 1){
322
			throw new IndexOutOfBoundsException("Wrong index: " + index);
323
		}
324
		if (child.getParent() != null){
325
			child.getParent().removeChild(child);
326
		}
327
		child.setParent(this);
328
		child.setFeatureTree(this.getFeatureTree());
329
		children.add(index, child);
330
		//TODO workaround (see sortIndex doc)
331
		for(int i = 0; i < children.size(); i++){
332
			children.get(i).setSortIndex(i);
333
		}
334
		child.setSortIndex(index);
335
	}
336

    
337

    
338
    /**
339
	 * Removes the given feature node from the list of {@link #getChildNodes() children}
340
	 * of <i>this</i> feature node.
341
	 *
342
	 * @param  child	the feature node which should be removed
343
	 * @see     		#getChildNodes()
344
	 * @see				#addChild(FeatureNode, int)
345
	 * @see				#addChild(FeatureNode)
346
	 * @see				#removeChild(int)
347
	 */
348
	public void removeChild(FeatureNode<T> child){
349

    
350
	    int index = children.indexOf(child);
351
		if (index >= 0){
352
			removeChild(index);
353
		}
354
	}
355
	/**
356
	 * Removes the feature node placed at the given (index + 1) position from
357
	 * the list of {@link #getChildNodes() children} of <i>this</i> feature node.
358
	 * If the given index is out of bounds no child will be removed.
359
	 *
360
	 * @param  index	the integer indicating the position of the feature node to
361
	 * 					be removed
362
	 * @see     		#getChildNodes()
363
	 * @see				#addChild(FeatureNode, int)
364
	 * @see				#addChild(FeatureNode)
365
	 * @see				#removeChild(FeatureNode)
366
	 */
367
	public void removeChild(int index){
368
	   FeatureNode<T> child = children.get(index);
369
	   if (child != null){
370
			children.remove(index);
371
			child.setParent(null);
372
			child.setFeatureTree(null);
373
			//TODO workaround (see sortIndex doc)
374
			for(int i = 0; i < children.size(); i++){
375
				FeatureNode<T> childAt = children.get(i);
376
				childAt.setSortIndex(i);
377
			}
378
			child.setSortIndex(null);
379
		}
380
	}
381

    
382
	/**
383
	 * Returns the feature node placed at the given (childIndex + 1) position
384
	 * within the list of {@link #getChildNodes() children} of <i>this</i> feature node.
385
	 * If the given index is out of bounds no child will be returned.
386
	 *
387
	 * @param  childIndex	the integer indicating the position of the feature node
388
	 * @see     			#getChildNodes()
389
	 * @see					#addChild(FeatureNode, int)
390
	 * @see					#removeChild(int)
391
	 */
392
	public FeatureNode<T> getChildAt(int childIndex) {
393
	    return children.get(childIndex);
394
	}
395

    
396
	/**
397
	 * Returns the number of children nodes of <i>this</i> feature node.
398
	 *
399
	 * @see	#getChildNodes()
400
	 */
401
	@Transient
402
	public int getChildCount() {
403
		return children.size();
404
	}
405

    
406
	/**
407
	 * Returns the integer indicating the position of the given feature node
408
	 * within the list of {@link #getChildNodes() children} of <i>this</i> feature node.
409
	 * If the list does not contain this node then -1 will be returned.
410
	 *
411
	 * @param  node	the feature node the position of which is being searched
412
	 * @see			#addChild(FeatureNode, int)
413
	 * @see			#removeChild(int)
414
	 */
415
	public int getIndex(FeatureNode<T> node) {
416
	    if (! children.contains(node)){
417
			return -1;
418
		}else{
419
			return children.indexOf(node);
420
		}
421
	}
422

    
423
	/**
424
	 * Returns the boolean value indicating if <i>this</i> feature node has
425
	 * children (false) or not (true). A node without children is at the
426
	 * bottommost level of a tree and is called a leaf.
427
	 *
428
	 * @see	#getChildNodes()
429
	 * @see	#getChildCount()
430
	 */
431
	@Transient
432
	public boolean isLeaf() {
433
		return children.size() < 1;
434
	}
435

    
436
	/**
437
	 * Whether <code>this</code> node is the root node of the associated {@link FeatureTree feature tree}.
438
	 *
439
	 * @return <code>true</code> if <code>this</code> is the feature trees root node, <code>false</code> if not
440
	 */
441
	@Transient
442
	public boolean isRoot(){
443
		if(getFeatureTree() != null){
444
			return this.equals(getFeatureTree().getRoot());
445
		}
446
		return false;
447
	}
448

    
449
	/**
450
	 * Returns the set of {@link State states} implying rendering the
451
	 * concerned {@link Feature feature} applicable.
452
	 * If at least one state is present in this set, in a given description
453
	 * the {@link Feature feature} in <i>this</i> feature node is inapplicable
454
	 * unless any of the listed controlling states is present in the parent
455
	 * {@link Feature feature} description element {@link CategoricalData
456
	 * categoricalData}.
457
	 * This attribute is not equivalent to onlyApplicableIf in SDD as it is
458
	 * attached directly to the child feature rather than the parent, which
459
	 * allow having different applicable states for each child feature.
460
	 *
461
	 * @see    #addApplicableState(State)
462
	 * @see    #removeApplicableState(State)
463
	 */
464
	public Set<State> getOnlyApplicableIf() {
465
		return onlyApplicableIf;
466
	}
467

    
468
	/**
469
	 * Adds an existing {@link State applicable state} to the set of
470
	 * {@link #getOnlyApplicableIf() applicable states} described in
471
	 * <i>this</i> feature node.<BR>
472
	 *
473
	 * @param applicableState	the applicable state to be added to <i>this</i> feature node
474
	 * @see    	   								#getApplicableState()
475
	 */
476
	public void addApplicableState(State applicableState) {
477
		this.onlyApplicableIf.add(applicableState);
478
	}
479

    
480
	/**
481
	 * Removes one element from the set of
482
	 * {@link #getOnlyApplicableIf() applicable states} described in
483
	 * <i>this</i> feature node.<BR>
484
	 *
485
	 * @param  applicableState   the applicable state which should be removed
486
	 * @see    	   								#getApplicableState()
487
	 * @see     		  						#addApplicableState(State)
488
	 */
489
	public void removeApplicableState(State applicableState) {
490
		this.onlyApplicableIf.remove(applicableState);
491
	}
492

    
493
	/**
494
	 * Returns the set of {@link State states} implying rendering the
495
	 * concerned {@link Feature feature} inapplicable.
496
	 * If at least one {@link State inapplicable state} is defined in the set,
497
	 * in a given description the {@link Feature feature} attribute of
498
	 * <i>this</i> feature node is inapplicable when any of the listed
499
	 * controlling states is present.
500
	 * This attribute is not equivalent to inapplicableIf in SDD as it is
501
	 * attached directly to the child feature rather than the parent, which
502
	 * allow having different inapplicability rules for each child feature.
503
	 *
504
	 * @see    #addInapplicableState(State)
505
	 * @see    #removeInapplicableState(State)
506
	 */
507
	public Set<State> getInapplicableIf() {
508
		return inapplicableIf;
509
	}
510

    
511
	/**
512
	 * Adds an existing {@link State inapplicable state} to the set of
513
	 * {@link #getInapplicableIf() inapplicable states} described in
514
	 * <i>this</i> feature node.<BR>
515
	 *
516
	 * @param inapplicableState	the inapplicable state to be added to <i>this</i> feature node
517
	 * @see    	   								#getInapplicableState()
518
	 */
519
	public void addInapplicableState(State inapplicableState) {
520
		this.inapplicableIf.add(inapplicableState);
521
	}
522

    
523
	/**
524
	 * Removes one element from the set of
525
	 * {@link #getInapplicableIf() inapplicable states} described in
526
	 * <i>this</i> feature node.<BR>
527
	 *
528
	 * @param  inapplicableState   the inapplicable state which should be removed
529
	 * @see    	   								#getInapplicableState()
530
	 * @see     		  						#addInapplicableState(State)
531
	 */
532
	public void removeInapplicableState(State inapplicableState) {
533
		this.inapplicableIf.remove(inapplicableState);
534
	}
535

    
536
//	//** ********************** QUESTIONS ******************************/
537
//
538
//	/**
539
//	 * Returns the {@link Representation question} formulation that
540
//	 * corresponds to <i>this</i> feature node and the corresponding
541
//	 * {@link Feature feature} in case it is part of a
542
//	 * {@link PolytomousKey polytomous key}.
543
//	 */
544
//	public Set<Representation> getQuestions() {
545
//		return this.questions;
546
//	}
547
//
548
//	public void addQuestion(Representation question) {
549
//		this.questions.add(question);
550
//	}
551
//
552
//	public void removeQuestion(Representation question) {
553
//		this.questions.remove(question);
554
//	}
555
//
556
//	@Transient
557
//	public Representation getQuestion(Language lang) {
558
//		for (Representation question : questions){
559
//			Language reprLanguage = question.getLanguage();
560
//			if (reprLanguage != null && reprLanguage.equals(lang)){
561
//				return question;
562
//			}
563
//		}
564
//		return null;
565
//	}
566

    
567
	/**
568
     * Throws {@link IllegalArgumentException} if the given
569
     * term has not the same term type as this term or if term type is null.
570
     * @param term
571
     */
572
    private void checkTermType(IHasTermType term) {
573
        IHasTermType.checkTermTypes(term, this);
574
    }
575

    
576
	/**
577
	 * Returns all terms that are contained in this node or a child node
578
	 *
579
	 * @param featureNode
580
	 * @param features
581
	 * @return
582
	 */
583
	@Transient
584
	public Set<T> getDistinctFeaturesRecursive(Set<T> features){
585
		T term = this.getTerm();
586

    
587
		if(term!=null){
588
		    features.add(term);
589
		}
590

    
591
		for(FeatureNode<T> childNode : this.getChildNodes()){
592
			features.addAll(childNode.getDistinctFeaturesRecursive(features));
593
		}
594

    
595
		return features;
596
	}
597

    
598
	public FeatureNode<T> cloneDescendants(){
599
		FeatureNode<T> clone = (FeatureNode<T>)this.clone();
600
		FeatureNode<T> childClone;
601

    
602
		for(FeatureNode<T> childNode : this.getChildNodes()){
603
			childClone = (FeatureNode<T>) childNode.clone();
604
			for (FeatureNode<T> childChild:childNode.getChildNodes()){
605
				childClone.addChild(childChild.cloneDescendants());
606
			}
607
			clone.addChild(childClone);
608

    
609
		}
610
		return clone;
611
	}
612

    
613
//*********************** CLONE ********************************************************/
614

    
615
	/**
616
	 * Clones <i>this</i> FeatureNode. This is a shortcut that enables to create
617
	 * a new instance that differs only slightly from <i>this</i> FeatureNode by
618
	 * modifying only some of the attributes.
619
	 * The parent, the feature and the featureTree are the are the same as for the original feature node
620
	 * the children are removed
621
	 *
622
	 * @see eu.etaxonomy.cdm.model.common.VersionableEntity#clone()
623
	 * @see java.lang.Object#clone()
624
	 */
625
	@Override
626
	public Object clone() {
627
		FeatureNode<T> result;
628
		try {
629
			result = (FeatureNode<T>)super.clone();
630
			result.children = new ArrayList<>();
631
			return result;
632
		}catch (CloneNotSupportedException e) {
633
			logger.warn("Object does not implement cloneable");
634
			e.printStackTrace();
635
			return null;
636
		}
637

    
638

    
639

    
640
	}
641

    
642
// ********************** TREE NODE METHODS ******************************/
643

    
644
	@Override
645
	public String treeIndex() {
646
		return this.treeIndex;
647
	}    @Override
648
    public String treeIndexLike() {
649
        return treeIndex + "%";
650
    }
651
    @Override
652
    public String treeIndexWc() {
653
        return treeIndex + "*";
654
    }
655

    
656
	@Override
657
	@Deprecated
658
	public void setTreeIndex(String newTreeIndex) {
659
		this.treeIndex = newTreeIndex;
660
	}
661

    
662

    
663
	@Override
664
	@Deprecated
665
	public int treeId() {
666
		if (this.featureTree == null){
667
			return -1;
668
		}else{
669
			return this.featureTree.getId();
670
		}
671
	}
672

    
673
	private void updateSortIndex(){
674
	 // TODO workaround (see sortIndex doc)
675
        for (int i = 0; i < children.size(); i++) {
676
            children.get(i).setSortIndex(i);
677
        }
678
	}
679

    
680
	public void removeNullValueFromChildren(){
681
	    HHH_9751_Util.removeAllNull(children);
682
	    updateSortIndex();
683
	}
684

    
685

    
686
}
(11-11/37)