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 3048 2007-07-28 18:02:42Z tmorgner $ 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 }