Package ar.com.fdvs.dj.core.layout

Source Code of ar.com.fdvs.dj.core.layout.ClassicLayoutManager

/*
* DynamicJasper: A library for creating reports dynamically by specifying
* columns, groups, styles, etc. at runtime. It also saves a lot of development
* time in many cases! (http://sourceforge.net/projects/dynamicjasper)
*
* Copyright (C) 2008  FDV Solutions (http://www.fdvsolutions.com)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
*
* License as published by the Free Software Foundation; either
*
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
*
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
*
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*
*
*/

package ar.com.fdvs.dj.core.layout;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import net.sf.jasperreports.crosstabs.design.JRDesignCrosstab;
import net.sf.jasperreports.engine.JRElement;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRGraphicElement;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.design.JRDesignBand;
import net.sf.jasperreports.engine.design.JRDesignBreak;
import net.sf.jasperreports.engine.design.JRDesignElement;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignGroup;
import net.sf.jasperreports.engine.design.JRDesignImage;
import net.sf.jasperreports.engine.design.JRDesignRectangle;
import net.sf.jasperreports.engine.design.JRDesignStyle;
import net.sf.jasperreports.engine.design.JRDesignSubreport;
import net.sf.jasperreports.engine.design.JRDesignSubreportParameter;
import net.sf.jasperreports.engine.design.JRDesignTextField;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import ar.com.fdvs.dj.core.CoreException;
import ar.com.fdvs.dj.core.DJConstants;
import ar.com.fdvs.dj.core.DynamicJasperHelper;
import ar.com.fdvs.dj.core.FontHelper;
import ar.com.fdvs.dj.core.registration.ColumnsGroupVariablesRegistrationManager;
import ar.com.fdvs.dj.domain.AutoText;
import ar.com.fdvs.dj.domain.DJCalculation;
import ar.com.fdvs.dj.domain.DJCrosstab;
import ar.com.fdvs.dj.domain.DynamicJasperDesign;
import ar.com.fdvs.dj.domain.ImageBanner;
import ar.com.fdvs.dj.domain.Style;
import ar.com.fdvs.dj.domain.constants.Border;
import ar.com.fdvs.dj.domain.constants.GroupLayout;
import ar.com.fdvs.dj.domain.constants.Transparency;
import ar.com.fdvs.dj.domain.entities.DJGroup;
import ar.com.fdvs.dj.domain.entities.DJGroupVariable;
import ar.com.fdvs.dj.domain.entities.Subreport;
import ar.com.fdvs.dj.domain.entities.SubreportParameter;
import ar.com.fdvs.dj.domain.entities.columns.AbstractColumn;
import ar.com.fdvs.dj.domain.entities.columns.GlobalGroupColumn;
import ar.com.fdvs.dj.domain.entities.columns.PropertyColumn;
import ar.com.fdvs.dj.util.ExpressionUtils;
import ar.com.fdvs.dj.util.LayoutUtils;

/**
* Main Layout Manager recommended for most cases.</br>
* </br>
* It provides DJ full features (styles, groups, conditional styles, </br>
* expressions, group and total variables, etc)
*/
public class ClassicLayoutManager extends AbstractLayoutManager {

  protected static final String PAGE_BREAK_FOR_ = "pageBreak_for_";

  protected static final int SUBREPORT_DEFAULT_HEIGHT = 30;

  private static final Log log = LogFactory.getLog(ClassicLayoutManager.class);

  protected static final String EXPRESSION_TRUE_WHEN_NOT_FIRST_PAGE = "new java.lang.Boolean(((Number)$V{PAGE_NUMBER}).doubleValue() != 1)";
  protected static final String EXPRESSION_TRUE_WHEN_FIRST_PAGE = "new java.lang.Boolean(((Number)$V{PAGE_NUMBER}).doubleValue() == 1)";

//  private Random subReportRandom = new Random();

  protected void startLayout() {
    super.startLayout();
    generateTitleBand();
    generateHeaderBand();
    applyHeaderAutotexts();

    if (getReport().getColumnsGroups() != null)
      layoutGroups();
  }

  /**
   *
   */
  protected void applyHeaderAutotexts() {
    if (getReport().getAutoTexts() == null)
      return;
    /**
     * Apply the autotext in footer if any
     */
    JRDesignBand headerband = (JRDesignBand) getDesign().getPageHeader();
    if (headerband == null ) {
      headerband = new JRDesignBand();
      getDesign().setPageHeader(headerband);
    }

    ArrayList positions = new ArrayList();
    positions.add(HorizontalBandAlignment.LEFT);
    positions.add(HorizontalBandAlignment.CENTER);
    positions.add(HorizontalBandAlignment.RIGHT);

    ArrayList autotexts = new ArrayList(getReport().getAutoTexts());
    Collections.reverse(autotexts);

    int totalYoffset = findTotalOffset(positions,autotexts, AutoText.POSITION_HEADER);
    LayoutUtils.moveBandsElemnts(totalYoffset, headerband);

    for (Iterator iterator = positions.iterator(); iterator.hasNext();) {
      HorizontalBandAlignment currentAlignment = (HorizontalBandAlignment) iterator.next();
      int yOffset = 0;

      for (Iterator iter = getReport().getAutoTexts().iterator(); iter.hasNext();) {
        AutoText text = (AutoText) iter.next();
        if (text.getPosition() == AutoText.POSITION_HEADER && text.getAlignment().equals(currentAlignment)) {
          CommonExpressionsHelper.add(yOffset,getDesign(), getReport(), headerband, text);
          yOffset += text.getHeight().intValue();
        }
      }
    }

    /** END */
  }

  /**
   * Finds the highest sum of height for each possible alignment (left, center, right)
   * @param aligments
   * @param autotexts
   * @return
   */
  protected int findTotalOffset(ArrayList aligments, ArrayList autotexts, byte position) {
    int total = 0;
    for (Iterator iterator = aligments.iterator(); iterator.hasNext();) {
      HorizontalBandAlignment currentAlignment = (HorizontalBandAlignment) iterator.next();
      int aux = 0;
      for (Iterator iter = getReport().getAutoTexts().iterator(); iter.hasNext();) {
        AutoText autotext = (AutoText) iter.next();
        if (autotext.getPosition() == position && currentAlignment.equals(autotext.getAlignment())) {
          aux += autotext.getHeight().intValue();
        }
      }
      if (aux > total)
        total = aux;
    }
    return total;
  }

  protected void endLayout() {
    super.endLayout();
    applyBanners();
    applyFooterAutotexts();
    setBandsFinalHeight();
  }

  protected void applyFooterAutotexts() {
    if (getReport().getAutoTexts() == null)
      return;

    JRDesignBand footerband = (JRDesignBand) getDesign().getPageFooter();
    if (footerband == null ) {
      footerband = new JRDesignBand();
      getDesign().setPageFooter(footerband);
    }

    ArrayList positions = new ArrayList();
    positions.add(HorizontalBandAlignment.LEFT);
    positions.add(HorizontalBandAlignment.CENTER);
    positions.add(HorizontalBandAlignment.RIGHT);

    for (Iterator iterator = positions.iterator(); iterator.hasNext();) {
      HorizontalBandAlignment currentAlignment = (HorizontalBandAlignment) iterator.next();
      int yOffset = 0;
      /**
       * Apply the autotext in footer if any
       */
      for (Iterator iter = getReport().getAutoTexts().iterator(); iter.hasNext();) {
        AutoText autotext = (AutoText) iter.next();
        if (autotext.getPosition() == AutoText.POSITION_FOOTER && autotext.getAlignment().equals(currentAlignment) ) {
          CommonExpressionsHelper.add(yOffset,getDesign(), getReport(), footerband, autotext);
          yOffset += autotext.getHeight().intValue();
        }
      }

    }
  }

  /**
   * Returns a list with the columns that are visible.
   * Invisible column are the one whose group is configured with hideColumn = true (in the GroupLayout)
   * @return
   */
  protected List getVisibleColumns() {
    List visibleColums = new ArrayList(getReport().getColumns());
    for (Iterator iterator = getReport().getColumnsGroups().iterator(); iterator.hasNext();) {
      DJGroup group = (DJGroup) iterator.next();
      if (group.getLayout().isHideColumn()){
        visibleColums.remove(group.getColumnToGroupBy());
      }
    }
    return visibleColums;
  }

  /**
   * Create the image elements for the banners tha goes into the
   * title and header bands depending on the case
   *
   */
  protected void applyBanners() {
    /**
     * First create image banners for the first page only
     */
    JRDesignBand title = (JRDesignBand) getDesign().getTitle();
    //if there is no title band, but there are banner images for the first page, we create a title band
    if (title == null && !getReport().getOptions().getFirstPageImageBanners().isEmpty()){
      title = new JRDesignBand();
      getDesign().setTitle(title);
    }
    applyImageBannersToBand(title,getReport().getOptions().getFirstPageImageBanners().values(),null);

    /**
     * Now create image banner for the rest of the pages
     */
    JRDesignBand pageHeader = (JRDesignBand) getDesign().getPageHeader();
    //if there is no title band, but there are banner images for the first page, we create a title band
    if (pageHeader == null && !getReport().getOptions().getImageBanners().isEmpty()){
      pageHeader = new JRDesignBand();
      getDesign().setPageHeader(pageHeader);
    }
    JRDesignExpression printWhenExpression = null;
    if (!getReport().getOptions().getFirstPageImageBanners().isEmpty()){
      printWhenExpression = new JRDesignExpression();
      printWhenExpression.setValueClass(Boolean.class);
      printWhenExpression.setText(EXPRESSION_TRUE_WHEN_NOT_FIRST_PAGE);
    }
    applyImageBannersToBand(pageHeader,getReport().getOptions().getImageBanners().values(),printWhenExpression);


  }
  /**
   * Create the image elements for the banners tha goes into the
   * title band
   * @param printWhenExpression
   *
   */
  protected void applyImageBannersToBand(JRDesignBand band, Collection imageBanners, JRDesignExpression printWhenExpression ) {
    int maxHeight = 0;
    for (Iterator iter = imageBanners.iterator(); iter.hasNext();) {
      ImageBanner imageBanner = (ImageBanner) iter.next();
      if (imageBanner.getHeight() > maxHeight)
        maxHeight = imageBanner.getHeight();
    }

    if (band != null){
      //move everything down
      for (Iterator iter =band.getChildren().iterator(); iter.hasNext();) {
        JRDesignElement element = (JRDesignElement) iter.next();
        element.setY(element.getY() + maxHeight);
      }

      for (Iterator iter = imageBanners.iterator(); iter.hasNext();) {
        ImageBanner imageBanner = (ImageBanner) iter.next();
        String path = "\"" + imageBanner.getImagePath().replaceAll("\\\\", "/") + "\"";
        JRDesignImage image = new JRDesignImage(new JRDesignStyle().getDefaultStyleProvider());
        JRDesignExpression imageExp = new JRDesignExpression();
        imageExp.setText(path);

        imageExp.setValueClass(String.class);
        image.setExpression(imageExp);
        image.setHeight(imageBanner.getHeight());
        image.setWidth(imageBanner.getWidth());
        image.setPrintWhenExpression(printWhenExpression);
        image.setRemoveLineWhenBlank(true);

        if (imageBanner.getAlign() == ImageBanner.ALIGN_LEFT)
          image.setX(0);
        else if (imageBanner.getAlign() == ImageBanner.ALIGN_RIGHT)
          image.setX(getReport().getOptions().getPage().getWidth() -  getReport().getOptions().getLeftMargin().intValue() - getReport().getOptions().getRightMargin().intValue() - imageBanner.getWidth());
        else if (imageBanner.getAlign() == ImageBanner.ALIGN_CENTER){
          int x = (getReport().getOptions().getPage().getWidth() -
              getReport().getOptions().getRightMargin().intValue() -
              getReport().getOptions().getLeftMargin().intValue() - imageBanner.getWidth()) / 2;
          image.setX(getReport().getOptions().getLeftMargin().intValue() + x);
        }

        image.setY(0);
        band.addElement(image);

      }
      band.setHeight(band.getHeight() + maxHeight);
    }
  }

  /**
   * Adds title and subtitle to the TitleBand when it applies.
   * If title is not present then subtitle will be ignored
   */
  protected void generateTitleBand() {
    log.debug("Generating title band...");
    JRDesignBand band = (JRDesignBand) getDesign().getPageHeader();
    int yOffset = 0;

    //If title is not present then subtitle will be ignored
    if (getReport().getTitle() == null)
      return;

    if (band != null && !getDesign().isTitleNewPage()){
      //Title and subtitle comes afer the page header
      yOffset = band.getHeight();

    } else {
      band = (JRDesignBand) getDesign().getTitle();
      if (band == null){
        band = new JRDesignBand();
        getDesign().setTitle(band);
      }
    }

    JRDesignExpression printWhenExpression = new JRDesignExpression();
    printWhenExpression.setValueClass(Boolean.class);
    printWhenExpression.setText(EXPRESSION_TRUE_WHEN_FIRST_PAGE);

    JRDesignTextField title = new JRDesignTextField();
    JRDesignExpression exp = new JRDesignExpression();
    exp.setText("\"" + getReport().getTitle() + "\"");
    exp.setValueClass(String.class);
    title.setExpression(exp);
    title.setWidth(getReport().getOptions().getPrintableWidth());
    title.setHeight(getReport().getOptions().getTitleHeight().intValue());
    title.setY(yOffset);
    title.setPrintWhenExpression(printWhenExpression);
    title.setRemoveLineWhenBlank(true);
    applyStyleToElement(getReport().getTitleStyle(), title);
    title.setStretchType(JRGraphicElement.STRETCH_TYPE_NO_STRETCH);
    band.addElement(title);

    JRDesignTextField subtitle = new JRDesignTextField();
    if (getReport().getSubtitle() != null) {
      JRDesignExpression exp2 = new JRDesignExpression();
      exp2.setText("\"" + getReport().getSubtitle() + "\"");
      exp2.setValueClass(String.class);
      subtitle.setExpression(exp2);
      subtitle.setWidth(getReport().getOptions().getPrintableWidth());
      subtitle.setHeight(getReport().getOptions().getSubtitleHeight().intValue());
      subtitle.setY(title.getY() + title.getHeight());
      subtitle.setPrintWhenExpression(printWhenExpression);
      subtitle.setRemoveLineWhenBlank(true);
      applyStyleToElement(getReport().getSubtitleStyle(), subtitle);
      title.setStretchType(JRGraphicElement.STRETCH_TYPE_NO_STRETCH);
      band.addElement(subtitle);
    }

  }

  /**
   * Layout columns in groups by reading the corresponding report options.
   * @throws LayoutException
   */
  protected void layoutGroups() {
    log.debug("Starting groups layout...");
    int i = 0;
    for (Iterator iter = getReport().getColumnsGroups().iterator(); iter.hasNext();) {
      DJGroup columnsGroup = (DJGroup) iter.next();
//      JRDesignGroup jgroup = (JRDesignGroup) getDesign().getGroupsList().get(i++);
      JRDesignGroup jgroup = getJRGroupFromDJGroup(columnsGroup);

      jgroup.setStartNewPage(columnsGroup.getStartInNewPage().booleanValue());
      jgroup.setStartNewColumn(columnsGroup.getStartInNewColumn().booleanValue());

      JRDesignBand header = (JRDesignBand) jgroup.getGroupHeader();
      JRDesignBand footer = (JRDesignBand) jgroup.getGroupFooter();
      header.setHeight(columnsGroup.getHeaderHeight().intValue());
      footer.setHeight(columnsGroup.getFooterHeight().intValue());

      header.setSplitAllowed(columnsGroup.isAllowHeaderSplit());
      footer.setSplitAllowed(columnsGroup.isAllowFooterSplit());

      if (columnsGroup.getLayout().isPrintHeaders()) {
        boolean found = false;
        boolean skipPreviousGroupHeaders = false;
        int groupIdx = getReport().getColumnsGroups().indexOf(columnsGroup);
        if (groupIdx>0){
          DJGroup prevG =  (DJGroup) getReport().getColumnsGroups().get(groupIdx-1);
          skipPreviousGroupHeaders = !prevG.getLayout().isShowValueForEachRow();
        }
        for (Iterator iterator =  getVisibleColumns().iterator(); iterator.hasNext();) {
          AbstractColumn col = (AbstractColumn) iterator.next();

          //If in a nested group, header for column prior to this groups column
          //depends on configuration

          if (col.equals(columnsGroup.getColumnToGroupBy())) {
            found = true;
          }

          if (!found && skipPreviousGroupHeaders){
            continue;
          }

          JRDesignTextField designTextField = createColumnNameTextField(columnsGroup, col);
          designTextField.setPositionType(JRDesignElement.POSITION_TYPE_FLOAT); //XXX changed to see what happens  (must come from the column position property)
          designTextField.setStretchType(JRDesignElement.STRETCH_TYPE_NO_STRETCH); //XXX changed to see what happens (must come from the column property)
          header.addElement(designTextField);
        }
      }
      layoutGroupVariables(columnsGroup, jgroup);
      layoutGroupSubreports(columnsGroup, jgroup);
      layoutGroupCrosstabs(columnsGroup, jgroup);
    }
  }

  /**
   * Looks for crosstabs in the groups, if any, it does the layout
   *
   * @param columnsGroup
   * @param jgroup
   */
  protected void layoutGroupCrosstabs(DJGroup columnsGroup,  JRDesignGroup jgroup) {
    for (Iterator iterator = columnsGroup.getHeaderCrosstabs().iterator(); iterator.hasNext();) {
      DJCrosstab djcross = (DJCrosstab) iterator.next();

      Dj2JrCrosstabBuilder djcb = new Dj2JrCrosstabBuilder();

      JRDesignCrosstab crosst = djcb.createCrosstab(djcross,this);
      JRDesignBand band = (JRDesignBand) jgroup.getGroupHeader();
      if (djcross.getBottomSpace() != 0){
        JRDesignRectangle rect = createBlankRectableCrosstab(djcross.getBottomSpace(), 0);
        LayoutUtils.moveBandsElemnts(rect.getHeight(), band);
        band.addElement(rect);
      }
      LayoutUtils.moveBandsElemnts(crosst.getHeight(), band);
      band.addElement(crosst);
      if (djcross.getTopSpace() != 0){
        LayoutUtils.moveBandsElemnts(djcross.getTopSpace(), band);
        JRDesignRectangle rect = createBlankRectableCrosstab(djcross.getBottomSpace(), 0);
        band.addElement(rect);
      }

    }

    for (Iterator iterator = columnsGroup.getFooterCrosstabs().iterator(); iterator.hasNext();) {
      DJCrosstab djcross = (DJCrosstab) iterator.next();

      Dj2JrCrosstabBuilder djcb = new Dj2JrCrosstabBuilder();

      JRDesignCrosstab crosst = djcb.createCrosstab(djcross,this);
      JRDesignBand band = (JRDesignBand) jgroup.getGroupFooter();
      int yOffset = LayoutUtils.findVerticalOffset(band);
      if (djcross.getTopSpace() != 0){
//        moveBandsElemnts(djcross.getTopSpace(), band);
        JRDesignRectangle rect = createBlankRectableCrosstab(djcross.getBottomSpace(), yOffset);
        rect.setPositionType(JRDesignElement.POSITION_TYPE_FIX_RELATIVE_TO_TOP);
        band.addElement(rect);
        crosst.setY(rect.getY() + rect.getHeight());
      }

      band.addElement(crosst);


      if (djcross.getBottomSpace() != 0){
        JRDesignRectangle rect = createBlankRectableCrosstab(djcross.getBottomSpace(), crosst.getY() + crosst.getHeight());
        band.addElement(rect);
      }
    }


  }

  /**
   * @param djcross
   * @param crosst
   * @return
   */
  protected JRDesignRectangle createBlankRectableCrosstab(int amount,int yOffset) {
    JRDesignRectangle rect = new JRDesignRectangle();
    rect.setPen(Border.NO_BORDER.getValue());
    rect.setMode(Transparency.TRANSPARENT.getValue());
//    rect.setMode(Transparency.OPAQUE.getValue());
//    rect.setBackcolor(Color.RED);
    rect.setWidth(getReport().getOptions().getPrintableWidth());
    rect.setHeight(amount);
    rect.setY(yOffset);
    rect.setPositionType(JRDesignElement.POSITION_TYPE_FLOAT);
    return rect;
  }

  /**
   * @param columnsGroup
   * @param col
   * @return
   */
  protected JRDesignTextField createColumnNameTextField(DJGroup columnsGroup, AbstractColumn col) {
    JRDesignTextField designStaticText = new JRDesignTextField();
    JRDesignExpression exp = new JRDesignExpression();
    exp.setText("\"" + col.getTitle() + "\"");
    exp.setValueClass(String.class);
    designStaticText.setExpression(exp);
    designStaticText.setHeight(columnsGroup.getHeaderHeight().intValue());
    designStaticText.setWidth(col.getWidth().intValue());
    designStaticText.setX(col.getPosX().intValue());
    designStaticText.setY(col.getPosY().intValue());

    Style headerStyle = columnsGroup.getColumnHeaderStyle(col);
    if (headerStyle == null)
      headerStyle = columnsGroup.getDefaultColumnHeaederStyle();
    if (headerStyle == null)
      headerStyle = col.getHeaderStyle();

    applyStyleToElement(headerStyle, designStaticText);
    return designStaticText;
  }

  /**
   * If there is a SubReport on a Group, we do the layout here
   * @param columnsGroup
   * @param jgroup
   */
  protected void layoutGroupSubreports(DJGroup columnsGroup, JRDesignGroup jgroup) {
    log.debug("Starting subreport layout...");
    JRDesignBand footerBand = (JRDesignBand) jgroup.getGroupFooter();
    JRDesignBand headerBand = (JRDesignBand) jgroup.getGroupHeader();

    layOutSubReportInBand(columnsGroup, headerBand, DJConstants.HEADER);
    layOutSubReportInBand(columnsGroup, footerBand, DJConstants.FOOTER);

  }

  /**
   * @param columnsGroup
   * @param band
   * @param position
   */
  protected void layOutSubReportInBand(DJGroup columnsGroup, JRDesignBand band, String position) {

    List subreportsList = DJConstants.FOOTER.equals(position)
        ? columnsGroup.getFooterSubreports()
        : columnsGroup.getHeaderSubreports();

    for (Iterator iterator = subreportsList.iterator(); iterator.hasNext();) {
      Subreport sr = (Subreport) iterator.next();
      JRDesignSubreport subreport = new JRDesignSubreport(new JRDesignStyle().getDefaultStyleProvider());

      //The data source
      int dataSourceOrigin = sr.getDatasource().getDataSourceOrigin();
      if (DJConstants.DATA_SOURCE_ORIGIN_USE_REPORT_CONNECTION == dataSourceOrigin){
        JRDesignExpression connectionExpression = ExpressionUtils.getReportConnectionExpression();
        subreport.setConnectionExpression(connectionExpression);
      } else if (DJConstants.DATA_SOURCE_TYPE_SQL_CONNECTION == sr.getDatasource().getDataSourceType()) {
        JRDesignExpression connectionExpression = ExpressionUtils.getConnectionExpression(sr.getDatasource());
        subreport.setConnectionExpression(connectionExpression);
      } else {
        JRDesignExpression dataSourceExpression = ExpressionUtils.getDataSourceExpression(sr.getDatasource());
        subreport.setDataSourceExpression(dataSourceExpression);
      }

//      int random_ = subReportRandom.nextInt();
      //the subreport design
      String paramname = sr.getReport().toString(); //TODO ensure this name is unique among all possible subreports
      ((DynamicJasperDesign)getDesign()).getParametersWithValues().put(paramname, sr.getReport());
      String expText = "("+JasperReport.class.getName()+")$P{REPORT_PARAMETERS_MAP}.get( \""+ paramname +"\" )";
      JRDesignExpression srExpression = ExpressionUtils.createExpression(expText, JasperReport.class);
      subreport.setExpression(srExpression );


      //set the parameters
      subreport.setParametersMapExpression(ExpressionUtils.getParameterExpression(sr));
      for (Iterator subreportParamsIter = sr.getParameters().iterator(); subreportParamsIter.hasNext();) {
        SubreportParameter srparam = (SubreportParameter) subreportParamsIter.next();
        JRDesignSubreportParameter subreportParameter = new JRDesignSubreportParameter();
        subreportParameter.setName(srparam.getName());
        JRExpression expression2 = ExpressionUtils.createExpression(srparam);
        subreportParameter.setExpression(expression2);
        try {
          subreport.addParameter(subreportParameter );
        } catch (JRException e) {
          log.error("Error registering parameter for subreport, there must be another parameter with the same name");
          throw new CoreException(e.getMessage(),e);
        }
      }

      //some other options (cosmetic)
      //subreport.setStretchType(JRDesignElement.STRETCH_TYPE_NO_STRETCH);
      int offset = LayoutUtils.findVerticalOffset(band);
      subreport.setY(offset);
      subreport.setX(-getReport().getOptions().getLeftMargin().intValue());
      subreport.setWidth(getReport().getOptions().getPage().getWidth());
      subreport.setHeight(SUBREPORT_DEFAULT_HEIGHT);
      subreport.setPositionType(JRElement.POSITION_TYPE_FLOAT);
      subreport.setStretchType(JRElement.STRETCH_TYPE_NO_STRETCH);
      subreport.setRemoveLineWhenBlank(true); //No subreport, no reserved space

      band.setHeight(offset + subreport.getHeight());
     
      if (sr.getStyle() != null)
        applyStyleToElement(sr.getStyle(), subreport);

      //adding to the band
      if (sr.isStartInNewPage()) {
        JRDesignGroup jrgroup = getJRGroupFromDJGroup(columnsGroup);
        JRDesignBand targetBand = null;
        int idx = getDesign().getGroupsList().indexOf(jrgroup);
        if (DJConstants.HEADER.equals(position)) {
//          if (idx == 0){
//            if (getDesign().getColumnHeader() != null)
//              targetBand = (JRDesignBand) getDesign().getColumnHeader();
//            else if (getDesign().getPageHeader() != null)
//              targetBand = (JRDesignBand) getDesign().getPageHeader();
//            else
//              targetBand = band;
//          }
//          else
//            targetBand = (JRDesignBand) ((JRDesignGroup) getDesign().getGroupsList().get(idx-1)).getGroupHeader();
        }
        else { //footer subreport (and concatenated report)
          if (idx+1 <  getDesign().getGroupsList().size())
            idx++;
          targetBand = (JRDesignBand) ((JRDesignGroup) getDesign().getGroupsList().get(idx)).getGroupFooter();
        }

        /**
         * There is no meaning in adding a page-break in header sub reports since
         * they will be placed right after the group header
         */
        if (DJConstants.FOOTER.equals(position)){
          JRDesignBreak pageBreak = new JRDesignBreak(new JRDesignStyle().getDefaultStyleProvider());
          pageBreak.setKey(PAGE_BREAK_FOR_ + jrgroup.toString()); //set up a name to recognize the item later
          pageBreak.setY(0);
          targetBand.addElement(pageBreak);
        }

      }
      band.addElement(subreport);
     
      sendPageBreakToBottom(band);

      /**
       * A subreport is placed in a group header or footer. This option configures the group's
       * header/footer band to allow it contents to be split. I'm not sure splitting logic works
       * inside complex object such as sub-reports since it has it's own bands inside
       */
      band.setSplitAllowed(sr.isSplitAllowed());
    }
  }

  /**
   * page breaks should be near the bottom of the band, this method used while adding subreports
   * which has the "start on new page" option.
   * @param band
   */
  protected void sendPageBreakToBottom(JRDesignBand band) {
    JRElement[] elems = band.getElements();
    JRElement aux = null;
    for (int i = 0; i < elems.length; i++) {
      if ((""+elems[i].getKey()).startsWith(PAGE_BREAK_FOR_)){
        aux = elems[i];
        break;
      }
    }
    if (aux != null)
      ((JRDesignElement)aux).setY(band.getHeight());
  }

  /**
   * If variables are present for a given group, they are placed in it's
   * header/footer band.
   * @param DJGroup group
   * @param JRDesignGroup jgroup
   * @throws LayoutException
   */
  protected void layoutGroupVariables(DJGroup group, JRDesignGroup jgroup) {
    log.debug("Starting groups variables layout...");
    JRDesignBand headerBand = (JRDesignBand) jgroup.getGroupHeader();
    JRDesignBand footerBand = (JRDesignBand) jgroup.getGroupFooter();

//    int headerOffset = changeHeaderBandHeightForVariables(headerBand, group);
    int headerOffset = 0;

    //Show the current value above the column name
    int yOffset = 0;
    GroupLayout layout = group.getLayout();
    //Only the value in header
    PropertyColumn column = group.getColumnToGroupBy();

    //VALUE_IN_HEADER,
    //VALUE_IN_HEADER_WITH_HEADERS,
    //VALUE_IN_HEADER_AND_FOR_EACH,
    //VALUE_IN_HEADER_AND_FOR_EACH_WITH_HEADERS
    if (layout.isShowValueInHeader() && layout.isHideColumn() && !layout.isShowColumnName()){
      //textfield for the current value
      JRDesignTextField currentValue = generateTextFieldFromColumn(column, getReport().getOptions().getDetailHeight().intValue(), group);

      //The width will be all the page
      currentValue.setWidth(getReport().getOptions().getPrintableWidth());

      //fix the height depending on the font size
      currentValue.setHeight(FontHelper.getHeightFor(column.getStyle().getFont()));
      yOffset += currentValue.getHeight();

      //Move down existing elements in the band.
      LayoutUtils.moveBandsElemnts(yOffset-1, headerBand); //Don't know why, but without the "-1" it wont show the headers

      headerBand.addElement(currentValue);
    }
    //DEFAULT and DEFAULT_WITH_HEADER
    else if (layout.isShowValueInHeader() && !layout.isHideColumn() && !layout.isShowColumnName()){
      headerOffset = changeHeaderBandHeightForVariables(headerBand, group);
      insertValueInHeader(headerBand, group, headerOffset);
    }
    //VALUE_IN_HEADER_WITH_HEADERS_AND_COLUMN_NAME
    else if (layout.isShowValueInHeader() && layout.isHideColumn() && layout.isShowColumnName()){
      //Create the element for the column name
      JRDesignTextField columnNameTf = createColumnNameTextField(group, column);
      columnNameTf.setY(columnNameTf.getY() + headerOffset);

      //textfield for the current value
      JRDesignTextField currentValue = generateTextFieldFromColumn(column, getReport().getOptions().getDetailHeight().intValue(), group);

      //The width will be (width of the page) - (column name width)
      currentValue.setWidth(getReport().getOptions().getPrintableWidth() - columnNameTf.getWidth());
      //The x position for the current value is right next to the column name
      currentValue.setX(columnNameTf.getWidth());

      //fix the height depending on the font size
      currentValue.setHeight(FontHelper.getHeightFor(column.getStyle().getFont()));
      columnNameTf.setHeight(currentValue.getHeight());

      yOffset += currentValue.getHeight();

      //Move down existing elements in the band.
      LayoutUtils.moveBandsElemnts(yOffset, headerBand);

      headerBand.addElement(columnNameTf);
      headerBand.addElement(currentValue);
    }

    placeVariableInBand(group.getHeaderVariables(), group, jgroup, DJConstants.HEADER, headerBand, headerOffset);
    placeVariableInBand(group.getFooterVariables(), group, jgroup, DJConstants.FOOTER, footerBand, 0);
  }

  protected void placeVariableInBand(List variables, DJGroup columnsGroup, JRDesignGroup jgroup, String type, JRDesignBand band, int yOffset) {
    log.debug("Placing variables in "+type+" band...");
    if ((variables != null) && (!variables.isEmpty())) {
      Iterator it = variables.iterator();
      while (it.hasNext()) {
        DJGroupVariable var = (DJGroupVariable) it.next();
        AbstractColumn col = var.getColumnToApplyOperation();

        String variableName = col.getGroupVariableName(type, columnsGroup.getColumnToGroupBy().getColumnProperty().getProperty());

        JRDesignExpression expression = new JRDesignExpression();
        JRDesignTextField textField = new JRDesignTextField();
        expression.setText("$V{" + variableName + "}");
        expression.setValueClassName(col.getVariableClassName(var.getOperation()));
        if (var.getOperation() != DJCalculation.COUNT)
          textField.setPattern(col.getPattern());

        textField.setKey(variableName);
        textField.setExpression(expression);

        if (DJConstants.FOOTER.equals(type)){
          textField.setPositionType(JRDesignElement.POSITION_TYPE_FIX_RELATIVE_TO_TOP);
        }

        textField.setX(col.getPosX().intValue());
        if (yOffset!=0)
          textField.setY(yOffset);

//        textField.setHeight(columnsGroup.getHeaderHeight().intValue());
        textField.setHeight(2 + getReport().getOptions().getDetailHeight().intValue()); //XXX be carefull with the "2+ ..."
        textField.setWidth(col.getWidth().intValue());

        textField.setEvaluationTime(JRExpression.EVALUATION_TIME_GROUP);

        textField.setEvaluationGroup(jgroup);
        //Assign the style to the element.
        //First we look for the specific element style, then the default style for the group variables
        //and finally the column style.
        Style defStyle = DJConstants.HEADER.equals(type)?columnsGroup.getDefaulHeaderVariableStyle():columnsGroup.getDefaulFooterVariableStyle();

        if (var.getStyle() != null)
          applyStyleToElement(var.getStyle(), textField);
        else if (defStyle != null)
          applyStyleToElement(defStyle, textField);
        else {
          //Last resource is tu use the column style, but a copy of it because
          //the one in the internal cache can get modified by the layout manager (like in the odd row case)
          Style style = col.getStyle();
          try {
            style = (Style) BeanUtils.cloneBean(style);
            style.setName(null); //set to null to make applyStyleToElement(...) assign a name
          } catch (Exception e) {  }
          applyStyleToElement(style, textField);
        }


        band.addElement(textField);

      }

      if (columnsGroup.getColumnToGroupBy() instanceof GlobalGroupColumn) {
        int totalWidth = 0;

        DJGroupVariable leftmostColumn = findLeftMostColumn(variables);
        totalWidth = leftmostColumn.getColumnToApplyOperation().getPosX().intValue();

        GlobalGroupColumn globalCol = (GlobalGroupColumn) columnsGroup.getColumnToGroupBy();

        JRDesignTextField globalTextField = new JRDesignTextField();
        JRDesignExpression globalExp = new JRDesignExpression();
        globalExp.setText(globalCol.getTextForExpression());
        globalExp.setValueClassName(globalCol.getValueClassNameForExpression());
        globalTextField.setExpression(globalExp);

//        globalTextField.setHeight(band.getHeight()); //XXX Changed, see if its ok
        globalTextField.setHeight(2 + getReport().getOptions().getDetailHeight().intValue()); //XXX be carefull with the "2+ ..."
        globalTextField.setWidth(totalWidth);
//        globalTextField.setX(((AbstractColumn)getReport().getColumns().get(0)).getPosX().intValue());
        globalTextField.setX(0);
        if (type.equals(ColumnsGroupVariablesRegistrationManager.HEADER))
          globalTextField.setY(yOffset);
        globalTextField.setKey("global_legend_"+type);

        applyStyleToElement(globalCol.getStyle(), globalTextField);

        band.addElement(globalTextField);
      }
    }
  }

  protected DJGroupVariable findLeftMostColumn(List variables) {
    int mostLeftX = Integer.MAX_VALUE;
    DJGroupVariable mostLeftColumn =  null;
    for (Iterator iterator = variables.iterator(); iterator.hasNext();) {
      DJGroupVariable currentCol = (DJGroupVariable) iterator.next();
      if (currentCol.getColumnToApplyOperation().getPosX().intValue() <= mostLeftX) {
        mostLeftColumn = currentCol;
                mostLeftX = mostLeftColumn.getColumnToApplyOperation().getPosX().intValue();
            }
        }
    return mostLeftColumn;
  }

  protected void insertValueInHeader(JRDesignBand headerBand, DJGroup columnsGroup, int headerOffset) {
//    JRDesignTextField textField = generateTextFieldFromColumn(columnsGroup.getColumnToGroupBy(), columnsGroup.getHeaderHeight().intValue(), columnsGroup);
    JRDesignTextField textField = generateTextFieldFromColumn(columnsGroup.getColumnToGroupBy(), getReport().getOptions().getDetailHeight().intValue(), columnsGroup);
    textField.setHorizontalAlignment(columnsGroup.getColumnToGroupBy().getStyle().getHorizontalAlign().getValue());
    textField.setStretchType(JRDesignElement.STRETCH_TYPE_NO_STRETCH); //XXX this is a patch for subreports, ensure it works well.
    textField.setY(textField.getY() + headerOffset);
    headerBand.addElement(textField);
  }

  protected int changeHeaderBandHeightForVariables(JRDesignBand headerBand, DJGroup columnsGroup) {
    int result = 0;
    if (!headerBand.getChildren().isEmpty()) {
      int acu = headerBand.getHeight();
      headerBand.setHeight(headerBand.getHeight() + columnsGroup.getHeaderHeight().intValue());
      result = acu;
    } else
      headerBand.setHeight(getReport().getOptions().getFooterHeight().intValue());
    return result;
  }

  protected void generateHeaderBand() {
    log.debug("generating header band...");
    JRDesignBand header = (JRDesignBand) getDesign().getColumnHeader();
    if (header == null) {
      header = new JRDesignBand();
      getDesign().setColumnHeader(header);
    }


    /**
     * Note: Te column names, when in header, are printed at the begining of every page.
     * You may dont want this option if you have groups that prints column names.
     */
    if (getReport().getOptions().isPrintColumnNames()){
      generateHeaderBand(header);
    }

//    if (!DynamicJasperHelper.existsGroupWithColumnNames(getReport().getColumnsGroups()))
//      generateHeaderBand(header);
  }

  protected void transformDetailBandTextField(AbstractColumn column, JRDesignTextField textField) {
    //TODO: Set default characters when null values are found.
    log.debug("transforming detail band text field...");
    DJGroup group = DynamicJasperHelper.getColumnGroup(column, getReport().getColumnsGroups());
    if (group!=null&&!group.getLayout().isShowValueForEachRow()) {
      textField.setExpression(null); //this way, the textfield is not added to the band
    }
  }

}
TOP

Related Classes of ar.com.fdvs.dj.core.layout.ClassicLayoutManager

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.