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 3525 2007-10-16 11:43:48Z tmorgner $ 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 final 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 final 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(final 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 final 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 }