Skip to content

Commit

Permalink
Added ability to fill a vertically-filled page with blank data rows.
Browse files Browse the repository at this point in the history
  • Loading branch information
TDHewson authored and ADI-SG\hewsont committed Apr 5, 2019
1 parent 357cdf1 commit 6f07ad1
Show file tree
Hide file tree
Showing 8 changed files with 1,834 additions and 1 deletion.
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;
}
}
}
Loading

0 comments on commit 6f07ad1

Please sign in to comment.