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 3057 2007-07-30 14:27:28Z 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.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      protected 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(getFlowController(), node, expression);
131        if (Boolean.TRUE.equals(result))
132        {
133          return true;
134        }
135        return false;
136      }
137    
138      /**
139       * Finishes the processing of this element. This method is called when the
140       * processing state is 'FINISHING'. The element should be closed now and all
141       * privatly owned resources should be freed. If the element has a parent, it
142       * would be time to join up with the parent now, else the processing state
143       * should be set to 'FINISHED'.
144       *
145       * @param target the report target that receives generated events.
146       * @return the new layout controller instance representing the new state.
147       *
148       * @throws DataSourceException        if there was a problem reading data from
149       *                                    the datasource.
150       * @throws ReportProcessingException  if there was a general problem during
151       *                                    the report processing.
152       * @throws ReportDataFactoryException if there was an error trying query
153       *                                    data.
154       */
155      protected LayoutController finishElement(final ReportTarget target)
156          throws ReportProcessingException, DataSourceException,
157          ReportDataFactoryException
158      {
159        FlowController fc = handleDefaultEndElement(target);
160    
161        // unwind the stack ..
162        final Section s = (Section) getElement();
163        fc = finishData(target, fc);
164    
165        if (s.isRepeat())
166        {
167          final FlowController cfc = tryRepeatingCommit(fc);
168          if (cfc != null)
169          {
170            // Go back to the beginning ...
171            final SectionLayoutController derived = (SectionLayoutController) clone();
172            derived.setProcessingState(ElementLayoutController.NOT_STARTED);
173            derived.setFlowController(cfc);
174            derived.resetSectionForRepeat();
175            return derived;
176          }
177        }
178    
179        // Go back to the beginning ...
180        final SectionLayoutController derived = (SectionLayoutController) clone();
181        derived.setProcessingState(ElementLayoutController.FINISHED);
182        derived.setFlowController(fc);
183        return derived;
184      }
185    
186      protected void resetSectionForRepeat()
187      {
188        setIndex(0);
189      }
190    
191      protected FlowController finishData(final ReportTarget target,
192                                          final FlowController fc)
193          throws DataSourceException, ReportProcessingException
194      {
195        final Section s = (Section) getElement();
196        return LayoutControllerUtil.processFlowOperations
197            (fc, s.getOperationAfter());
198      }
199    
200      /**
201       * Joins with a delegated process flow. This is generally called from a child
202       * flow and should *not* (I mean it!) be called from outside. If you do,
203       * you'll suffer.
204       *
205       * @param flowController the flow controller of the parent.
206       * @return the joined layout controller that incorperates all changes from the
207       *         delegate.
208       */
209      public LayoutController join(final FlowController flowController)
210      {
211        final Node[] nodes = getNodes();
212        int index = getIndex() + 1;
213        for (; index < nodes.length; index++)
214        {
215          final Node node = nodes[index];
216          if (node.isEnabled())
217          {
218            break;
219          }
220        }
221    
222        if (index < nodes.length)
223        {
224          final SectionLayoutController derived = (SectionLayoutController) clone();
225          derived.setProcessingState(ElementLayoutController.OPENED);
226          derived.setFlowController(flowController);
227          derived.setIndex(index);
228          return derived;
229        }
230    
231        final SectionLayoutController derived = (SectionLayoutController) clone();
232        derived.setProcessingState(ElementLayoutController.FINISHING);
233        derived.setFlowController(flowController);
234        return derived;
235      }
236    
237      public Node[] getNodes()
238      {
239        if (nodes == null)
240        {
241          final Section s = (Section) getElement();
242          nodes = s.getNodeArray();
243        }
244        return nodes;
245      }
246    
247      public int getIndex()
248      {
249        return index;
250      }
251    
252      public void setIndex(final int index)
253      {
254        this.index = index;
255      }
256    }