Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to fill a vertically-filled page with blank data rows. #55

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ public interface JRParameter extends JRPropertiesHolder, JRCloneable
*/
public static final String REPORT_FORMAT_FACTORY = "REPORT_FORMAT_FACTORY";

/**
* An option allowing the remainder of a vertically-filled report's detail section to be filled with blank rows of
* data when the main data set is exhausted.
*/
public static final String REPORT_FILL_DETAIL_WITH_BLANK_ROWS = "REPORT_FILL_DETAIL_WITH_BLANK_ROWS";

/**
* This built-in flag parameter specifies whether to ignore pagination.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1194,6 +1194,13 @@ protected boolean next() throws JRException
return mainDataset.next();
}

/**
* @return whether elements should evaluate as blank
*/
protected boolean evaluateElementToBlank() {
return false;
}

/**
* Resolves elements which are to be evaluated at report level.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,9 @@ protected boolean delayedEvaluationUpdatesTemplate()
*/
public final Object evaluateExpression(JRExpression expression, byte evaluation) throws JRException
{
if (filler.evaluateElementToBlank()) {
return null;
}
return expressionEvaluator.evaluate(expression, evaluation);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,18 @@
*/
package net.sf.jasperreports.engine.fill;

import java.util.Map;

import org.apache.commons.javaflow.api.continuable;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRGroup;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JRRuntimeException;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.engine.type.FooterPositionEnum;
Expand All @@ -47,6 +51,16 @@ public class JRVerticalFiller extends JRBaseFiller

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

// Whether we are configured to fill the detail section with blank rows of data.
// Is configured to not fill by default.
private boolean fillDetailWithBlankRows = false;

// Flag to indicate whether we've reached the end of our main data set.
private boolean isEndOfMainDataset = false;

// Flag to indicate when we're writing the detail section.
private boolean writingDetailSection = false;

/**
*
*/
Expand Down Expand Up @@ -81,6 +95,26 @@ public JRVerticalFiller(
setPageHeight(pageHeight);
}

@Override
protected void setParameters(Map<String, Object> parameterValues) throws JRException
{
super.setParameters(parameterValues);

setFillDetailWithBlankRows(parameterValues);
}

protected void setFillDetailWithBlankRows(Map<String,Object> parameterValues)
{
Object value = parameterValues.getOrDefault(JRParameter.REPORT_FILL_DETAIL_WITH_BLANK_ROWS, Boolean.FALSE);
if (value instanceof String)
{
fillDetailWithBlankRows = Boolean.parseBoolean((String)value);
} else if (value instanceof Boolean)
{
fillDetailWithBlankRows = ((Boolean)value).booleanValue();
}
}


@Override
protected void setPageHeight(int pageHeight)
Expand All @@ -98,6 +132,15 @@ protected void setPageHeight(int pageHeight)
}
}

/**
* {@inheritDoc}
*/
@Override
public JasperPrint fill(Map<String, Object> parameterValues) throws JRException
{
isEndOfMainDataset = false;
return super.fill(parameterValues);
}

@Override
@continuable
Expand Down Expand Up @@ -231,7 +274,42 @@ protected synchronized void fillReport() throws JRException
}
}

/**
* {@inheritDoc}
*/
@Override
protected boolean next() throws JRException {
if (super.next()) {
return true;
}
if (fillDetailWithBlankRows) {
// If we have no more data in our main data set and we are configured to fill will blank rows,
// move the cursor forward until we have reached the end of the current page's detail section.
isEndOfMainDataset = true;
return !endOfPageDetail();
}
return false;
}

private boolean endOfPageDetail() {
JRFillBand[] detailBands = detailSection.getFillBands();
for (int i = 0; i < detailBands.length; i++) {
JRFillBand detailBand = detailBands[i];
if (detailBand.isToPrint() && (detailBand.getBreakHeight() > columnFooterOffsetY - offsetY)) {
return true;
}
}
return false;
}

/**
* {@inheritDoc}
*/
@Override
protected boolean evaluateElementToBlank() {
return isEndOfMainDataset && writingDetailSection;
}

/**
*
*/
Expand Down Expand Up @@ -752,6 +830,8 @@ private void fillGroupHeaderReprint(JRFillGroup group, byte evaluation) throws J
@continuable
private void fillDetail() throws JRException
{
writingDetailSection = true;

if (log.isDebugEnabled() && !detailSection.isEmpty())
{
log.debug("Fill " + fillerId + ": detail at " + offsetY);
Expand Down Expand Up @@ -851,6 +931,7 @@ private void fillDetail() throws JRException

isNewPage = false;
isNewColumn = false;
writingDetailSection = false;
}


Expand Down
22 changes: 21 additions & 1 deletion jasperreports/tests/net/sf/jasperreports/AbstractTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.testng.annotations.BeforeClass;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
Expand Down Expand Up @@ -103,16 +105,26 @@ protected void runReport(String jrxmlFileName, String referenceFileNamePrefix)
HashMap<String, Object> params = new HashMap<String, Object>();
params.put(JRParameter.REPORT_LOCALE, Locale.US);
params.put(JRParameter.REPORT_TIME_ZONE, TimeZone.getTimeZone("GMT"));
params.putAll(additionalReportParams());
params.put(TEST, this);

JRDataSource dataSource = createDataSource();

log.debug("Running report " + jrxmlFileName);

try
{
JasperReport report = compileReport(jrxmlFileName);
if (report != null)
{
JasperPrint print = fillManager.fill(report, params);
JasperPrint print;
if (dataSource == null)
{
print = fillManager.fill(report, params);
} else
{
print = fillManager.fill(report, params, dataSource);
}

assert !print.getPages().isEmpty();

Expand Down Expand Up @@ -154,6 +166,14 @@ protected void runReport(String jrxmlFileName, String referenceFileNamePrefix)
}
}

protected Map<String, Object> additionalReportParams() {
return new HashMap<>();
}

protected JRDataSource createDataSource() {
return null;
}

protected JasperReportsContext getJasperReportsContext()
{
return jasperReportsContext;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* JasperReports - Free Java Reporting Library.
* Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
* http://www.jaspersoft.com
*
* Unless you have purchased a commercial license agreement from Jaspersoft,
* the following license terms apply:
*
* This program is part of JasperReports.
*
* JasperReports 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 3 of the License, or
* (at your option) any later version.
*
* JasperReports 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 JasperReports. If not, see <http://www.gnu.org/licenses/>.
*/
package net.sf.jasperreports.bands.fill;

import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import net.sf.jasperreports.AbstractTest;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.data.JRBeanArrayDataSource;

/** @author Tim Hewson */
public class BandFillTest extends AbstractTest
{

@Override
protected Map<String, Object> additionalReportParams()
{
Map<String, Object> params = new HashMap<String, Object>();
params.put(JRParameter.REPORT_FILL_DETAIL_WITH_BLANK_ROWS, Boolean.TRUE);
return params;
}


@Override
protected JRDataSource createDataSource()
{
return new JRBeanArrayDataSource(
IntStream.range(0, 90)
.mapToObj(i -> new Ascii(33 + i, String.valueOf((char) (33 + i))))
.toArray());
}

@Test(dataProvider = "testArgs")
public void testReport(String jrxmlFileName, String referenceFileNamePrefix)
throws JRException, NoSuchAlgorithmException, IOException
{
runReport(jrxmlFileName, referenceFileNamePrefix);
}

@DataProvider
public Object[][] testArgs()
{
return runReportArgs("net/sf/jasperreports/bands/fill/repo", "BandFillReport", 40);
}

public static class Ascii
{
long record_num;
String record_val;

Ascii(long number, String value) {
this.record_num = number;
this.record_val = value;
}

public long getRecord_num() {
return record_num;
}

public String getRecord_val() {
return record_val;
}
}
}