001: /*
002: * This file is part of the WfMOpen project.
003: * Copyright (C) 2001-2005 Danet GmbH (www.danet.de), BU BTS.
004: * All rights reserved.
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * $Id: HtmlExtendedDataTable.java,v 1.8 2007/03/27 21:59:43 mlipp Exp $
021: *
022: * $Log: HtmlExtendedDataTable.java,v $
023: * Revision 1.8 2007/03/27 21:59:43 mlipp
024: * Fixed lots of checkstyle warnings.
025: *
026: * Revision 1.7 2007/02/27 10:56:59 drmlipp
027: * Really fixed problems with decreasing table.
028: *
029: * Revision 1.6 2006/09/29 12:32:09 drmlipp
030: * Consistently using WfMOpen as projct name now.
031: *
032: * Revision 1.5 2006/08/30 21:02:46 mlipp
033: * Updated MyFaces to 1.1.5-SNAPSHOT.
034: *
035: * Revision 1.4 2005/11/02 22:21:42 mlipp
036: * Fixed remaining problems with event processing.
037: *
038: * Revision 1.3 2005/11/01 22:40:57 mlipp
039: * Overriding some more methods.
040: *
041: * Revision 1.2 2005/10/26 21:24:02 mlipp
042: * Type fixes.
043: *
044: * Revision 1.1 2005/10/26 15:31:36 drmlipp
045: * Extended table implementation continued.
046: *
047: */
048: package de.danet.an.util.jsf.taglib;
049:
050: import java.util.HashMap;
051: import java.util.Iterator;
052: import java.util.Map;
053:
054: import javax.faces.component.UIColumn;
055: import javax.faces.component.UIComponent;
056: import javax.faces.context.FacesContext;
057: import javax.faces.el.ValueBinding;
058:
059: import org.apache.myfaces.component.html.ext.HtmlDataTable;
060:
061: /**
062: * An extended table component that supports repetition of rows.
063: * @author lipp
064: */
065: public class HtmlExtendedDataTable extends HtmlDataTable {
066:
067: public static final String COMPONENT_TYPE = "de.danet.bts.HtmlDataTable";
068:
069: private static final int PROCESS_DECODES = 1;
070: private static final int PROCESS_VALIDATORS = 2;
071: private static final int PROCESS_UPDATES = 3;
072:
073: private Long repetitions;
074: private String repetitionCounter;
075:
076: /**
077: * Create a new instance with all attributes initialized to
078: * default values.
079: */
080: public HtmlExtendedDataTable() {
081: super ();
082: }
083:
084: /**
085: * @param localValue
086: * @param valueBindingName
087: * @return
088: */
089: private Object getLocalOrValueBindingValue(Object localValue,
090: String valueBindingName) {
091: if (localValue != null) {
092: return localValue;
093: }
094: ValueBinding vb = getValueBinding(valueBindingName);
095: return vb != null ? vb.getValue(getFacesContext()) : null;
096: }
097:
098: /**
099: * @see javax.faces.component.UIComponentBase#saveState(javax.faces.context.FacesContext)
100: */
101: public Object saveState(FacesContext context) {
102: Object[] values = new Object[3];
103: values[0] = super .saveState(context);
104: values[1] = repetitions;
105: values[2] = repetitionCounter;
106: return values;
107: }
108:
109: /**
110: * @see javax.faces.component.UIComponentBase#restoreState(javax.faces.context.FacesContext, java.lang.Object)
111: */
112: public void restoreState(FacesContext context, Object state) {
113: Object[] values = (Object[]) state;
114: super .restoreState(context, values[0]);
115: repetitions = (Long) values[1];
116: repetitionCounter = (String) values[2];
117: }
118:
119: /* (non-Javadoc)
120: * @see org.apache.myfaces.component.html.ext.HtmlDataTable#getFirst()
121: */
122: public int getFirst() {
123: if (super .getFirst() >= getRowCount()) {
124: setFirst(0);
125: }
126: return super .getFirst();
127: }
128:
129: /**
130: * @return Returns the repetitions.
131: */
132: public Long getRepetitions() {
133: return (Long) getLocalOrValueBindingValue(repetitions,
134: "repetitions");
135: }
136:
137: /**
138: * @param repetitions The repetitions to set.
139: */
140: public void setRepetitions(Long repetitions) {
141: this .repetitions = repetitions;
142: }
143:
144: /**
145: * @return Returns the repetitionCounter.
146: */
147: public String getRepetitionCounter() {
148: return (String) getLocalOrValueBindingValue(repetitionCounter,
149: "repetitionCounter");
150: }
151:
152: /**
153: * @param repetitionCounter The repetitionCounter to set.
154: */
155: public void setRepetitionCounter(String repetitionCounter) {
156: this .repetitionCounter = repetitionCounter;
157: }
158:
159: public void processDecodes(FacesContext context) {
160: super .processDecodes(context);
161: // Do extra (repeated) rows.
162: if (!isRendered()) {
163: return;
164: }
165: setRowIndex(-1);
166: processAdditionalColumnChildren(context, PROCESS_DECODES);
167: setRowIndex(-1);
168: }
169:
170: public void processValidators(FacesContext context) {
171: super .processValidators(context);
172: // Do extra (repeated) rows.
173: if (!isRendered()) {
174: return;
175: }
176: setRowIndex(-1);
177: processAdditionalColumnChildren(context, PROCESS_VALIDATORS);
178: setRowIndex(-1);
179:
180: // check if an validation error forces the render response for our data
181: if (context.getRenderResponse()) {
182: // TODO _isValidChilds = false;
183: }
184: }
185:
186: public void processUpdates(FacesContext context) {
187: super .processUpdates(context);
188: // Do extra (repeated) rows.
189: if (!isRendered()) {
190: return;
191: }
192: setRowIndex(-1);
193: processAdditionalColumnChildren(context, PROCESS_UPDATES);
194: setRowIndex(-1);
195:
196: if (context.getRenderResponse()) {
197: // TODO _isValidChilds = false;
198: }
199: }
200:
201: /**
202: * Process the additional (repeated) rows.
203: * @param context
204: * @param processAction
205: */
206: private void processAdditionalColumnChildren(FacesContext context,
207: int processAction) {
208: int first = getFirst();
209: int rows = getRows();
210: int last;
211: if (rows == 0) {
212: last = getRowCount();
213: } else {
214: last = first + rows;
215: }
216: String repetitionCounterVar = getRepetitionCounter();
217: int repetitionCounter = 0;
218: int repetitions = 0; // force new row
219: Map rowspansCounters = new HashMap();
220: for (int rowIndex = first; last == -1 || rowIndex < last; rowIndex++, repetitionCounter++) {
221: if (repetitionCounter < repetitions) {
222: // repeat row, i.e. undo increment
223: rowIndex -= 1;
224: } else {
225: setRowIndex(rowIndex);
226: //scrolled past the last row
227: if (!isRowAvailable()) {
228: break;
229: }
230: repetitionCounter = 0;
231: Long rv = getRepetitions();
232: repetitions = (rv == null ? 1 : rv.intValue());
233: }
234: if (repetitionCounterVar != null) {
235: context.getExternalContext().getRequestMap().put(
236: repetitionCounterVar,
237: new Integer(repetitionCounter));
238: }
239:
240: long colSkipCounter = 0;
241: for (Iterator it = getChildren().iterator(); it.hasNext();) {
242: UIComponent child = (UIComponent) it.next();
243: if (!(child instanceof UIColumn) || !child.isRendered()) {
244: //Column not UIColumn or not visible
245: continue;
246: }
247: Long rowspanCounter = (Long) rowspansCounters
248: .get(child);
249: long rsc = (rowspanCounter == null ? 0 : rowspanCounter
250: .longValue());
251: boolean doProcess = false;
252: if (rsc > 1) {
253: // skipped due to previous rowspan
254: rowspansCounters.put(child, new Long(rsc - 1));
255: } else {
256: if (rowspanCounter != null) {
257: rowspansCounters.remove(child);
258: }
259: // encode unless skipped due to colspan
260: doProcess = (colSkipCounter == 0);
261: }
262: if (doProcess) {
263: if (repetitionCounter > 0) {
264: for (Iterator columnChildIter = child
265: .getChildren().iterator(); columnChildIter
266: .hasNext();) {
267: UIComponent columnChild = (UIComponent) columnChildIter
268: .next();
269: process(context, columnChild, processAction);
270: }
271: }
272: if (child instanceof HtmlExtendedColumn) {
273: // get new colspan/rowspan values
274: HtmlExtendedColumn xCol = (HtmlExtendedColumn) child;
275: if (xCol.getRowspan() != null
276: && Long.parseLong(xCol.getRowspan()) > 1) {
277: rowspansCounters.put(child, new Long(xCol
278: .getRowspan()));
279: }
280: if (xCol.getColspan() != null
281: && Long.parseLong(xCol.getColspan()) > 1) {
282: colSkipCounter = Long.parseLong(xCol
283: .getColspan());
284: }
285: }
286: }
287: if (colSkipCounter > 0) {
288: colSkipCounter -= 0;
289: }
290: }
291: }
292: }
293:
294: private void process(FacesContext context, UIComponent component,
295: int processAction) {
296: switch (processAction) {
297: case PROCESS_DECODES:
298: component.processDecodes(context);
299: break;
300: case PROCESS_VALIDATORS:
301: component.processValidators(context);
302: break;
303: case PROCESS_UPDATES:
304: component.processUpdates(context);
305: break;
306: }
307: }
308:
309: }
|