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: SectionLayoutController.java,v 1.16 2007/05/14 08:55:52 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.flow.layoutprocessor;
033    
034    import org.jfree.report.DataSourceException;
035    import org.jfree.report.ReportDataFactoryException;
036    import org.jfree.report.ReportProcessingException;
037    import org.jfree.report.expressions.Expression;
038    import org.jfree.report.flow.FlowController;
039    import org.jfree.report.flow.ReportContext;
040    import org.jfree.report.flow.ReportTarget;
041    import org.jfree.report.structure.Node;
042    import org.jfree.report.structure.Section;
043    
044    /**
045     * Creation-Date: 24.11.2006, 13:56:10
046     *
047     * @author Thomas Morgner
048     */
049    public class SectionLayoutController extends ElementLayoutController
050    {
051      // we store the child instead of the index, as the report can be manipulated
052      // it is safer this way ..
053      private Node[] nodes;
054      private int index;
055    
056      public SectionLayoutController()
057      {
058      }
059    
060      protected FlowController startData(final ReportTarget target,
061                                         final FlowController fc)
062          throws DataSourceException, ReportProcessingException,
063          ReportDataFactoryException
064      {
065        final Section s = (Section) getElement();
066        return LayoutControllerUtil.processFlowOperations
067            (fc, s.getOperationBefore());
068      }
069    
070      protected LayoutController processContent(final ReportTarget target)
071          throws DataSourceException, ReportProcessingException,
072          ReportDataFactoryException
073      {
074    
075        final FlowController flowController = getFlowController();
076    
077        final Node[] nodes = getNodes();
078        final int currentIndex = getIndex();
079        if (currentIndex < nodes.length)
080        {
081          final Node node = nodes[currentIndex];
082          final SectionLayoutController derived = (SectionLayoutController) clone();
083          return processChild(derived, node, flowController);
084        }
085        else
086        {
087          final SectionLayoutController derived = (SectionLayoutController) clone();
088          derived.setProcessingState(ElementLayoutController.FINISHING);
089          return derived;
090        }
091      }
092    
093      protected LayoutController processChild(final SectionLayoutController derived,
094                                              final Node node,
095                                              final FlowController flowController)
096          throws DataSourceException, ReportProcessingException,
097          ReportDataFactoryException
098      {
099        final ReportContext reportContext = flowController.getReportContext();
100        final LayoutControllerFactory layoutControllerFactory = reportContext.getLayoutControllerFactory();
101        if (isDisplayable(node))
102        {
103          derived.setProcessingState(ElementLayoutController.WAITING_FOR_JOIN);
104          return layoutControllerFactory.create(flowController, node, derived);
105        }
106        else
107        {
108          derived.setProcessingState(ElementLayoutController.WAITING_FOR_JOIN);
109          final LayoutController childLc = layoutControllerFactory.create(flowController, node, derived);
110          return LayoutControllerUtil.skipInvisibleElement(childLc);
111    //      derived.setIndex(derived.getIndex() + 1);
112    //      return LayoutControllerUtil.skipInvisibleElement(derived);
113        }
114      }
115    
116      private boolean isDisplayable(final Node node)
117          throws DataSourceException
118      {
119        if (node.isEnabled() == false)
120        {
121          return false;
122        }
123    
124        final Expression expression = node.getDisplayCondition();
125        if (expression == null)
126        {
127          return true;
128        }
129    
130        final Object result = LayoutControllerUtil.evaluateExpression
131            (getFlowController(), node, expression);
132        if (Boolean.TRUE.equals(result))
133        {
134          return true;
135        }
136        return false;
137      }
138    
139      /**
140       * Finishes the processing of this element. This method is called when the
141       * processing state is 'FINISHING'. The element should be closed now and all
142       * privatly owned resources should be freed. If the element has a parent, it
143       * would be time to join up with the parent now, else the processing state
144       * should be set to 'FINISHED'.
145       *
146       * @param target the report target that receives generated events.
147       * @return the new layout controller instance representing the new state.
148       *
149       * @throws DataSourceException        if there was a problem reading data from
150       *                                    the datasource.
151       * @throws ReportProcessingException  if there was a general problem during
152       *                                    the report processing.
153       * @throws ReportDataFactoryException if there was an error trying query
154       *                                    data.
155       */
156      protected LayoutController finishElement(final ReportTarget target)
157          throws ReportProcessingException, DataSourceException,
158          ReportDataFactoryException
159      {
160        FlowController fc = handleDefaultEndElement(target);
161    
162        // unwind the stack ..
163        final Section s = (Section) getElement();
164        fc = finishData(target, fc);
165    
166        if (s.isRepeat())
167        {
168          final FlowController cfc = tryRepeatingCommit(fc);
169          if (cfc != null)
170          {
171            // Go back to the beginning ...
172            final SectionLayoutController derived = (SectionLayoutController) clone();
173            derived.setProcessingState(ElementLayoutController.NOT_STARTED);
174            derived.setFlowController(cfc);
175            derived.resetSectionForRepeat();
176            return derived;
177          }
178        }
179    
180        // Go back to the beginning ...
181        final SectionLayoutController derived = (SectionLayoutController) clone();
182        derived.setProcessingState(ElementLayoutController.FINISHED);
183        derived.setFlowController(fc);
184        return derived;
185      }
186    
187      protected void resetSectionForRepeat()
188      {
189        setIndex(0);
190      }
191    
192      protected FlowController finishData(final ReportTarget target,
193                                          final FlowController fc)
194          throws DataSourceException, ReportProcessingException
195      {
196        final Section s = (Section) getElement();
197        return LayoutControllerUtil.processFlowOperations
198            (fc, s.getOperationAfter());
199      }
200    
201      /**
202       * Joins with a delegated process flow. This is generally called from a child
203       * flow and should *not* (I mean it!) be called from outside. If you do,
204       * you'll suffer.
205       *
206       * @param flowController the flow controller of the parent.
207       * @return the joined layout controller that incorperates all changes from the
208       *         delegate.
209       */
210      public LayoutController join(final FlowController flowController)
211      {
212        final Node[] nodes = getNodes();
213        int index = getIndex() + 1;
214        for (; index < nodes.length; index++)
215        {
216          final Node node = nodes[index];
217          if (node.isEnabled())
218          {
219            break;
220          }
221        }
222    
223        if (index < nodes.length)
224        {
225          final SectionLayoutController derived = (SectionLayoutController) clone();
226          derived.setProcessingState(ElementLayoutController.OPENED);
227          derived.setFlowController(flowController);
228          derived.setIndex(index);
229          return derived;
230        }
231    
232        final SectionLayoutController derived = (SectionLayoutController) clone();
233        derived.setProcessingState(ElementLayoutController.FINISHING);
234        derived.setFlowController(flowController);
235        return derived;
236      }
237    
238      public Node[] getNodes()
239      {
240        if (nodes == null)
241        {
242          final Section s = (Section) getElement();
243          nodes = s.getNodeArray();
244        }
245        return nodes;
246      }
247    
248      public int getIndex()
249      {
250        return index;
251      }
252    
253      public void setIndex(final int index)
254      {
255        this.index = index;
256      }
257    }