ar.com.fdvs.dj.core.layout.ClassicLayoutManager.java Source code

Java tutorial

Introduction

Here is the source code for ar.com.fdvs.dj.core.layout.ClassicLayoutManager.java

Source

/*
 * 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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

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.JRDesignElementGroup;
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.collections.CollectionUtils;
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.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.DJGroupLabel;
import ar.com.fdvs.dj.domain.DJLabel;
import ar.com.fdvs.dj.domain.DynamicJasperDesign;
import ar.com.fdvs.dj.domain.DynamicReportOptions;
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.LabelPosition;
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.PercentageColumn;
import ar.com.fdvs.dj.domain.entities.columns.PropertyColumn;
import ar.com.fdvs.dj.util.ExpressionUtils;
import ar.com.fdvs.dj.util.LayoutUtils;
import ar.com.fdvs.dj.util.Utils;

/**
 * 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)";

    protected Map referencesMap = new HashMap();

    public Map getReferencesMap() {
        return referencesMap;
    }

    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, (DynamicJasperDesign) getDesign(), this, 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, (DynamicJasperDesign) getDesign(), this, 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);
                image.setScaleImage(imageBanner.getScaleMode().getValue());

                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();
        if (getReport().isTitleIsJrExpression()) {
            exp.setText(getReport().getTitle());
        } else {
            exp.setText("\"" + Utils.escapeTextForExpression(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...");
        for (Iterator iter = getReport().getColumnsGroups().iterator(); iter.hasNext();) {
            DJGroup columnsGroup = (DJGroup) iter.next();
            JRDesignGroup jgroup = getJRGroupFromDJGroup(columnsGroup);

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

            JRDesignBand header = (JRDesignBand) jgroup.getGroupHeader();
            JRDesignBand footer = (JRDesignBand) jgroup.getGroupFooter();

            //double check to prevent NPE
            if (header == null) {
                header = new JRDesignBand();
                jgroup.setGroupHeader(header);
            }
            if (footer == null) {
                footer = new JRDesignBand();
                jgroup.setGroupFooter(footer);
            }

            header.setHeight(columnsGroup.getHeaderHeight().intValue());
            //         footer.setHeight( getFooterVariableHeight(columnsGroup));
            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);
                    if (!(prevG.getColumnToGroupBy() instanceof GlobalGroupColumn))
                        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);
                }
            }
            DJGroupLabel label = columnsGroup.getFooterLabel();
            if (label != null /*&& !footerVariables.isEmpty()*/) {
                List footerVariables = columnsGroup.getFooterVariables();
                PropertyColumn col = columnsGroup.getColumnToGroupBy();
                JRDesignBand band = (JRDesignBand) jgroup.getGroupFooter();
                int x = 0, y = 0;
                //max width
                int width = getDesign().getPageWidth() - getDesign().getLeftMargin() - getDesign().getRightMargin();
                int height = label.getHeight();
                int yOffset = 0;
                if (label.getLabelPosition() == LabelPosition.LEFT) {
                    DJGroupVariable lmvar = findLeftMostColumn(footerVariables);

                    x = col.getPosX().intValue(); //label starts in the column-to-group-by x position
                    y = findYOffsetForGroupLabel(band);
                    if (lmvar != null) {
                        AbstractColumn lmColumn = lmvar.getColumnToApplyOperation();
                        width = lmColumn.getPosX().intValue() - x;
                    } else
                        width -= x;
                    height = getFooterVariableHeight(columnsGroup);
                } else if (label.getLabelPosition() == LabelPosition.RIGHT) {
                    DJGroupVariable rmvar = findRightMostColumn(footerVariables);

                    if (rmvar != null) {
                        AbstractColumn rmColumn = rmvar.getColumnToApplyOperation();
                        x = rmColumn.getPosX().intValue() + rmColumn.getWidth().intValue();
                    } else
                        x = col.getPosX().intValue(); //label starts in the column-to-group-by x position
                    y = findYOffsetForGroupLabel(band);
                    width -= x;
                    height = getFooterVariableHeight(columnsGroup);
                } else if (label.getLabelPosition() == LabelPosition.TOP) {
                    x = col.getPosX().intValue(); //label starts in the column-to-group-by x position
                    width -= x;
                    yOffset = height;
                } else if (label.getLabelPosition() == LabelPosition.BOTTOM) {
                    x = col.getPosX().intValue(); //label starts in the column-to-group-by x position
                    y = getFooterVariableHeight(columnsGroup);
                    width -= x;
                }
                layoutGroupFooterLabels(columnsGroup, jgroup, x, y, width, height);
                layoutGroupVariables(columnsGroup, jgroup, yOffset);
            } else {
                layoutGroupVariables(columnsGroup, jgroup, 0);
            }

            layoutGroupSubreports(columnsGroup, jgroup);
            layoutGroupCrosstabs(columnsGroup, jgroup);
        }
    }

    /**
     * Creates needed textfields for general label in footer groups. 
     * @param djgroup
     * @param jgroup
     */
    protected void layoutGroupFooterLabels(DJGroup djgroup, JRDesignGroup jgroup, int x, int y, int width,
            int height) {
        //List footerVariables = djgroup.getFooterVariables();
        DJGroupLabel label = djgroup.getFooterLabel();

        //if (label == null || footerVariables.isEmpty())
        //return;

        //PropertyColumn col = djgroup.getColumnToGroupBy();
        JRDesignBand band = (JRDesignBand) jgroup.getGroupFooter();

        //      log.debug("Adding footer group label for group " + djgroup);

        /*DJGroupVariable lmvar = findLeftMostColumn(footerVariables);
        AbstractColumn lmColumn = lmvar.getColumnToApplyOperation();
        int width = lmColumn.getPosX().intValue()  - col.getPosX().intValue();
            
        int yOffset = findYOffsetForGroupLabel(band);*/

        JRDesignExpression labelExp;
        if (label.isJasperExpression()) //a text with things like "$F{myField}"
            labelExp = ExpressionUtils.createStringExpression(label.getText());
        else if (label.getLabelExpression() != null) {
            labelExp = ExpressionUtils.createExpression(jgroup.getName() + "_labelExpression",
                    label.getLabelExpression());
        } else //a simple text
            //labelExp = ExpressionUtils.createStringExpression("\""+ Utils.escapeTextForExpression(label.getText())+ "\"");      
            labelExp = ExpressionUtils.createStringExpression("\"" + label.getText() + "\"");
        JRDesignTextField labelTf = new JRDesignTextField();
        labelTf.setExpression(labelExp);
        labelTf.setWidth(width);
        labelTf.setHeight(height);
        labelTf.setX(x);
        labelTf.setY(y);
        //int yOffsetGlabel = labelTf.getHeight();            
        labelTf.setPositionType(JRDesignElement.POSITION_TYPE_FIX_RELATIVE_TO_TOP);
        applyStyleToElement(label.getStyle(), labelTf);
        band.addElement(labelTf);
    }

    /**
     * Used to ensure that the general footer label will be at the same Y position as the variables in the band.
     * @param band
     * @return
     */
    private int findYOffsetForGroupLabel(JRDesignBand band) {
        int offset = 0;
        for (Iterator iterator = band.getChildren().iterator(); iterator.hasNext();) {
            JRDesignElement elem = (JRDesignElement) iterator.next();
            if (elem.getKey() != null && elem.getKey().startsWith("variable_for_column_")) {
                offset = elem.getY();
                break;
            }
        }
        return offset;
    }

    /**
     * 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);
            DJLabel caption = djcross.getCaption();
            if (caption != null) {
                JRDesignExpression captExp = null;
                if (caption.isJasperExpression()) //a text with things like "$F{myField}"
                    captExp = ExpressionUtils.createStringExpression(caption.getText());
                else if (caption.getLabelExpression() != null) {
                    String name = "expression_for_label_at_header_of_group["
                            + getReport().getColumnsGroups().indexOf(columnsGroup) + "]_crosstab["
                            + columnsGroup.getHeaderCrosstabs().indexOf(djcross) + "]";
                    LayoutUtils.registerCustomExpressionParameter((DynamicJasperDesign) getDesign(), name,
                            caption.getLabelExpression());
                    captExp = ExpressionUtils.createExpression(
                            ExpressionUtils.createCustomExpressionInvocationText(name),
                            caption.getLabelExpression().getClassName());
                    log.debug(ExpressionUtils.createCustomExpressionInvocationText(name));
                } else //a simple text
                    captExp = ExpressionUtils
                            .createStringExpression("\"" + Utils.escapeTextForExpression(caption.getText()) + "\"");

                JRDesignTextField captTf = new JRDesignTextField();
                captTf.setExpression(captExp);
                captTf.setHeight(caption.getHeight());
                captTf.setWidth(getReport().getOptions().getPrintableWidth());
                LayoutUtils.moveBandsElemnts(caption.getHeight(), band);
                band.addElement(captTf);
            }

            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(getDesign(), 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);
                    pageBreak.setPositionType(JRDesignElement.POSITION_TYPE_FLOAT);
                    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
     * @param int labelOffset
     * @throws LayoutException
     */
    protected void layoutGroupVariables(DJGroup group, JRDesignGroup jgroup, int labelOffset) {
        log.debug("Starting groups variables layout...");

        JRDesignBand headerBand = (JRDesignBand) jgroup.getGroupHeader();
        if (headerBand == null) {
            headerBand = new JRDesignBand();
            jgroup.setGroupHeader(headerBand);
        }

        JRDesignBand footerBand = (JRDesignBand) jgroup.getGroupFooter();
        if (footerBand == null) {
            footerBand = new JRDesignBand();
            jgroup.setGroupFooter(footerBand);
        }

        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();

        Integer height = group.getHeaderVariablesHeight() != null ? group.getHeaderVariablesHeight()
                : getReport().getOptions().getDetailHeight();

        //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, height.intValue(), group);
            currentValue.setPositionType(JRDesignElement.POSITION_TYPE_FIX_RELATIVE_TO_TOP);

            //The width will be all the page, except for the width of the header variables
            int headerVariablesWidth = getReport().getOptions().getPrintableWidth();

            if (!group.getHeaderVariables().isEmpty()) {
                DJGroupVariable leftmostcol = findLeftMostColumn(group.getHeaderVariables());
                headerVariablesWidth = leftmostcol.getColumnToApplyOperation().getPosX().intValue();
                if (groupLabelsPresent(group.getHeaderVariables())) {
                    currentValue.setY(height.intValue());
                    currentValue.setHeight(getHeaderVariablesHeight(group));
                }
            }
            currentValue.setWidth(headerVariablesWidth);

            //fix the height depending on the font size
            //         currentValue.setHeight(FontHelper.getHeightFor(column.getStyle().getFont())); //XXX CAREFULL
            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

            if (group.getLayout().isPrintHeaders()) {
                headerOffset += group.getHeaderHeight().intValue()
                        + getReport().getOptions().getDetailHeight().intValue();
            }

            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, height.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
            //fixes issue 2817859
            //currentValue.setHeight(FontHelper.getHeightFor(column.getStyle().getFont()));
            if (column.getStyle() != null && column.getStyle().getFont() != null)
                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, labelOffset);
    }

    /**
     * 
     * @param groupVariables
     * @return
     */
    protected boolean groupLabelsPresent(List groupVariables) {
        for (Iterator iterator = groupVariables.iterator(); iterator.hasNext();) {
            DJGroupVariable var = (DJGroupVariable) iterator.next();
            if (var.getLabel() != null)
                return true;

        }
        return false;
    }

    /**
     * 
     * @param variables
     * @param djGroup
     * @param jgroup
     * @param type (header or footer)
     * @param band
     * @param yOffset
     */
    protected void placeVariableInBand(List variables, DJGroup djGroup, JRDesignGroup jgroup, String type,
            JRDesignBand band, int yOffset) {
        if ((variables == null) || (variables.isEmpty())) {
            return;
        }

        boolean inFooter = DJConstants.FOOTER.equals(type);

        log.debug("Placing variables in " + type + " band for group "
                + djGroup.getColumnToGroupBy().getTextForExpression());

        int height = 0;
        if (inFooter)
            height = getFooterVariableHeight(djGroup);
        else
            height = getHeaderVariablesHeight(djGroup);

        Iterator it = variables.iterator();
        int yOffsetGlabel = 0;
        while (it.hasNext()) {
            DJGroupVariable var = (DJGroupVariable) it.next();
            AbstractColumn col = var.getColumnToApplyOperation();

            //Build the expression for the variable 
            String variableName = col.getGroupVariableName(type,
                    djGroup.getColumnToGroupBy().getColumnProperty().getProperty());

            //Add the group label
            DJGroupLabel label = var.getLabel();
            JRDesignTextField labelTf = null;
            if (label != null) {
                JRDesignExpression labelExp;
                if (label.isJasperExpression()) //a text with things like "$F{myField}"
                    labelExp = ExpressionUtils.createStringExpression(label.getText());
                else if (label.getLabelExpression() != null) {
                    labelExp = ExpressionUtils.createExpression(variableName + "_labelExpression",
                            label.getLabelExpression());
                } else //a simple text
                    //labelExp = ExpressionUtils.createStringExpression("\""+ Utils.escapeTextForExpression(label.getText())+ "\"");
                    labelExp = ExpressionUtils.createStringExpression("\"" + label.getText() + "\"");
                labelTf = new JRDesignTextField();
                labelTf.setExpression(labelExp);
                labelTf.setWidth(col.getWidth().intValue());
                labelTf.setHeight(label.getHeight());
                labelTf.setX(col.getPosX().intValue());
                labelTf.setY(yOffset);
                yOffsetGlabel = labelTf.getHeight();
                if (inFooter) {
                    labelTf.setPositionType(JRDesignElement.POSITION_TYPE_FIX_RELATIVE_TO_TOP);
                }
                applyStyleToElement(label.getStyle(), labelTf);
                band.addElement(labelTf);

            }

            JRDesignExpression expression = new JRDesignExpression();
            JRDesignTextField textField = new JRDesignTextField();

            textField.setEvaluationTime(JRExpression.EVALUATION_TIME_GROUP);

            if (var.getValueExpression() != null) {
                expression = ExpressionUtils.createExpression(variableName + "_valueExpression",
                        var.getValueExpression());
            } else
                setTextAndClassToExpression(expression, var, col, variableName);

            if (var.getOperation() != DJCalculation.COUNT && var.getOperation() != DJCalculation.DISTINCT_COUNT)
                textField.setPattern(col.getPattern());

            if (col instanceof PercentageColumn) {
                PercentageColumn pcol = (PercentageColumn) col;
                expression.setText(pcol.getTextForExpression(djGroup, djGroup, type));
                expression.setValueClassName(pcol.getValueClassNameForExpression());
                textField.setEvaluationTime(JRExpression.EVALUATION_TIME_AUTO);
            } else {
                textField.setEvaluationGroup(jgroup);
            }

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

            if (inFooter) {
                textField.setPositionType(JRDesignElement.POSITION_TYPE_FIX_RELATIVE_TO_TOP);
            }

            textField.setX(col.getPosX().intValue());

            //if (yOffset!=0)
            textField.setY(yOffset + yOffsetGlabel);

            textField.setHeight(0 + height); //XXX be carefull with the "2+ ..."

            textField.setWidth(col.getWidth().intValue());

            textField.setKey("variable_for_column_" + getVisibleColumns().indexOf(col) + "_in_group_"
                    + getDesign().getGroupsList().indexOf(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) ? djGroup.getDefaulHeaderVariableStyle()
                    : djGroup.getDefaulFooterVariableStyle();

            if (var.getStyle() != null)
                applyStyleToElement(var.getStyle(), textField);
            else if (col.getStyle() != null) {
                //Last resource is to 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) style.clone();
                    style.setName(null); //set to null to make applyStyleToElement(...) assign a name
                } catch (Exception e) {
                }
                applyStyleToElement(style, textField);
            } else if (defStyle != null)
                applyStyleToElement(defStyle, textField);

            if (var.getPrintWhenExpression() != null) {
                JRDesignExpression exp = ExpressionUtils.createExpression(variableName + "_printWhenExpression",
                        var.getPrintWhenExpression());
                textField.setPrintWhenExpression(exp);
                if (labelTf != null)
                    labelTf.setPrintWhenExpression(exp);
            }

            band.addElement(textField);

        }

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

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

            GlobalGroupColumn globalCol = (GlobalGroupColumn) djGroup.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.setHeight(2 + height); //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 int getHeaderVariablesHeight(DJGroup columnsGroup) {
        Integer height;
        height = columnsGroup.getHeaderVariablesHeight() != null ? columnsGroup.getHeaderVariablesHeight()
                : DynamicReportOptions.DEFAULT_HEADER_VARIABLES_HEIGHT;
        return height.intValue();
    }

    protected int getFooterVariableHeight(DJGroup columnsGroup) {
        Integer height;
        height = columnsGroup.getFooterVariablesHeight() != null ? columnsGroup.getFooterVariablesHeight()
                : DynamicReportOptions.DEFAULT_FOOTER_VARIABLES_HEIGHT;
        return height.intValue();
    }

    /**
     * If a variable has a DJValueFormatter, we must use it in the expression, otherwise, use plain $V{...}
     * @param expression
     * @param var
     * @param col
     * @param variableName
     */
    protected void setTextAndClassToExpression(JRDesignExpression expression, DJGroupVariable var,
            AbstractColumn col, String variableName) {

        if (var.getValueFormatter() != null) {
            expression.setText(var.getTextForValueFormatterExpression(variableName));
            expression.setValueClassName(var.getValueFormatter().getClassName());
        } else if (col.getTextFormatter() != null) {

            expression.setText("$V{" + variableName + "}");
            expression.setValueClassName(col.getVariableClassName(var.getOperation()));
        } else {
            expression.setText("$V{" + variableName + "}");
            expression.setValueClassName(col.getVariableClassName(var.getOperation()));
        }
    }

    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 DJGroupVariable findRightMostColumn(List variables) {
        int mostRightX = Integer.MIN_VALUE;
        DJGroupVariable mostRightColumn = null;
        for (Iterator iterator = variables.iterator(); iterator.hasNext();) {
            DJGroupVariable currentCol = (DJGroupVariable) iterator.next();
            if (currentCol.getColumnToApplyOperation().getPosX().intValue() >= mostRightX) {
                mostRightColumn = currentCol;
                mostRightX = mostRightColumn.getColumnToApplyOperation().getPosX().intValue();
            }
        }
        return mostRightColumn;
    }

    protected void insertValueInHeader(JRDesignBand headerBand, DJGroup djgroup, int headerOffset) {
        //      JRDesignTextField textField = generateTextFieldFromColumn(columnsGroup.getColumnToGroupBy(), columnsGroup.getHeaderHeight().intValue(), columnsGroup);
        int height = getReport().getOptions().getDetailHeight().intValue();

        if (!djgroup.getHeaderVariables().isEmpty())
            height = djgroup.getHeaderVariablesHeight() != null ? djgroup.getHeaderVariablesHeight().intValue()
                    : getReport().getOptions().getDetailHeight().intValue();

        JRDesignTextField textField = generateTextFieldFromColumn(djgroup.getColumnToGroupBy(), height, djgroup);
        //fixes issue 2817859, textField has columnToGroupBy style
        //textField.setHorizontalAlignment(djgroup.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().getHeaderVariablesHeight().intValue());
        return result;
    }

    protected void generateHeaderBand() {
        log.debug("Generating main report 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 = getDJGroup(column);
        if (group != null && !group.getLayout().isShowValueForEachRow()) {
            textField.setExpression(null); //this way, the textfield is not added to the band
        }
    }

}