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.ItsNatException;
017: import org.itsnat.core.domutil.ElementTable;
018: import org.itsnat.impl.core.ItsNatDocumentImpl;
019: import java.util.ArrayList;
020: import java.util.Iterator;
021: import java.util.List;
022: import org.itsnat.core.domutil.ElementTableRenderer;
023: import org.itsnat.core.domutil.ElementTableStructure;
024: import org.itsnat.core.domutil.ListElementInfo;
025: import org.w3c.dom.DocumentFragment;
026: import org.w3c.dom.Element;
027: import org.w3c.dom.Node;
028:
029: /**
030: *
031: * @author jmarranz
032: */
033: public class ElementTableImpl extends ElementTableBaseImpl implements
034: ElementTable {
035: protected ElementTableRenderer renderer;
036: protected ElementTableStructure structure;
037: protected ElementListImpl columnListPattern;
038: protected DocumentFragment cellContentPatternFragment; // Será recordado como patrón del contenido
039: protected boolean usePatternMarkupToRender;
040:
041: /**
042: * Creates a new instance of ElementTableImpl
043: */
044: public ElementTableImpl(ItsNatDocumentImpl itsNatDoc,
045: Element parentElement, boolean removePattern,
046: ElementTableStructure structure,
047: ElementTableRenderer renderer) {
048: super (itsNatDoc, parentElement);
049:
050: this .structure = structure;
051: this .renderer = renderer;
052: this .usePatternMarkupToRender = itsNatDoc
053: .isUsePatternMarkupToRender();
054:
055: this .columnListOfRow = new ArrayList(); // Siempre es modo master
056:
057: this .rows = (ElementListImpl) itsNatDoc
058: .createElementListNoRenderInternal(parentElement, null,
059: !removePattern, false);
060:
061: Element rowContentParentPattern = structure
062: .getRowContentElement(this , 0, getRowPatternElement());
063: this .columnListPattern = itsNatDoc
064: .createElementListNoRenderInternal(
065: rowContentParentPattern, null, !removePattern,
066: false);
067:
068: if (removePattern)
069: rows.removeAllElements(); // Quita la primera fila (pattern)
070: else
071: createAndSyncColumnArrayList(); // Está el pattern (no eliminado)
072: }
073:
074: public boolean isUsePatternMarkupToRender() {
075: return usePatternMarkupToRender;
076: }
077:
078: public void setUsePatternMarkupToRender(
079: boolean usePatternMarkupToRender) {
080: this .usePatternMarkupToRender = usePatternMarkupToRender;
081: }
082:
083: public ElementListFreeImpl getRowsAsElementListFree() {
084: return getRowElementList().getInternalElementListFreeMaster();
085: }
086:
087: public ElementListImpl getRowElementList() {
088: return (ElementListImpl) rows;
089: }
090:
091: public ElementTableRenderer getElementTableRenderer() {
092: return renderer;
093: }
094:
095: public void setElementTableRenderer(ElementTableRenderer renderer) {
096: this .renderer = renderer;
097: }
098:
099: public ElementTableStructure getElementTableStructure() {
100: return structure;
101: }
102:
103: public void setElementTableStructure(ElementTableStructure structure) {
104: this .structure = structure;
105: }
106:
107: public Element getRowPatternElement() {
108: return getRowElementList().getChildPatternElement();
109: }
110:
111: public Element getCellPatternElement() {
112: return columnListPattern.getChildPatternElement();
113: }
114:
115: public DocumentFragment getCellContentPatternFragment() {
116: if (cellContentPatternFragment == null) {
117: // El cellContentPatternFragment necesario para el renderTable con usePatternMarkupToRender = true
118: Element cellPatternContentElem = structure
119: .getCellContentElement(this , 0, 0,
120: getCellPatternElement());
121: if (cellPatternContentElem != null) // Si no se puede no se puede
122: {
123: Element clonedItemContentElem = (Element) cellPatternContentElem
124: .cloneNode(true); // Necesitamos clonar porque al extraer los nodos hijos se vaciará el contenido
125: this .cellContentPatternFragment = ItsNatDOMUtilInternal
126: .extractChildrenToDocFragment(clonedItemContentElem);
127: }
128: }
129:
130: return cellContentPatternFragment;
131: }
132:
133: protected void setRowContent(int row, Element rowElem,
134: Object[] rowData, boolean isNew) {
135: if ((rowData != null) && (rowData.length > 0)) {
136: ElementListImpl columns = (ElementListImpl) getColumnsOfRowElementList(
137: row, rowElem);
138: // Si la longitud de rowData es menor que el número de columnas dará error
139: int col = 0;
140: for (Iterator it = columns
141: .getInternalElementListFreeMaster().iterator(); it
142: .hasNext();) {
143: Element columElem = (Element) it.next();
144: Object value = rowData[col];
145: setCellValueAt(row, col, value, columElem, isNew);
146:
147: col++;
148: }
149: }
150: }
151:
152: public Element addRow() {
153: return addRow((Object[]) null);
154: }
155:
156: public Element addRow(List rowData) {
157: return addRow(toObjectArray(rowData));
158: }
159:
160: public Element addRow(Object[] rowData) {
161: int row = rows.getLength();
162: Element rowElem = getRowElementList().addElement();
163:
164: insertColumnListOfRow(row, rowElem);
165:
166: setRowContent(row, rowElem, rowData, true);
167: return rowElem;
168: }
169:
170: public Element insertRowAt(int row) {
171: return insertRowAt(row, (Object[]) null);
172: }
173:
174: public Element insertRowAt(int row, List rowData) {
175: return insertRowAt(row, toObjectArray(rowData));
176: }
177:
178: public Element insertRowAt(int row, Object[] rowData) {
179: Element rowElem = getRowElementList().insertElementAt(row);
180: if (rowElem == null)
181: return null; // Fuera de rango
182:
183: insertColumnListOfRow(row, rowElem);
184:
185: setRowContent(row, rowElem, rowData, true);
186: return rowElem;
187: }
188:
189: public void setRowValuesAt(int row, List rowData) {
190: setRowValuesAt(row, toObjectArray(rowData));
191: }
192:
193: public void setRowValuesAt(int row, Object[] rowData) {
194: Element rowElem = getRowElementAt(row);
195: setRowContent(row, rowElem, rowData, false);
196: }
197:
198: public ElementListBaseImpl getColumnsOfRowElementList(int row,
199: Element rowElem) {
200: return (ElementListImpl) columnListOfRow.get(row);
201: }
202:
203: public ElementListBaseImpl newColumnsOfRowElementList(int row,
204: Element rowElem) {
205: Element rowContentElem = getRowContentElementAt(row, rowElem);
206: Element cellPattern = getCellPatternElement();
207: DocumentFragment cellContentPattern = getCellContentPatternFragment();
208: return (ElementListImpl) itsNatDoc.createElementListInternal(
209: rowContentElem, cellPattern, false, cellContentPattern,
210: false, null, null); // No clonamos pues el mismo elemento patrón celda ya fue clonado y es utilizado para crear todas las columnas
211: }
212:
213: public Element[] addOrInsertColumn(int column, Object[] columnData,
214: boolean add) {
215: if (add)
216: columnListPattern.addElement(); // Añadimos también al patrón para que al añadir una nueva fila tenga el nuevo número de columnas
217: else
218: columnListPattern.insertElementAt(column); // Añadimos también al patrón para que al añadir una nueva fila tenga el nuevo número de columnas
219:
220: ElementListFreeImpl rows = getRowsAsElementListFree();
221: if (rows.isEmpty())
222: return new Element[0]; // Nada más que hacer
223:
224: Element[] newCells = new Element[rows.getLength()];
225:
226: // Si la longitud de columnData es menor que el número de columnas dará error
227: int row = 0;
228: for (Iterator it = rows.iterator(); it.hasNext();) {
229: Element rowElem = (Element) it.next();
230:
231: ElementListImpl columns = (ElementListImpl) getColumnsOfRowElementList(
232: row, rowElem);
233: Element columnElem = null;
234: if (add)
235: columnElem = columns.addElement();
236: else
237: columnElem = columns.insertElementAt(column);
238:
239: newCells[row] = columnElem;
240: if (columnData != null)
241: setCellValueAt(row, column, columnData[row],
242: columnElem, true);
243:
244: row++;
245: }
246:
247: return newCells;
248: }
249:
250: public Element[] addColumn() {
251: return addColumn((Object[]) null);
252: }
253:
254: public Element[] addColumn(List columnData) {
255: return addColumn(toObjectArray(columnData));
256: }
257:
258: public Element[] addColumn(Object[] columnData) {
259: int column = getColumnCount();
260: return addOrInsertColumn(column, columnData, true);
261: }
262:
263: public Element[] insertColumnAt(int column) {
264: return insertColumnAt(column, (Object[]) null);
265: }
266:
267: public Element[] insertColumnAt(int column, List columnData) {
268: return insertColumnAt(column, toObjectArray(columnData));
269: }
270:
271: public Element[] insertColumnAt(int column, Object[] columnData) {
272: return addOrInsertColumn(column, columnData, false);
273: }
274:
275: public void setColumnValuesAt(int column, List columnData) {
276: setColumnValuesAt(column, toObjectArray(columnData));
277: }
278:
279: public void setColumnValuesAt(int column, Object[] columnData) {
280: // Nada que hacer al pattern
281:
282: ElementListFreeImpl rows = getRowsAsElementListFree();
283: if (rows.isEmpty())
284: return; // Nada que hacer
285:
286: // Si la longitud de columnData es menor que el número de columnas dará error
287: int row = 0;
288: for (Iterator it = rows.iterator(); it.hasNext();) {
289: Element rowElem = (Element) it.next();
290:
291: ElementListImpl columns = (ElementListImpl) getColumnsOfRowElementList(
292: row, rowElem);
293: Element columnElem = columns.getElementAt(column);
294: setCellValueAt(row, column, columnData[row], columnElem,
295: false);
296:
297: row++;
298: }
299: }
300:
301: public void removeColumnAt(int column) {
302: ElementTableRenderer renderer = getElementTableRenderer();
303: if (renderer != null) {
304: int rowCount = getRowCount();
305: for (int row = 0; row < rowCount; row++)
306: unrenderCell(row, column);
307: }
308:
309: columnListPattern.removeElementAt(column); // Quitamos también al patrón para que al añadir una nueva fila tenga el nuevo número de columnas
310:
311: super .removeColumnAt(column);
312: }
313:
314: public void removeAllColumns() {
315: unrenderAllCells();
316:
317: columnListPattern.removeAllElements(); // Quitamos también al patrón para que al añadir una nueva fila tenga el nuevo número de columnas
318:
319: super .removeAllColumns();
320: }
321:
322: public int getColumnCount() {
323: return columnListPattern.getLength();
324: }
325:
326: public Element getCellContentElementAt(int row, int column) {
327: Element cellElem = getCellElementAt(row, column);
328: if (cellElem == null)
329: return null;
330: return getCellContentElementAt(row, column, cellElem);
331: }
332:
333: public Element getCellContentElementAt(int row, int column,
334: Element cellElem) {
335: return getElementTableStructure().getCellContentElement(this ,
336: row, column, cellElem);
337: }
338:
339: public Element getRowContentElementAt(int row) {
340: Element rowElem = getRowElementAt(row);
341: if (rowElem == null)
342: return null;
343: return getRowContentElementAt(row, rowElem);
344: }
345:
346: public Element getRowContentElementAt(int row, Element rowElem) {
347: return getElementTableStructure().getRowContentElement(this ,
348: row, rowElem);
349: }
350:
351: public void setCellValueAt(int row, int column, Object value) {
352: Element cellElem = getCellElementAt(row, column);
353: if (cellElem == null)
354: throw new ItsNatException("Out of range");
355:
356: setCellValueAt(row, column, value, cellElem, false);
357: }
358:
359: public void setCellValueAt(int row, int column, Object value,
360: Element cellElem, boolean isNew) {
361: Element cellContentElem = getCellContentElementAt(row, column,
362: cellElem);
363: prepareRendering(cellContentElem, isNew);
364: ElementTableRenderer renderer = getElementTableRenderer();
365: if (renderer != null)
366: renderer.renderTable(this , row, column, value,
367: cellContentElem, isNew);
368: }
369:
370: public void prepareRendering(Element cellContentElem, boolean isNew) {
371: if (!isNew && isUsePatternMarkupToRender()) // Si es nuevo el markup es ya el del patrón
372: {
373: // Es una actualización en donde tenemos que usar el markup pattern en vez del contenido actual
374: restorePatternMarkupWhenRendering(cellContentElem,
375: getCellContentPatternFragment());
376: }
377: }
378:
379: public Element removeRowAt(int row) {
380: ElementTableRenderer renderer = getElementTableRenderer();
381: if (renderer != null) {
382: int columnCount = getColumnCount();
383: for (int col = 0; col < columnCount; col++)
384: unrenderCell(row, col);
385: }
386:
387: return super .removeRowAt(row);
388: }
389:
390: public void removeRowRange(int fromIndex, int toIndex) {
391: ElementTableRenderer renderer = getElementTableRenderer();
392: if (renderer != null) {
393: int columnCount = getColumnCount();
394: for (int row = fromIndex; row <= toIndex; row++)
395: for (int col = 0; col < columnCount; col++)
396: unrenderCell(row, col);
397: }
398:
399: super .removeRowRange(fromIndex, toIndex);
400: }
401:
402: public void removeAllRows() {
403: unrenderAllCells();
404:
405: super .removeAllRows();
406: }
407:
408: public void unrenderCell(int row, int column) {
409: ElementTableRenderer renderer = getElementTableRenderer();
410: if (renderer == null)
411: return;
412:
413: Element cellElem = getCellElementAt(row, column);
414: if (cellElem == null)
415: return;
416:
417: Element cellContentElem = getCellContentElementAt(row, column,
418: cellElem);
419: renderer.unrenderTable(this , row, column, cellContentElem);
420: }
421:
422: public void unrenderAllCells() {
423: ElementTableRenderer renderer = getElementTableRenderer();
424: if (renderer == null)
425: return;
426:
427: int rowCount = getRowCount();
428: int columnCount = getColumnCount();
429: for (int row = 0; row < rowCount; row++)
430: for (int col = 0; col < columnCount; col++)
431: unrenderCell(row, col);
432: }
433:
434: public void setRowCount(int rowCount) {
435: if (rowCount < 0)
436: throw new ItsNatException("Negative row count: " + rowCount);
437: int currentRowCount = getRowCount();
438: int diff = rowCount - currentRowCount;
439: if (diff > 0)
440: for (int i = 0; i < diff; i++)
441: addRow();
442: else if (diff < 0)
443: for (int i = currentRowCount - 1; i >= rowCount; i--)
444: removeRowAt(i);
445: }
446:
447: public void setColumnCount(int columnCount) {
448: if (columnCount < 0)
449: throw new ItsNatException("Negative column count: "
450: + columnCount);
451: int currentColumnCount = getColumnCount();
452: int diff = columnCount - currentColumnCount;
453: if (diff > 0)
454: for (int i = 0; i < diff; i++)
455: addColumn();
456: else if (diff < 0)
457: for (int i = currentColumnCount - 1; i >= columnCount; i--)
458: removeColumnAt(i);
459: }
460:
461: public void setTableValues(List values) {
462: for (int i = 0; i < values.size(); i++) {
463: List rowValues = (List) values.get(i);
464: for (int j = 0; j < rowValues.size(); i++) {
465: Object cellValue = rowValues.get(i);
466: setCellValueAt(i, j, cellValue);
467: }
468: }
469: }
470:
471: public void setTableValues(Object[][] values) {
472: for (int i = 0; i < values.length; i++) {
473: Object[] rowValues = values[i];
474: for (int j = 0; j < rowValues.length; j++) {
475: Object cellValue = rowValues[i];
476: setCellValueAt(i, j, cellValue);
477: }
478: }
479: }
480:
481: public void moveColumn(int columnIndex, int newIndex) {
482: if (columnIndex == newIndex)
483: return;
484:
485: columnListPattern.moveElement(columnIndex, columnIndex,
486: newIndex);
487:
488: ElementListFreeImpl rows = getRowsAsElementListFree();
489: if (rows.isEmpty())
490: return; // Nada que hacer
491:
492: int row = 0;
493: for (Iterator it = rows.iterator(); it.hasNext();) {
494: Element rowElem = (Element) it.next();
495:
496: ElementListImpl columns = (ElementListImpl) getColumnsOfRowElementList(
497: row, rowElem);
498: columns.moveElement(columnIndex, columnIndex, newIndex);
499:
500: row++;
501: }
502: }
503:
504: public TableCellElementInfoImpl getTableCellElementInfo(
505: ListElementInfo rowInfo, ListElementInfo cellInfo) {
506: return TableCellElementInfoMasterImpl
507: .getTableCellElementInfoMaster(
508: (ListElementInfoMasterImpl) rowInfo,
509: (ListElementInfoMasterImpl) cellInfo, this );
510: }
511:
512: public static Object[] toObjectArray(List data) {
513: if (data == null)
514: return null;
515:
516: Object[] dataArray = new Object[data.size()];
517: dataArray = data.toArray(dataArray);
518: return dataArray;
519: }
520: }
|