/** * Insert an empty child. Will shift all children having an index * greater than or equal to the child inserted to the right. * @param nameIndex position where child is inserted */ public void insert(Path.PathElement nameIndex) { // convert 1-based index value to 0-base value int index = getZeroBasedIndex(nameIndex); if (children != null) { ArrayList list = (ArrayList) children.get(nameIndex.getName()); if (list != null && list.size() > index) { for (int i = index; i < list.size(); i++) { Element element = (Element) list.get(i); if (element != null) { element.index = element.getNormalizedIndex() + 1; } } list.add(index, null); } } }
int index = getZeroBasedIndex(nameIndex); if (children == null) { return null; parent.remove(getPathElement(), shift, true);
/** * Sets a new list of children of this element. * * @param children map of children; keys are of type * <code>Path.PathElement</code> and values * are of type <code>Element</code> */ public void setChildren(Map children) { // Remove all children without removing the element itself this.children = null; childrenCount = 0; // Now add back all items Iterator entries = children.entrySet().iterator(); while (entries.hasNext()) { Map.Entry entry = (Map.Entry) entries.next(); Path.PathElement nameIndex = (Path.PathElement) entry.getKey(); Element element = (Element) entry.getValue(); put(nameIndex, element); } // Special case: if map was empty, handle like removeAll() if (childrenCount == 0 && obj == null && parent != null) { parent.remove(getPathElement(), false, true); } }
/** * Link a child of this node. Position is given by <code>nameIndex</code>. * @param nameIndex position where child should be located * @param element element to add */ public void put(Path.PathElement nameIndex, Element element) { // convert 1-based index value to 0-base value int index = getZeroBasedIndex(nameIndex); if (children == null) { children = new HashMap(); } ArrayList list = (ArrayList) children.get(nameIndex.getName()); if (list == null) { list = new ArrayList(); children.put(nameIndex.getName(), list); } while (list.size() < index) { list.add(null); } if (list.size() == index) { list.add(element); } else { list.set(index, element); } element.parent = this; element.name = nameIndex.getName(); element.index = nameIndex.getIndex(); childrenCount++; }
/** * Map a relPath starting at <code>this</code> Element. If * <code>exact</code> is <code>false</code>, returns the last available * item along the relPath that is stored in the map. * * @param relPath relPath to map * @param exact flag indicating whether an exact match is required * @return descendant, maybe <code>null</code> if <code>exact</code> is * <code>true</code> */ public Element getDescendant(Path relPath, boolean exact) { Path.PathElement[] elements = relPath.getElements(); Element current = this; for (int i = 0; i < elements.length; i++) { Element next = current.getChild(elements[i]); if (next == null) { if (exact) { return null; } break; } current = next; } return current; } }
/** * Return an element matching a name and index. * @param nameIndex position where child is located * @return element matching <code>nameIndex</code> or <code>null</code> if * none exists. */ private Element getChild(Path.PathElement nameIndex) { // convert 1-based index value to 0-base value int index = getZeroBasedIndex(nameIndex); Element element = null; if (children != null) { ArrayList list = (ArrayList) children.get(nameIndex.getName()); if (list != null && list.size() > index) { element = (Element) list.get(index); } } return element; }
/** * Put an element given by its path. The path map will create any necessary * intermediate elements. * @param path path to child * @param element element to store at destination */ public void put(Path path, Element element) { Path.PathElement[] elements = path.getElements(); Element current = root; for (int i = 1; i < elements.length - 1; i++) { Element next = current.getChild(elements[i]); if (next == null) { next = current.createChild(elements[i]); } current = next; } current.put(path.getNameElement(), element); }
/** * Internal implementation of {@link #getPath()} that populates entries * in a builder. On exit, <code>builder</code> contains the path * of this element */ private void getPath(Path.PathBuilder builder) { if (parent == null) { builder.addRoot(); return; } parent.getPath(builder); if (index == Path.INDEX_UNDEFINED || index == Path.INDEX_DEFAULT) { builder.addLast(name); } else { builder.addLast(name, index); } }
/** * Checks whether this element has the specified path, given by * path elements. * @param elements path elements to compare to * @param len number of elements to compare to * @return <code>true</code> if this element has the path given; * otherwise <code>false</code> */ private boolean hasPath(Path.PathElement[] elements, int len) { if (getPathElement().equals(elements[len - 1])) { if (parent != null) { return parent.hasPath(elements, len - 1); } return true; } return false; }
/** * Return the path of this element. * @return path * @throws MalformedPathException if building the path fails */ public Path getPath() throws MalformedPathException { if (parent == null) { return Path.ROOT; } Path.PathBuilder builder = new Path.PathBuilder(); getPath(builder); return builder.getPath(); }
/** * Remove this element. Delegates the call to the parent item. * @param shift if index of same name siblings will be shifted. */ public void remove(boolean shift) { if (parent != null) { parent.remove(getPathElement(), shift, true); } else { // Removing the root node is not possible: if it has become // invalid, remove all its children and the associated object children = null; childrenCount = 0; obj = null; } }
/** * Remove this element. Delegates the call to the parent item. * Index of same name siblings will be shifted! */ public void remove() { remove(true); }
/** * Set the object associated with this element * @param obj object associated with this element */ public void set(Object obj) { this.obj = obj; if (obj == null && childrenCount == 0 && parent != null) { parent.remove(getPathElement(), false, true); } }
/** * Remove all children of this element. Removes this element itself * if this element does not contain associated information. */ public void removeAll() { children = null; childrenCount = 0; if (obj == null && parent != null) { parent.remove(getPathElement(), false, true); } }
/** * Remove a child. Will shift all children having an index greater than * the child removed to the left. If there are no more children left in * this element and no object is associated with this element, the * element itself gets removed. * * @param nameIndex child's path element * @return removed child, may be <code>null</code> */ public Element remove(Path.PathElement nameIndex) { return remove(nameIndex, true, true); }
/** * Return the depth of this element. Defined to be <code>0</code> for the * root element and <code>n + 1</code> for some element if the depth of * its parent is <code>n</code>. */ public int getDepth() { if (parent != null) { return parent.getDepth() + 1; } // Root return Path.ROOT_DEPTH; }
/** * Checks whether this element has the specified path. Introduced to * avoid catching a <code>MalformedPathException</code> for simple * path comparisons. * @param path path to compare to * @return <code>true</code> if this child has the path * <code>path</code>, <code>false</code> otherwise */ public boolean hasPath(Path path) { return hasPath(path.getElements(), path.getLength()); }