001 /**
002 * ========================================
003 * JFreeReport : a free Java report library
004 * ========================================
005 *
006 * Project Info: http://reporting.pentaho.org/
007 *
008 * (C) Copyright 2000-2007, by Object Refinery Limited, Pentaho Corporation and Contributors.
009 *
010 * This library is free software; you can redistribute it and/or modify it under the terms
011 * of the GNU Lesser General Public License as published by the Free Software Foundation;
012 * either version 2.1 of the License, or (at your option) any later version.
013 *
014 * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
015 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
016 * See the GNU Lesser General Public License for more details.
017 *
018 * You should have received a copy of the GNU Lesser General Public License along with this
019 * library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
020 * Boston, MA 02111-1307, USA.
021 *
022 * [Java is a trademark or registered trademark of Sun Microsystems, Inc.
023 * in the United States and other countries.]
024 *
025 * ------------
026 * $Id: AutoTableLayoutController.java,v 1.5 2007/06/10 15:54:22 taqua Exp $
027 * ------------
028 * (C) Copyright 2000-2005, by Object Refinery Limited.
029 * (C) Copyright 2005-2007, by Pentaho Corporation.
030 */
031
032 package org.jfree.report.modules.misc.autotable.flow;
033
034 import org.jfree.layouting.util.AttributeMap;
035 import org.jfree.report.DataSourceException;
036 import org.jfree.report.ReportDataFactoryException;
037 import org.jfree.report.ReportProcessingException;
038 import org.jfree.report.data.ReportDataRow;
039 import org.jfree.report.flow.FlowControlOperation;
040 import org.jfree.report.flow.FlowController;
041 import org.jfree.report.flow.ReportContext;
042 import org.jfree.report.flow.ReportTarget;
043 import org.jfree.report.flow.layoutprocessor.ElementLayoutController;
044 import org.jfree.report.flow.layoutprocessor.LayoutController;
045 import org.jfree.report.flow.layoutprocessor.LayoutControllerFactory;
046 import org.jfree.report.flow.layoutprocessor.LayoutControllerUtil;
047 import org.jfree.report.modules.misc.autotable.AutoTableElement;
048 import org.jfree.report.modules.misc.autotable.AutoTableModule;
049
050 /**
051 * Creation-Date: Dec 9, 2006, 6:05:58 PM
052 *
053 * @author Thomas Morgner
054 */
055 public class AutoTableLayoutController extends ElementLayoutController
056 {
057 public static final int HANDLING_HEADER = 0;
058 public static final int HANDLING_DATA = 1;
059 public static final int HANDLING_FOOTER = 2;
060
061 private int currentColumn;
062 private int processingState;
063 private int columnCount;
064
065 public AutoTableLayoutController()
066 {
067 }
068
069 public void initialize(final Object node, final FlowController flowController, final LayoutController parent)
070 throws DataSourceException, ReportDataFactoryException, ReportProcessingException
071 {
072 super.initialize(node, flowController, parent);
073 final ReportDataRow reportDataRow =
074 flowController.getMasterRow().getReportDataRow();
075 this.columnCount = reportDataRow.getColumnCount();
076 }
077
078 protected LayoutController processContent(final ReportTarget target)
079 throws DataSourceException, ReportProcessingException, ReportDataFactoryException
080 {
081 switch (processingState)
082 {
083 case AutoTableLayoutController.HANDLING_HEADER:
084 return processHeader(target);
085 case AutoTableLayoutController.HANDLING_FOOTER:
086 return processFooter(target);
087 case AutoTableLayoutController.HANDLING_DATA:
088 return processData(target);
089 default:
090 throw new ReportProcessingException("No such state.");
091 }
092
093 }
094
095 private LayoutController processData(final ReportTarget target)
096 throws ReportProcessingException, DataSourceException, ReportDataFactoryException
097 {
098 // the auto-table is responsible for the iteration over the table.
099 final AutoTableElement node = (AutoTableElement) getElement();
100 if (node.getContentCount() == 0)
101 {
102 throw new ReportProcessingException
103 ("An Auto-Table must have at least one defined column.");
104 }
105
106 if (currentColumn == 0)
107 {
108 // Start a new table-header section ..
109 final AttributeMap elementMap = LayoutControllerUtil.createEmptyMap
110 (AutoTableModule.AUTOTABLE_NAMESPACE, "data-row");
111 target.startElement(elementMap);
112 }
113
114 if (currentColumn < columnCount)
115 {
116 // now delegate the processing to the section handler for the header ..
117 final FlowController flowController = getFlowController();
118 final ReportContext reportContext = flowController.getReportContext();
119 final LayoutControllerFactory layoutControllerFactory =
120 reportContext.getLayoutControllerFactory();
121
122 final int idx = currentColumn % node.getContentCount();
123 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
124 return layoutControllerFactory.create
125 (flowController, node.getContentCell(idx), derived);
126 }
127
128 // close the table-header section ..
129 final AttributeMap elementMap = LayoutControllerUtil.createEmptyMap
130 (AutoTableModule.AUTOTABLE_NAMESPACE, "data-row");
131 target.endElement(elementMap);
132
133 final FlowController flowController =
134 getFlowController().performOperation(FlowControlOperation.ADVANCE);
135 final FlowController cfc = tryRepeatingCommit(flowController);
136 if (cfc != null)
137 {
138 // Go back to the beginning. We have made a commit, so the cursor points
139 // to the next row of data ..
140 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
141 derived.setFlowController(cfc);
142 derived.currentColumn = 0;
143 return derived;
144 }
145
146 // Advance is impossible, that means we reached the end of the group or
147 // the end of the table ..
148 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
149 derived.currentColumn = 0;
150 derived.processingState = AutoTableLayoutController.HANDLING_FOOTER;
151 return derived;
152 }
153
154 private LayoutController processFooter(final ReportTarget target)
155 throws ReportProcessingException, DataSourceException, ReportDataFactoryException
156 {
157 final AutoTableElement node = (AutoTableElement) getElement();
158 if (node.getFooterCount() == 0)
159 {
160 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
161 derived.currentColumn = 0;
162 derived.processingState = -1;
163 derived.setProcessingState(ElementLayoutController.FINISHING);
164 return derived;
165 }
166
167 if (currentColumn == 0)
168 {
169 // Start a new table-header section ..
170 final AttributeMap elementMap = LayoutControllerUtil.createEmptyMap
171 (AutoTableModule.AUTOTABLE_NAMESPACE, "footer-row");
172 target.startElement(elementMap);
173 }
174
175 if (currentColumn < columnCount)
176 {
177 // now delegate the processing to the section handler for the header ..
178 final FlowController flowController = getFlowController();
179 final ReportContext reportContext = flowController.getReportContext();
180 final LayoutControllerFactory layoutControllerFactory =
181 reportContext.getLayoutControllerFactory();
182
183 final int idx = currentColumn % node.getFooterCount();
184 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
185 return layoutControllerFactory.create
186 (flowController, node.getFooterCell(idx), derived);
187 }
188
189 // close the table-header section ..
190 final AttributeMap elementMap = LayoutControllerUtil.createEmptyMap
191 (AutoTableModule.AUTOTABLE_NAMESPACE, "footer-row");
192 target.endElement(elementMap);
193
194 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
195 derived.currentColumn = 0;
196 derived.processingState = -1;
197 derived.setProcessingState(ElementLayoutController.FINISHING);
198 return derived;
199 }
200
201 private LayoutController processHeader(final ReportTarget target)
202 throws ReportProcessingException, DataSourceException, ReportDataFactoryException
203 {
204 final AutoTableElement node = (AutoTableElement) getElement();
205 if (node.getHeaderCount() == 0)
206 {
207 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
208 derived.currentColumn = 0;
209 derived.processingState = AutoTableLayoutController.HANDLING_DATA;
210 return derived;
211 }
212
213 if (currentColumn == 0)
214 {
215 // Start a new table-header section ..
216 final AttributeMap elementMap = LayoutControllerUtil.createEmptyMap
217 (AutoTableModule.AUTOTABLE_NAMESPACE, "header-row");
218 target.startElement(elementMap);
219 }
220
221 if (currentColumn < columnCount)
222 {
223 // now delegate the processing to the section handler for the header ..
224 final FlowController flowController = getFlowController();
225 final ReportContext reportContext = flowController.getReportContext();
226 final LayoutControllerFactory layoutControllerFactory =
227 reportContext.getLayoutControllerFactory();
228
229 final int idx = currentColumn % node.getHeaderCount();
230 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
231 return layoutControllerFactory.create
232 (flowController, node.getHeaderCell(idx), derived);
233 }
234
235 // close the table-header section ..
236 final AttributeMap elementMap = LayoutControllerUtil.createEmptyMap
237 (AutoTableModule.AUTOTABLE_NAMESPACE, "header-row");
238 target.endElement(elementMap);
239
240 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
241 derived.currentColumn = 0;
242 derived.processingState = AutoTableLayoutController.HANDLING_DATA;
243 return derived;
244 }
245
246 /**
247 * Joins with a delegated process flow. This is generally called from a child flow and should *not* (I mean it!) be
248 * called from outside. If you do, you'll suffer.
249 *
250 * @param flowController the flow controller of the parent.
251 * @return the joined layout controller that incorperates all changes from the delegate.
252 */
253 public LayoutController join(final FlowController flowController)
254 {
255 final AutoTableLayoutController derived = (AutoTableLayoutController) clone();
256 derived.setFlowController(flowController);
257 derived.currentColumn += 1;
258 return derived;
259 }
260
261 public int getCurrentColumn()
262 {
263 return currentColumn;
264 }
265 }