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    }