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: GlobalMasterRow.java,v 1.8 2007/04/01 18:49:24 taqua Exp $
027 * ------------
028 * (C) Copyright 2000-2005, by Object Refinery Limited.
029 * (C) Copyright 2005-2007, by Pentaho Corporation.
030 */
031 package org.jfree.report.data;
032
033 import org.jfree.report.DataRow;
034 import org.jfree.report.DataSourceException;
035 import org.jfree.report.flow.ReportContext;
036
037 /**
038 * This data row holds all statefull information from the datasources of the
039 * report.
040 * <p/>
041 * When doing subreports, a datarow only has access to its own dataset and the
042 * columns from the next direct subreport, which have been marked as exported.
043 *
044 * @author Thomas Morgner
045 */
046 public final class GlobalMasterRow
047 {
048 // private StaticDataRow previousRow;
049 private ReportDataRow reportDataRow;
050 private ParameterDataRow parameterDataRow;
051 private ExpressionDataRow expressionDataRow;
052 private GlobalMasterRow parentDataRow;
053 private GlobalView globalView;
054 private ImportedVariablesDataRow importedDataRow;
055
056 private GlobalMasterRow()
057 {
058 }
059
060 public static GlobalMasterRow createReportRow(final ReportContext reportContext)
061 {
062 GlobalMasterRow gmr = new GlobalMasterRow();
063 gmr.globalView = GlobalView.createView();
064 gmr.expressionDataRow = new ExpressionDataRow(gmr, reportContext, 10);
065 return gmr;
066 }
067
068 public static GlobalMasterRow createReportRow(final GlobalMasterRow parentRow,
069 final ReportContext reportContext)
070 {
071 GlobalMasterRow gmr = createReportRow(reportContext);
072 gmr.parentDataRow = parentRow;
073 return gmr;
074 }
075
076 public ExpressionDataRow getExpressionDataRow()
077 {
078 return expressionDataRow;
079 }
080
081 public ReportDataRow getReportDataRow()
082 {
083 return reportDataRow;
084 }
085
086 public void setReportDataRow(final ReportDataRow reportDataRow)
087 throws DataSourceException
088 {
089 this.reportDataRow = reportDataRow;
090 updateGlobalView();
091 }
092
093 public ParameterDataRow getParameterDataRow()
094 {
095 return parameterDataRow;
096 }
097
098 public void setParameterDataRow(final ParameterDataRow parameterDataRow)
099 throws DataSourceException
100 {
101 this.parameterDataRow = parameterDataRow;
102 updateGlobalView();
103 }
104
105 public GlobalMasterRow getParentDataRow()
106 {
107 return parentDataRow;
108 }
109
110 public ImportedVariablesDataRow getImportedDataRow()
111 {
112 return importedDataRow;
113 }
114
115 public void setExportedDataRow(final ImportedVariablesDataRow importedDataRow)
116 throws DataSourceException
117 {
118 this.importedDataRow = importedDataRow;
119 updateImportedParameterView();
120 }
121
122 /**
123 * Derives an instance of this datarow. That copy is completly disconnected
124 * from the original one and no change made to that copy affects the original
125 * datarow.
126 *
127 * @return the derived datarow.
128 */
129 public GlobalMasterRow derive() throws DataSourceException
130 {
131 return derive(null);
132 }
133
134 private GlobalMasterRow derive(GlobalMasterRow subReportRow)
135 throws DataSourceException
136 {
137 final GlobalMasterRow dataRow = new GlobalMasterRow();
138 dataRow.parameterDataRow = parameterDataRow;
139 dataRow.reportDataRow = reportDataRow;
140 dataRow.expressionDataRow = expressionDataRow.derive(dataRow);
141 dataRow.globalView = globalView.derive();
142 if (parentDataRow != null)
143 {
144 dataRow.parentDataRow = parentDataRow.derive(subReportRow);
145 }
146 dataRow.importedDataRow = importedDataRow;
147 return dataRow;
148 }
149
150 /**
151 * This advances the cursor by one row and updates the flags.
152 *
153 * @return
154 * @throws DataSourceException
155 */
156 public GlobalMasterRow advance() throws DataSourceException
157 {
158 return advance(false, null);
159 }
160
161 private GlobalMasterRow advance(final boolean deepTraversingOnly,
162 final GlobalMasterRow subReportRow)
163 throws DataSourceException
164 {
165 GlobalMasterRow dataRow = new GlobalMasterRow();
166 dataRow.globalView = globalView.advance();
167 dataRow.parameterDataRow = parameterDataRow;
168
169 if (deepTraversingOnly == false && reportDataRow != null)
170 {
171 dataRow.reportDataRow = reportDataRow.advance();
172 }
173 else
174 {
175 dataRow.reportDataRow = reportDataRow;
176 }
177 dataRow.updateGlobalView();
178 if (expressionDataRow != null)
179 {
180 dataRow.expressionDataRow =
181 expressionDataRow.advance(dataRow, deepTraversingOnly);
182 }
183 if (parentDataRow != null)
184 {
185 // the parent row should get a grip on our data as well - just for the
186 // deep traversing fun and so on ..
187 dataRow.parentDataRow = parentDataRow.advance(true, dataRow);
188 }
189 if (importedDataRow != null)
190 {
191 if (subReportRow == null)
192 {
193 throw new NullPointerException();
194 }
195 dataRow.importedDataRow = importedDataRow.advance(subReportRow);
196 dataRow.updateImportedParameterView();
197 }
198 return dataRow;
199 }
200
201 private void updateImportedParameterView() throws DataSourceException
202 {
203 if (importedDataRow == null)
204 {
205 return;
206 }
207
208 final int parameterCount = importedDataRow.getColumnCount();
209 for (int i = 0; i < parameterCount; i++)
210 {
211 final String columnName = importedDataRow.getColumnName(i);
212 if (columnName != null)
213 {
214 final Object columnValue = importedDataRow.get(i);
215 globalView.putField(columnName, columnValue, true);
216 }
217 }
218 }
219
220 /** This updates the global view. */
221 private void updateGlobalView() throws DataSourceException
222 {
223 if (parameterDataRow != null)
224 {
225 final int parameterCount = parameterDataRow.getColumnCount();
226 for (int i = 0; i < parameterCount; i++)
227 {
228 final String columnName = parameterDataRow.getColumnName(i);
229 if (columnName != null)
230 {
231 final Object columnValue = parameterDataRow.get(i);
232 globalView.putField(columnName, columnValue, true);
233 }
234 }
235 }
236 if (reportDataRow != null)
237 {
238 final int dataColCount = reportDataRow.getColumnCount();
239 for (int i = 0; i < dataColCount; i++)
240 {
241 final String columnName = reportDataRow.getColumnName(i);
242 if (columnName != null)
243 {
244 final Object columnValue = reportDataRow.get(i);
245 globalView.putField(columnName, columnValue, true);
246 }
247 }
248 }
249 }
250
251 public boolean isAdvanceable() throws DataSourceException
252 {
253 if (reportDataRow == null)
254 {
255 return false;
256 }
257 return reportDataRow.isAdvanceable();
258 }
259
260 public DataRow getGlobalView()
261 {
262 return globalView;
263 }
264
265 /**
266 * A call back method to communicate structural changes back to the master
267 * rows. (This is only called from the expression row, as all other datarows
268 * are static).
269 *
270 * @param chEvent
271 */
272 public void dataRowChanged(final MasterDataRowChangeEvent chEvent)
273 throws DataSourceException
274 {
275 // rebuild the global view and tracks changes ..
276 final int type = chEvent.getType();
277 if (type == MasterDataRowChangeEvent.COLUMN_ADDED)
278 {
279 globalView.putField(chEvent.getColumnName(), chEvent.getColumnValue(), false);
280 }
281 else if (type == MasterDataRowChangeEvent.COLUMN_UPDATED)
282 {
283 globalView.putField(chEvent.getColumnName(), chEvent.getColumnValue(), true);
284 }
285 else if (type == MasterDataRowChangeEvent.COLUMN_REMOVED)
286 {
287 globalView.removeColumn(chEvent.getColumnName());
288 }
289 }
290 }