/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2008 jOpenDocument, by ILM Informatique. All rights reserved. * * The contents of this file are subject to the terms of the GNU * General Public License Version 3 only ("GPL"). * You may not use this file except in compliance with the License. * You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.html * See the License for the specific language governing permissions and limitations under the License. * * When distributing the software, include this License Header Notice in each file. * */ package org.jopendocument.dom; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ListIterator; import org.jdom.Element; import org.jdom.Namespace; /** * A helper to create children in the schema order. * * @author Sylvain CUAZ */ public class ChildCreator { private final Element content; private final List<Element> elemsOrder; protected ChildCreator(final Element content, final List<Element> children) { if (content == null) throw new NullPointerException("null content"); this.content = content; this.elemsOrder = new ArrayList<Element>(children); } public ChildCreator(Element content, final Element... children) { this(content, Arrays.asList(children)); } public final Element getElement() { return this.content; } public final List<Element> getChildren() { return this.elemsOrder; } // *** children public final Element getChild(Namespace childNS, String childName) { return this.getChild(childNS, childName, false); } private final int indexOf(Namespace childNS, String childName) { for (int i = 0; i < this.elemsOrder.size(); i++) { final Element elem = this.elemsOrder.get(i); if (elem.getNamespace().equals(childNS) && elem.getName().equals(childName)) return i; } return -1; } private final int indexOf(final Element elem) { return this.indexOf(elem.getNamespace(), elem.getName()); } /** * Trouve l'index ou il faut insérer le fils dans ce document. * * @param childName le nom du fils que l'on veut insérer. * @return l'index ou il faut l'insérer (s'il est déjà présent son index actuel +1). * @throws IllegalArgumentException if childName is not in {@link #getChildren()}. */ @SuppressWarnings("unchecked") private final int findInsertIndex(Namespace childNS, String childName) { // eg 6, for "master-styles" final int idealIndex = indexOf(childNS, childName); if (idealIndex == -1) throw new IllegalArgumentException(childName + " is unknown."); final Element existingChild = this.getChild(childNS, childName); if (existingChild != null) return this.getElement().getChildren().indexOf(existingChild) + 1; // eg [scripts, font-decls, styles, font-face-decls, automatic-styles, body] final List<Element> children = this.getElement().getChildren(); final ListIterator<Element> iter = children.listIterator(); while (iter.hasNext()) { final Element elem = iter.next(); if (indexOf(elem) > idealIndex) // eg indexOf("body") == 7 > 6 // eg return 5 return iter.previousIndex(); } return children.size(); } /** * Insère cet élément à la bonne place. The child should not be already present. * * @param child l'élément à insérer, doit être dans TOP_ELEMENTS. */ @SuppressWarnings("unchecked") private final void insertChild(Element child) { // on ajoute au bon endroit this.getElement().getChildren().add(this.findInsertIndex(child.getNamespace(), child.getName()), child); } /** * Return the asked child, optionally creating it. * * @param childNS the namespace of the child. * @param childName the name of the child. * @param create whether it should be created in case it doesn't exist. * @return the asked child or <code>null</code> if it doesn't exist and create is * <code>false</code> */ public final Element getChild(Namespace childNS, String childName, boolean create) { Element child = this.getElement().getChild(childName, childNS); if (create && child == null) { child = new Element(childName, childNS); this.insertChild(child); } return child; } public final Element addChild(Namespace childNS, String childName) { final Element child = new Element(childName, childNS); this.insertChild(child); return child; } public final void setChild(Element elem) { this.getElement().removeChildren(elem.getName(), elem.getNamespace()); this.insertChild(elem); } }