001: /*
002: ItsNat Java Web Application Framework
003: Copyright (C) 2007 Innowhere Software Services S.L., Spanish Company
004: Author: Jose Maria Arranz Santamaria
005:
006: This program is free software: you can redistribute it and/or modify
007: it under the terms of the GNU Affero General Public License as published by
008: the Free Software Foundation, either version 3 of the License, or
009: (at your option) any later version. See the GNU Affero General Public
010: License for more details. See the copy of the GNU Affero General Public License
011: included in this program. If not, see <http://www.gnu.org/licenses/>.
012: */
013:
014: package org.itsnat.impl.core.domutil;
015:
016: import org.itsnat.core.ItsNatDOMException;
017: import org.itsnat.core.ItsNatException;
018: import org.itsnat.core.domutil.ListElementInfo;
019: import org.itsnat.core.domutil.ElementList;
020: import org.itsnat.impl.core.ItsNatDocumentImpl;
021: import org.itsnat.core.domutil.ElementListRenderer;
022: import org.itsnat.core.domutil.ElementListStructure;
023: import org.w3c.dom.DocumentFragment;
024: import org.w3c.dom.Element;
025: import org.w3c.dom.Node;
026:
027: /**
028: *
029: * @author jmarranz
030: */
031: public class ElementListImpl extends ElementListBaseImpl implements
032: ElementList {
033: protected ElementListRenderer renderer;
034: protected ElementListStructure structure;
035: protected Element childPatternElement; // Será recordado como patrón aunque sea removido de la lista el original pues es una copia de otro (clone) y será inmune a los cambios del original
036: protected ElementListFreeMasterImpl elementList;
037: protected DocumentFragment childContentPatternFragment; // Será recordado como patrón del contenido
038: protected boolean usePatternMarkupToRender;
039:
040: /**
041: * Creates a new instance of ElementListImpl
042: */
043: public ElementListImpl(ItsNatDocumentImpl itsNatDoc,
044: Element parentElement, Element childPatternElement,
045: boolean clonePattern,
046: DocumentFragment childContentPatternFragment,
047: boolean removePattern, ElementListRenderer renderer,
048: ElementListStructure structure) {
049: super (itsNatDoc);
050:
051: this .renderer = renderer;
052: this .structure = structure;
053: this .usePatternMarkupToRender = itsNatDoc
054: .isUsePatternMarkupToRender();
055:
056: this .elementList = (ElementListFreeMasterImpl) itsNatDoc
057: .createElementListFree(parentElement, true);
058:
059: if (childPatternElement == null) {
060: // Debe existir al menos un elemento, dicho nodo, el primero,
061: // será recordado como patrón aunque sea removido de la lista.
062: childPatternElement = getElementAt(0);
063: if (childPatternElement == null)
064: throw new ItsNatDOMException(
065: "The list must have at least one cell (used as pattern)",
066: elementList.getParentElement());
067: clonePattern = !removePattern; // Si se va a quitar el elemento hijo no hacemos clone pues no va a quedarse en la lista
068: }
069:
070: setChildPatternElement(childPatternElement, clonePattern);
071:
072: this .childContentPatternFragment = childContentPatternFragment;
073:
074: if (removePattern) // Eliminamos el original, queda el clonado memorizado
075: removeAllElements();
076: }
077:
078: public ElementListFreeMasterImpl getInternalElementListFreeMaster() {
079: return elementList;
080: }
081:
082: public ElementListRenderer getElementListRenderer() {
083: return renderer;
084: }
085:
086: public void setElementListRenderer(ElementListRenderer renderer) {
087: this .renderer = renderer;
088: }
089:
090: public ElementListStructure getElementListStructure() {
091: return structure;
092: }
093:
094: public void setElementListStructure(ElementListStructure structure) {
095: this .structure = structure;
096: }
097:
098: public Element getContentElementAt(int index) {
099: Element elem = getElementAt(index);
100: if (elem == null)
101: return null;
102: return getContentElementAt(index, elem);
103: }
104:
105: public Element getContentElementAt(int index, Element elem) {
106: return getElementListStructure().getContentElement(this , index,
107: elem);
108: }
109:
110: public boolean isMaster() {
111: return elementList.isMaster();
112: }
113:
114: public Element getParentElement() {
115: return elementList.getParentElement();
116: }
117:
118: public Element getChildPatternElement() {
119: return childPatternElement;
120: }
121:
122: public void setChildPatternElement(Element childPatternElement,
123: boolean clone) {
124: if (clone)
125: this .childPatternElement = (Element) childPatternElement
126: .cloneNode(true);
127: else
128: this .childPatternElement = childPatternElement;
129:
130: if (this .childPatternElement.getAttribute("id").length() > 0)
131: this .childPatternElement.removeAttribute("id"); // Para evitar duplicidades del id cuando se inserten clones basados en el pattern
132: }
133:
134: public DocumentFragment getChildContentPatternFragment() {
135: if (childContentPatternFragment == null) {
136: // Se crea cuando se necesita, pues puede no usarse nunca
137: ElementListStructure structure = getElementListStructure();
138:
139: if (structure == null)
140: throw new ItsNatException("INTERNAL ERROR");
141:
142: Element itemContentElem = structure.getContentElement(this ,
143: 0, getChildPatternElement());
144: if (itemContentElem != null) // Si no se puede no se puede
145: {
146: Element clonedItemContentElem = (Element) itemContentElem
147: .cloneNode(true); // Necesitamos clonar porque al extraer los nodos hijos se vaciará el contenido
148: this .childContentPatternFragment = ItsNatDOMUtilInternal
149: .extractChildrenToDocFragment(clonedItemContentElem);
150: }
151: }
152:
153: return childContentPatternFragment;
154: }
155:
156: public boolean isEmpty() {
157: return elementList.isEmpty();
158: }
159:
160: public int getLength() {
161: return elementList.getLength();
162: }
163:
164: public void setLength(int len) {
165: if (len < 0)
166: throw new ItsNatException("Length can not be negative:"
167: + len);
168: int currentSize = getLength();
169: int diff = len - currentSize;
170: if (diff > 0)
171: for (int i = 0; i < diff; i++)
172: addElement();
173: else if (diff < 0)
174: for (int i = currentSize - 1; i >= len; i--)
175: removeElementAt(i);
176: }
177:
178: public Element getElementAt(int index) {
179: return elementList.getElementAt(index);
180: }
181:
182: public Element createNewElement() {
183: return (Element) childPatternElement.cloneNode(true);
184: }
185:
186: public Element addElement() {
187: Element newNode = createNewElement();
188: newNode = elementList.addElement2(newNode);
189: return newNode;
190: }
191:
192: public Element addElement(Object value) {
193: Element newNode = addElement();
194: setElementValueAt(getLength() - 1, newNode, value, true);
195: return newNode;
196: }
197:
198: public Element insertElementAt(int index) {
199: Element newNode = createNewElement();
200: newNode = elementList.insertElementAt2(index, newNode);
201: return newNode;
202: }
203:
204: public Element insertElementAt(int index, Object value) {
205: Element newNode = insertElementAt(index);
206: setElementValueAt(index, newNode, value, true);
207: return newNode;
208: }
209:
210: public void unrenderElementAt(int index) {
211: ElementListRenderer renderer = getElementListRenderer();
212: if (renderer == null)
213: return;
214:
215: Element elem = getElementAt(index);
216: if (elem == null)
217: return;
218:
219: Element contentElem = getContentElementAt(index, elem);
220: renderer.unrenderList(this , index, contentElem);
221: }
222:
223: public Element removeElementAt(int index) {
224: unrenderElementAt(index);
225:
226: return elementList.removeElementAt(index);
227: }
228:
229: public void removeElementRange(int fromIndex, int toIndex) {
230: if (getElementListRenderer() != null)
231: for (int i = fromIndex; i <= toIndex; i++)
232: unrenderElementAt(i);
233:
234: elementList.removeElementRange(fromIndex, toIndex);
235: }
236:
237: public void removeAllElements() {
238: if (getElementListRenderer() != null) {
239: int size = getLength();
240: for (int i = 0; i < size; i++)
241: unrenderElementAt(i);
242: }
243:
244: elementList.removeAllElements();
245: }
246:
247: public void removeChildPatternElement() {
248: Node parent = childPatternElement.getParentNode();
249: if (parent != null) // Si es null es que el propio pattern ya fue eliminado del árbol (sigue asociado al documento pero no está en el árbol)
250: parent.removeChild(childPatternElement);
251: }
252:
253: public void setElementValueAt(int index, Object value) {
254: Element elem = getElementAt(index);
255: if (elem == null)
256: throw new ItsNatException("Out of range");
257: setElementValueAt(index, elem, value, false);
258: }
259:
260: public void setElementValueAt(int index, Element elem,
261: Object value, boolean isNew) {
262: Element contentElem = getContentElementAt(index, elem);
263: prepareRendering(contentElem, isNew);
264: ElementListRenderer renderer = getElementListRenderer();
265: if (renderer != null)
266: renderer.renderList(this , index, value, contentElem, isNew);
267: }
268:
269: public void prepareRendering(Element contentElem, boolean isNew) {
270: if (!isNew && isUsePatternMarkupToRender()) // Si es nuevo el markup es ya el del patrón
271: {
272: // Es una actualización en donde tenemos que usar el markup pattern en vez del contenido actual
273: restorePatternMarkupWhenRendering(contentElem,
274: getChildContentPatternFragment());
275: }
276: }
277:
278: public boolean isUsePatternMarkupToRender() {
279: return usePatternMarkupToRender;
280: }
281:
282: public void setUsePatternMarkupToRender(
283: boolean usePatternMarkupToRender) {
284: this .usePatternMarkupToRender = usePatternMarkupToRender;
285: }
286:
287: public Element getElementFromNode(Node node) {
288: return elementList.getElementFromNode(node);
289: }
290:
291: public ListElementInfo getListElementInfoAt(int index) {
292: return elementList.getListElementInfoAt(index);
293: }
294:
295: public ListElementInfo getListElementInfoFromNode(Node node) {
296: return elementList.getListElementInfoFromNode(node);
297: }
298:
299: public ListElementInfoImpl getListElementInfoFromNode(Node node,
300: Element limitElem) {
301: // Uso interno
302: return elementList.getListElementInfoFromNode(node, limitElem);
303: }
304:
305: public Element getFirstElement() {
306: return elementList.getFirstElement();
307: }
308:
309: public Element getLastElement() {
310: return elementList.getLastElement();
311: }
312:
313: public int indexOfElement(Element node) {
314: return elementList.indexOfElement(node);
315: }
316:
317: public int lastIndexOfElement(Element node) {
318: return elementList.lastIndexOfElement(node);
319: }
320:
321: public Element[] getElements() {
322: return elementList.getElements();
323: }
324:
325: public void moveElement(int start, int end, int to) {
326: elementList.moveElement(start, end, to);
327: }
328:
329: }
|