org.eclipse.birt.report.engine.nLayout.area.impl.PageArea.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.birt.report.engine.nLayout.area.impl.PageArea.java

Source

/***********************************************************************
 * Copyright (c) 2009 Actuate Corporation.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 * Actuate Corporation - initial API and implementation
 ***********************************************************************/

package org.eclipse.birt.report.engine.nLayout.area.impl;

import java.awt.Color;
import java.util.Iterator;
import java.util.logging.Level;

import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.report.engine.api.IPDFRenderOption;
import org.eclipse.birt.report.engine.content.IContent;
import org.eclipse.birt.report.engine.content.IPageContent;
import org.eclipse.birt.report.engine.content.IStyle;
import org.eclipse.birt.report.engine.content.impl.ReportContent;
import org.eclipse.birt.report.engine.css.engine.StyleConstants;
import org.eclipse.birt.report.engine.emitter.EmitterUtil;
import org.eclipse.birt.report.engine.executor.ExecutionContext;
import org.eclipse.birt.report.engine.ir.DimensionType;
import org.eclipse.birt.report.engine.layout.PDFConstants;
import org.eclipse.birt.report.engine.layout.pdf.emitter.LayoutEmitterAdapter;
import org.eclipse.birt.report.engine.layout.pdf.util.PropertyUtil;
import org.eclipse.birt.report.engine.nLayout.LayoutContext;
import org.eclipse.birt.report.engine.nLayout.RegionLayoutEngine;
import org.eclipse.birt.report.engine.nLayout.area.IContainerArea;
import org.eclipse.birt.report.engine.nLayout.area.style.BackgroundImageInfo;
import org.eclipse.birt.report.engine.nLayout.area.style.BorderInfo;
import org.eclipse.birt.report.engine.nLayout.area.style.BoxStyle;
import org.eclipse.birt.report.engine.util.ResourceLocatorWrapper;
import org.eclipse.birt.report.model.api.ReportDesignHandle;

import com.lowagie.text.Image;

public class PageArea extends BlockContainerArea {

    final static int DEFAULT_PAGE_WIDTH = 595275;
    final static int DEFAULT_PAGE_HEIGHT = 841889;

    private transient boolean extendToMultiplePages = false;

    private transient boolean enlargePageSize = false;

    protected ContainerArea root;
    protected ContainerArea body;
    protected RegionArea header;
    protected RegionArea footer;

    protected transient IPageContent pageContent;

    protected transient LayoutEmitterAdapter emitter;

    private transient int pageContentWidth = DEFAULT_PAGE_WIDTH;
    private transient int pageContentHeight = DEFAULT_PAGE_HEIGHT;
    private transient int rootWidth;
    private transient int rootHeight;
    private transient int rootLeft;
    private transient int rootTop;

    public PageArea(LayoutContext context, IContent content, LayoutEmitterAdapter emitter) {
        super(null, context, content);
        this.emitter = emitter;
        pageContent = (IPageContent) content;
    }

    public PageArea(PageArea area) {
        super(area);
    }

    public IContainerArea getHeader() {
        return header;
    }

    public boolean isExtendToMultiplePages() {
        return extendToMultiplePages;
    }

    public void removeHeader() {
        ((ContainerArea) root).removeChild(header);
        header = null;
    }

    public void removeFooter() {
        ((ContainerArea) root).removeChild(footer);
        footer = null;
    }

    public IContainerArea getFooter() {
        return footer;
    }

    public IContainerArea getBody() {
        return body;
    }

    public IContainerArea getRoot() {
        return root;
    }

    public void setRoot(ContainerArea root) {
        this.root = root;
        this.children.add(root);
    }

    public void setBody(ContainerArea body) {
        if (this.body != null) {
            body.setPosition(this.body.getX(), this.body.getY());
            root.children.remove(this.body);
        }
        root.children.add(body);
        body.setParent(root);
        this.body = body;
    }

    public void removeBody() {
        root.children.remove(body);
        this.body = null;
    }

    public void setHeader(RegionArea header) {
        this.header = header;
    }

    public void setFooter(RegionArea footer) {
        this.footer = footer;
    }

    public boolean isEnlargePageSize() {
        return enlargePageSize;
    }

    public void setEnlargePageSize(boolean enlargePageSize) {
        this.enlargePageSize = enlargePageSize;
    }

    public PageArea cloneArea() {
        return new PageArea(this);
    }

    // support page border on root area
    protected BoxStyle buildRootStyle() {
        IStyle style = pageContent.getStyle();
        if ((style != null) && !style.isEmpty()) {
            BoxStyle boxStyle = new BoxStyle();
            IStyle cs = pageContent.getComputedStyle();
            int borderWidth = getDimensionValue(cs.getProperty(IStyle.STYLE_BORDER_LEFT_WIDTH), width);
            if (borderWidth > 0) {
                boxStyle.setLeftBorder(new BorderInfo(cs.getProperty(IStyle.STYLE_BORDER_LEFT_COLOR),
                        cs.getProperty(IStyle.STYLE_BORDER_LEFT_STYLE), borderWidth));

            }

            borderWidth = getDimensionValue(cs.getProperty(IStyle.STYLE_BORDER_RIGHT_WIDTH), width);
            if (borderWidth > 0) {
                boxStyle.setRightBorder(new BorderInfo(cs.getProperty(IStyle.STYLE_BORDER_RIGHT_COLOR),
                        cs.getProperty(IStyle.STYLE_BORDER_RIGHT_STYLE), borderWidth));

            }
            borderWidth = getDimensionValue(cs.getProperty(IStyle.STYLE_BORDER_TOP_WIDTH), width);
            if (borderWidth > 0) {
                boxStyle.setTopBorder(new BorderInfo(cs.getProperty(IStyle.STYLE_BORDER_TOP_COLOR),
                        cs.getProperty(IStyle.STYLE_BORDER_TOP_STYLE), borderWidth));

            }

            borderWidth = getDimensionValue(cs.getProperty(IStyle.STYLE_BORDER_BOTTOM_WIDTH), width);
            if (borderWidth > 0) {
                boxStyle.setBottomBorder(new BorderInfo(cs.getProperty(IStyle.STYLE_BORDER_BOTTOM_COLOR),
                        cs.getProperty(IStyle.STYLE_BORDER_BOTTOM_STYLE), borderWidth));
            }
            return boxStyle;
        }
        return boxStyle.DEFAULT;
    }

    public void initialize() throws BirtException {
        createRoot();
        Color backgroundColor = PropertyUtil
                .getColor(pageContent.getComputedStyle().getProperty(StyleConstants.STYLE_BACKGROUND_COLOR));
        ReportDesignHandle designHandle = pageContent.getReportContent().getDesign().getReportDesign();
        IStyle style = pageContent.getStyle();

        String imageUrl = EmitterUtil.getBackgroundImageUrl(style, designHandle,
                pageContent.getReportContent().getReportContext() == null ? null
                        : pageContent.getReportContent().getReportContext().getAppContext());
        if (backgroundColor != null || imageUrl != null) {
            boxStyle = new BoxStyle();
            boxStyle.setBackgroundColor(backgroundColor);
            if (imageUrl != null) {
                boxStyle.setBackgroundImage(createBackgroundImage(imageUrl));
            }
        }
        context.setMaxHeight(root.getHeight());
        context.setMaxWidth(root.getWidth());
        context.setMaxBP(root.getHeight());
        layoutHeader();
        layoutFooter();
        updateBodySize();

        context.setMaxHeight(body.getHeight());
        context.setMaxWidth(body.getWidth());

        int overFlowType = context.getPageOverflow();
        if (overFlowType == IPDFRenderOption.FIT_TO_PAGE_SIZE
                || overFlowType == IPDFRenderOption.ENLARGE_PAGE_SIZE) {
            context.setMaxBP(Integer.MAX_VALUE);
        } else {
            context.setMaxBP(body.getHeight());
        }
        maxAvaWidth = context.getMaxWidth();
        context.resetUnresolvedRowHints();
    }

    protected BackgroundImageInfo createBackgroundImage(String url) {
        ResourceLocatorWrapper rl = null;
        ExecutionContext exeContext = ((ReportContent) content.getReportContent()).getExecutionContext();
        if (exeContext != null) {
            rl = exeContext.getResourceLocator();
        }
        IStyle cs = pageContent.getComputedStyle();
        BackgroundImageInfo backgroundImage = new BackgroundImageInfo(url,
                cs.getProperty(IStyle.STYLE_BACKGROUND_REPEAT), 0, 0, 0, 0, rl);
        Image img = backgroundImage.getImageInstance();

        IStyle style = pageContent.getStyle();
        String widthStr = style.getBackgroundWidth();
        String heightStr = style.getBackgroundHeight();

        if (img != null) {
            int resolutionX = img.getDpiX();
            int resolutionY = img.getDpiY();
            if (0 == resolutionX || 0 == resolutionY) {
                resolutionX = 96;
                resolutionY = 96;
            }
            float imageWidth = img.getPlainWidth() / resolutionX * 72 * PDFConstants.LAYOUT_TO_PDF_RATIO;
            float imageHeight = img.getPlainHeight() / resolutionY * 72 * PDFConstants.LAYOUT_TO_PDF_RATIO;
            int actualWidth = (int) imageWidth;
            int actualHeight = (int) imageHeight;

            if (widthStr != null && widthStr.length() > 0 || heightStr != null && heightStr.length() > 0) {
                if ("contain".equals(widthStr) || "contain".equals(heightStr)) {
                    float rh = imageHeight / height;
                    float rw = imageWidth / width;
                    if (rh > rw) {
                        actualHeight = height;
                        actualWidth = (int) (imageWidth * height / imageHeight);
                    } else {
                        actualWidth = width;
                        actualHeight = (int) (imageHeight * width / imageWidth);
                    }

                } else if ("cover".equals(widthStr) || "cover".equals(heightStr)) {
                    float rh = imageHeight / height;
                    float rw = imageWidth / width;
                    if (rh > rw) {
                        actualWidth = width;
                        actualHeight = (int) (imageHeight * width / imageWidth);
                    } else {
                        actualHeight = height;
                        actualWidth = (int) (imageWidth * height / imageHeight);
                    }
                } else {
                    DimensionType widthDim = DimensionType.parserUnit(widthStr);
                    DimensionType heightDim = DimensionType.parserUnit(heightStr);
                    if (widthDim != null) {
                        actualWidth = PropertyUtil.getDimensionValue(content, widthDim);
                        if (heightDim == null) {
                            actualHeight = (int) (imageHeight * actualWidth / imageWidth);
                        } else {
                            actualHeight = PropertyUtil.getDimensionValue(content, heightDim);
                        }
                    } else if (heightDim != null) {
                        actualHeight = PropertyUtil.getDimensionValue(content, heightDim);
                        if (widthDim == null) {
                            actualWidth = (int) (imageWidth * actualHeight / imageHeight);
                        } else {
                            actualWidth = PropertyUtil.getDimensionValue(content, widthDim);
                        }
                    } else {
                        actualHeight = (int) imageHeight;
                        actualWidth = (int) imageWidth;
                    }
                }
            }

            backgroundImage.setXOffset(
                    getDimensionValue(cs.getProperty(IStyle.STYLE_BACKGROUND_POSITION_X), width - actualWidth));
            backgroundImage.setYOffset(
                    getDimensionValue(cs.getProperty(IStyle.STYLE_BACKGROUND_POSITION_Y), height - actualHeight));
            backgroundImage.setHeight(actualHeight);
            backgroundImage.setWidth(actualWidth);
            return backgroundImage;
        }
        return null;
    }

    /**
     * support body auto resize, remove invalid header and footer
     * 
     * @param page
     */
    protected void updateBodySize() {
        if (header != null && header.getHeight() >= root.getHeight()) {
            removeHeader();
            header = null;
        }
        if (footer != null && footer.getHeight() >= root.getHeight()) {
            removeFooter();
            footer = null;
        }
        if (header != null && footer != null && footer.getHeight() + header.getHeight() >= root.getHeight()) {
            removeHeader();
        }

        body.setHeight(root.getContentHeight() - (header == null ? 0 : header.getHeight())
                - (footer == null ? 0 : footer.getHeight()));
        body.setPosition(body.getX(),
                (header == null ? 0 : header.getHeight()) + root.getBoxStyle().getTopBorderWidth());
        if (footer != null) {
            footer.setPosition(footer.getX(), (header == null ? 0 : header.getHeight())
                    + root.getBoxStyle().getTopBorderWidth() + (body == null ? 0 : body.getHeight()));
        }
    }

    /**
     * layout page header area
     * 
     */
    protected void layoutHeader() {
        IContent headerContent = pageContent.getPageHeader();
        if (headerContent != null) {
            DimensionType h = pageContent.getHeaderHeight();
            if (h == null) {
                h = new DimensionType(0.5f, DimensionType.UNITS_IN);
            }
            headerContent.setHeight(h);
            header.content = headerContent;
            boolean autoPageBreak = context.isAutoPageBreak();
            context.setAutoPageBreak(false);
            RegionLayoutEngine rle = new RegionLayoutEngine(header, context);

            try {
                rle.layout(headerContent);
            } catch (BirtException e) {
                logger.log(Level.WARNING, e.getMessage(), e);
            }
            context.setAutoPageBreak(autoPageBreak);

        }
    }

    /**
     * layout page footer area
     * 
     */
    protected void layoutFooter() {
        IContent footerContent = pageContent.getPageFooter();
        if (footerContent != null) {
            DimensionType h = pageContent.getFooterHeight();
            if (h == null) {
                h = new DimensionType(0.5f, DimensionType.UNITS_IN);
            }
            footerContent.setHeight(h);
            footer.content = footerContent;
            boolean autoPageBreak = context.isAutoPageBreak();
            context.setAutoPageBreak(false);
            RegionLayoutEngine rle = new RegionLayoutEngine(footer, context);
            try {
                rle.layout(footerContent);
            } catch (BirtException e) {
                logger.log(Level.WARNING, e.getMessage(), e);
            }
            context.setAutoPageBreak(autoPageBreak);
        }
    }

    public void floatingFooter(PageArea page) {
        ContainerArea footer = (ContainerArea) page.getFooter();
        IContainerArea body = page.getBody();
        IContainerArea header = page.getHeader();
        if (footer != null) {
            footer.setPosition(footer.getX(),
                    (header == null ? 0 : header.getHeight()) + (body == null ? 0 : body.getHeight()));
        }
    }

    protected void createRoot() {
        int overFlowType = context.getPageOverflow();

        if (overFlowType == IPDFRenderOption.OUTPUT_TO_MULTIPLE_PAGES) {
            // page.setExtendToMultiplePages( true );
        }

        pageContentWidth = getDimensionValue(pageContent, pageContent.getPageWidth())
                - boxStyle.getLeftBorderWidth() - boxStyle.getRightBorderWidth();
        pageContentHeight = getDimensionValue(pageContent, pageContent.getPageHeight())
                - boxStyle.getTopBorderWidth() - boxStyle.getBottomBorderWidth();

        // validate page width
        if (pageContentWidth <= 0) {
            pageContentWidth = DEFAULT_PAGE_WIDTH;
        }

        // validate page height
        if (pageContentHeight <= 0) {
            pageContentHeight = DEFAULT_PAGE_HEIGHT;
        }

        setWidth(pageContentWidth);
        setHeight(pageContentHeight);

        /**
         * set position and dimension for root
         */
        ContainerArea pageRoot = new BlockContainerArea();
        BoxStyle boxStyle = buildRootStyle();
        if (boxStyle != BoxStyle.DEFAULT) {
            pageRoot.hasStyle = true;
        }
        pageRoot.setBoxStyle(boxStyle);
        rootLeft = getDimensionValue(pageContent, pageContent.getMarginLeft(), pageContentWidth);
        rootTop = getDimensionValue(pageContent, pageContent.getMarginTop(), pageContentHeight);
        rootLeft = Math.max(0, rootLeft);
        rootLeft = Math.min(pageContentWidth, rootLeft);
        rootTop = Math.max(0, rootTop);
        rootTop = Math.min(pageContentHeight, rootTop);
        pageRoot.setPosition(rootLeft, rootTop);
        int rootRight = getDimensionValue(pageContent, pageContent.getMarginRight(), pageContentWidth);
        int rootBottom = getDimensionValue(pageContent, pageContent.getMarginBottom(), pageContentWidth);
        rootRight = Math.max(0, rootRight);
        rootBottom = Math.max(0, rootBottom);
        if (rootLeft + rootRight > pageContentWidth) {
            rootRight = 0;
        }
        if (rootTop + rootBottom > pageContentHeight) {
            rootBottom = 0;
        }

        rootWidth = pageContentWidth - rootLeft - rootRight;
        rootHeight = pageContentHeight - rootTop - rootBottom;
        pageRoot.setWidth(rootWidth);
        pageRoot.setHeight(rootHeight);
        setRoot(pageRoot);
        pageRoot.setParent(this);

        /**
         * set position and dimension for header
         */
        int headerHeight = getDimensionValue(pageContent, pageContent.getHeaderHeight(), pageRoot.getHeight());
        int headerWidth = pageRoot.getWidth() - boxStyle.getLeftBorderWidth() - boxStyle.getRightBorderWidth();
        headerHeight = Math.max(0, headerHeight);
        headerHeight = Math.min(pageRoot.getHeight(), headerHeight);
        RegionArea header = new RegionArea();
        header.setHeight(headerHeight);
        header.setWidth(headerWidth);
        header.context = context;
        header.needClip = true;
        header.setPosition(boxStyle.getLeftBorderWidth(), boxStyle.getTopBorderWidth());
        pageRoot.addChild(header);
        setHeader(header);
        header.setParent(pageRoot);

        /**
         * set position and dimension for footer
         */
        int footerHeight = getDimensionValue(pageContent, pageContent.getFooterHeight(), pageRoot.getHeight());
        int footerWidth = pageRoot.getWidth() - boxStyle.getLeftBorderWidth() - boxStyle.getRightBorderWidth();
        footerHeight = Math.max(0, footerHeight);
        footerHeight = Math.min(pageRoot.getHeight() - headerHeight, footerHeight);
        RegionArea footer = new RegionArea();
        footer.setHeight(footerHeight);
        footer.setWidth(footerWidth);
        footer.context = context;
        footer.needClip = true;
        footer.setPosition(boxStyle.getLeftBorderWidth(),
                pageRoot.getHeight() - boxStyle.getBottomBorderWidth() - footerHeight);
        pageRoot.addChild(footer);
        setFooter(footer);
        footer.setParent(pageRoot);

        /**
         * set position and dimension for body
         */
        ContainerArea body = new BlockContainerArea();
        int bodyLeft = getDimensionValue(pageContent, pageContent.getLeftWidth(), pageRoot.getWidth());
        bodyLeft = Math.max(0, bodyLeft);
        bodyLeft = Math.min(pageRoot.getWidth(), bodyLeft);
        body.setPosition(boxStyle.getLeftBorderWidth() + bodyLeft, headerHeight + boxStyle.getRightBorderWidth());
        int bodyRight = getDimensionValue(pageContent, pageContent.getRightWidth(), pageRoot.getWidth());
        bodyRight = Math.max(0, bodyRight);
        bodyRight = Math.min(pageRoot.getWidth() - bodyLeft, bodyRight);

        body.setWidth(pageRoot.getWidth() - bodyLeft - bodyRight - boxStyle.getLeftBorderWidth()
                - boxStyle.getRightBorderWidth());
        body.setHeight(pageRoot.getHeight() - headerHeight - footerHeight - boxStyle.getTopBorderWidth()
                - boxStyle.getBottomBorderWidth());
        setBody(body);
        if (overFlowType == IPDFRenderOption.CLIP_CONTENT
                || overFlowType == IPDFRenderOption.OUTPUT_TO_MULTIPLE_PAGES) {
            pageRoot.setNeedClip(true);
            body.setNeedClip(true);
        } else {
            pageRoot.setNeedClip(false);
        }
        // TODO add left area and right area;
    }

    public void close() throws BirtException {
        int overFlowType = context.getPageOverflow();
        if (overFlowType == IPDFRenderOption.FIT_TO_PAGE_SIZE) {
            float scale = calculatePageScale(this);
            if (1f == scale) {
                pageContent.setExtension(IContent.LAYOUT_EXTENSION, this);
                outputPage(pageContent);
                return;
            }
            this.setScale(scale);
            getBody().setNeedClip(false);
            updatePageDimension(scale, this);
        } else if (overFlowType == IPDFRenderOption.ENLARGE_PAGE_SIZE) {
            getBody().setNeedClip(false);
            updatePageDimension(this);
        }

        pageContent.setExtension(IContent.LAYOUT_EXTENSION, this);
        outputPage(pageContent);
        finished = true;
    }

    public boolean isPageEmpty() {
        if (body.getChildrenCount() > 0) {
            return false;
        }
        return true;
    }

    public void outputPage(IPageContent page) throws BirtException {
        FixedLayoutPageHintGenerator gen = context.getPageHintGenerator();
        if (null != gen) {
            gen.generatePageHints(page);
        }
        emitter.outputPage(page);
        // context.pageNumber++;
    }

    private float calculatePageScale(PageArea page) {
        float scale = 1.0f;
        if (page != null && page.getRoot().getChildrenCount() > 0) {
            int maxWidth = context.getMaxWidth();
            int maxHeight = context.getMaxHeight();
            int prefWidth = context.getPreferenceWidth();
            int prefHeight = body.getHeight();
            Iterator iter = page.getBody().getChildren();
            while (iter.hasNext()) {
                AbstractArea area = (AbstractArea) iter.next();
                prefWidth = Math.max(prefWidth, area.getAllocatedX() + area.getAllocatedWidth());
            }

            if (prefHeight > maxHeight) {
                ((ContainerArea) page.getBody()).setHeight(prefHeight);
                floatingFooter(page);
            }

            if (prefWidth > maxWidth || prefHeight > maxHeight) {
                scale = Math.min(maxWidth / (float) prefWidth, maxHeight / (float) prefHeight);
            }
        }
        return scale;
    }

    protected void updatePageDimension(float scale, PageArea page) {
        // 0 < scale <= 1
        page.setHeight((int) (pageContentHeight / scale));
        page.setWidth((int) (pageContentWidth / scale));
        ContainerArea pageRoot = (ContainerArea) page.getRoot();
        pageRoot.setPosition((int) (rootLeft / scale), (int) (rootTop / scale));
        pageRoot.setHeight((int) (rootHeight / scale));
        pageRoot.setWidth((int) (rootWidth / scale));
    }

    protected void updatePageDimension(PageArea page) {
        if (page != null && page.getRoot().getChildrenCount() > 0) {
            int maxWidth = context.getMaxWidth();
            int maxHeight = context.getMaxHeight();
            int prefWidth = context.getPreferenceWidth(); // 0
            int prefHeight = page.getBody().getHeight();
            Iterator iter = page.getBody().getChildren();
            while (iter.hasNext()) {
                AbstractArea area = (AbstractArea) iter.next();
                prefWidth = Math.max(prefWidth, area.getAllocatedX() + area.getAllocatedWidth());
            }

            if (prefHeight > maxHeight) {
                ((ContainerArea) page.getBody()).setHeight(prefHeight);
                floatingFooter(page);
                int deltaHeight = prefHeight - maxHeight;
                ContainerArea pageRoot = (ContainerArea) page.getRoot();
                pageRoot.setHeight(pageRoot.getHeight() + deltaHeight);
                page.setHeight(pageContentHeight + deltaHeight);
            }

            if (prefWidth > maxWidth) {
                ((ContainerArea) page.getBody()).setWidth(prefWidth);
                int deltaWidth = prefWidth - maxWidth;
                ContainerArea pageRoot = (ContainerArea) page.getRoot();
                pageRoot.setWidth(pageRoot.getWidth() + deltaWidth);
                page.setWidth(pageContentWidth + deltaWidth);
            }
        }

    }

}