/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package cli_fmw.report.implemenatation;
import cli_fmw.report.ReportPreferences;
import cli_fmw.report.AlignmentType;
import cli_fmw.report.ExtraField;
import cli_fmw.report.PageOptions;
import cli_fmw.report.TableReportOptions;
import cli_fmw.report.ReporterFactory;
import java.awt.Color;
import java.awt.Font;
import java.awt.font.FontRenderContext;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.table.TableModel;
import net.sf.jasperreports.engine.JRDefaultStyleProvider;
import net.sf.jasperreports.engine.JRElement;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExpression;
import net.sf.jasperreports.engine.JRLineBox;
import net.sf.jasperreports.engine.JRStyle;
import net.sf.jasperreports.engine.JRStyleContainer;
import net.sf.jasperreports.engine.JRTextElement;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.base.JRBaseFont;
import net.sf.jasperreports.engine.design.JRDesignBand;
import net.sf.jasperreports.engine.design.JRDesignExpression;
import net.sf.jasperreports.engine.design.JRDesignFrame;
import net.sf.jasperreports.engine.design.JRDesignParameter;
import net.sf.jasperreports.engine.design.JRDesignStyle;
import net.sf.jasperreports.engine.design.JRDesignTextField;
import net.sf.jasperreports.engine.design.JasperDesign;
import net.sf.jasperreports.engine.export.TextRenderer;
import net.sf.jasperreports.engine.util.JRFontUtil;
/**
* Клас отвечает за динамическую генерацию отчета.
*
* краткая справка по терминам:
* Параметр отчета 1) - В jasper report пред использование внешнего параметра, его надо описать,
* описание включает в себя тип параметра (Имя его класса), и его имя.
* При автогенерации тип всегда String
* Параметр отчета 2) - обект типа Map.Entry, состоит из имени параметра, его ключа
* (типа java.lang.String), и собственно занчения. Обработка занчений приметивна,
* и сводится к приведению их к строке с помощью функции ReporterFactory.convertDataToString.
* За исключением случаев когда в качестве обьекта передается ExtraFields
* Поле отчета - обект всавленный в отчет для отображения содержимого параметра.
* Тексьовое поле - СМ Поле отчета.
* Поле данных - В jasper report прараметры каждого повторяющегося элемента отчета,
* должны быть предворитльно описаны, описание называются поле.
* Элемент - одна ячейка таблицы.
* @author finder
*/
public class JasperReportBuilder implements JasperBuilder{
public static String AUTO_GENERATED_PROPERTY = "infotech.is_autogenerated";
/**
* Строка которая будет напечатанна в заголовке отчета.
*/
String title;
/**
* Общие опции генерации отчета
*/
PageOptions options;
/**
* список дополнительны полей которые будут размещенны сверху отчета.
* элементы типа ExtraFields будут обработтаны отдельно, для преврощение всех
* остальных в строку будет вызванна ReporterFactory.convertDataToString
*/
Collection<Map.Entry<String, Object>>topExtraFields;
/**
* список дополнительны полей которые будут размещенны снизу отчета.
*/
Collection<Map.Entry<String, Object>>bottomExtraFields;
/**
* Ссылка на итерфейс изменяющий геренацию отчета, для коррекции внешнего вида,
* в процессе построения шаблона отчета, этот интерфейс прифодится к его наследжникам,
* и вызываются соотведствующие методы обработки.
*/
JasperReportBuilderCustomizer customizer;
/**
* Шаблон создаваемого в данный момент отчета.
*/
JasperDesign targetDesting;
/**
* Обычный слиль отчета, им например ресуются поля.
* Все остальные слили базируются на обычном
*/
JRDesignStyle normalStyle;
/**
* Стиль которым ресуетс заголовок отчета. Обычный + увеличенный в двое размер шрифта.
*/
JRDesignStyle headerStyle;
/**
* Банд содержит элементы заголовка отчета. (Строку заголовка, и вегхние поля)
* При добавлении элементов они начинаю добовлятся начиная с позиции равной
* высоте банда, после добавлении банд растягивается чтобы вместить новые элементы.
*/
JRDesignBand reportHeaderBand;
/**
* Банд содержит заголовок таблицы высота как у элемента таблицы
*/
JRDesignBand colomnHeaderBand;
/**
* Банд с элементами таблицы
*/
JRDesignBand detalsBand;
/**
* Банд находящий внизу последней страницы отчета, содержит
*/
JRDesignBand reportFooterBand;
/**
* Шрифт максимально близкий к шрифту слитиля Normal
*/
Font normalJavaFont;
/**
* Данне контекста шрифта которым будет рейдится отчет
*/
FontRenderContext frontRenderContext = TextRenderer.LINE_BREAK_FONT_RENDER_CONTEXT;
JasperDetailBuilder builder;
/**
* Ширина отчета в логических пикселях
*/
int destingWidth;
/**
* Основной конструктор, созает построитель отчета. Для каждого набора данных нужно создать свой построитель.
* Все параметры могут быть null
* @param title - Строка которая будет напечатанна в заголовке отчета
* @param options - Общие опции генерации отчета
* @param topExtraFields - список дополнительны полей которые будут размещенны сверху отчета.
* элементы типа ExtraFields будут обработтаны отдельно, для преврощение всех
* остальных в строку будет вызванна ReporterFactory.convertDataToString
* @param bottomExtraFields - элеметы которые будут напечатанны снизу отчета
* @param table - ссылка на модель таблицы, если отчет содержит таблицу
*/
public JasperReportBuilder(String title, PageOptions options, Collection<Entry<String, Object>> topExtraFields, Collection<Entry<String, Object>> bottomExtraFields, JasperDetailBuilder builder) {
this.title = title;
if (options == null) {
throw new IllegalArgumentException("options cannot be null");
}
this.options = options;
this.topExtraFields = topExtraFields;
this.bottomExtraFields = bottomExtraFields;
this.builder = builder;
}
/**
* Строит шаблоннон отчета, на на основе пустого наблона, и переданных в конструктор данных.
* @return свежепостроеный отчет.
* @throws net.sf.jasperreports.engine.JRException - если построение отчета навернулось изза невалидных данны,
* нефатально, но генератор после в невалидном состоянии.
*/
public JasperReport buildReport() throws JRException{
initDesting();
double pos = 0;
if (reportHeaderBand != null) {
pos = reportHeaderBand.getHeight();
}
if (title != null) {
pos = createTitle(pos, reportHeaderBand, title);
}
if (topExtraFields != null) {
pos = createReportFields(pos, reportHeaderBand, topExtraFields);
}
if (reportHeaderBand != null) {
reportHeaderBand.setHeight((int) Math.round(pos));
}
if (builder != null) {
builder.buildDetails(this, customizer);
}
if (reportFooterBand != null) {
pos = reportFooterBand.getHeight();
}
if (bottomExtraFields != null) {
pos = createReportFields(pos, reportFooterBand, bottomExtraFields);
}
if (reportFooterBand != null) {
reportFooterBand.setHeight((int) Math.round(pos));
}
//JRXmlWriter.writeReport(targetDesting, "/home/vip/test.jrxml", "UTF-8");
return JasperCompileManager.compileReport(targetDesting);
}
/**
* Устанавливает кастомизатор для генератора, кастомизатор работает как обработчик раличных событитй,
* меняет процес построениея шаблона отчета.
* @param costomizer - интерфейс класса меняющего построение отчета.
* В случае если класс наследует любой из потомков
* JasperReportBuilderCustomizer то в процессе построения отчета
* интерфейс будет автоматичеки приведен к этому потомку
* и вызванна соотведствующия функция обработчик.
*/
public void applyCostumizer(JasperReportBuilderCustomizer costomizer){
this.customizer = costomizer;
costomizer.customizerBuilder(this);
}
/**
* Возвращает ширину отчета в логических пикселях
* @return
*/
@Override
public int getDestingWidth() {
return destingWidth;
}
/**
* Взвращает длинну линии, отпечатонной стилем Normal.
* @param line
* @return
*/
double getLineLength(String line){
return normalJavaFont.getStringBounds(line, frontRenderContext).getWidth();
}
/**
* Взвращает длинну строки, отпечатонной стилем Normal.
* @param line
* @return
*/
@Override
public double getStringLength(String str){
double target = 0;
int lastPos = 0;
do{
int newPos = str.indexOf('\n', lastPos);
if (newPos < 0) {
newPos = str.length();
}
String line = str.substring(lastPos, newPos);
target = Math.max(target, getLineLength(line));
lastPos = newPos + 1;
}
while (lastPos < str.length());
return target;
}
/**
* Возаращает высоту поля вмещающего одну строку текста.
* @return
*/
@Override
public double getFieldHeigth(){
double target = normalJavaFont.getMaxCharBounds(frontRenderContext).getHeight();
JRLineBox box = normalStyle.getLineBox();
target += box.getTopPadding();
target += box.getBottomPadding();
target += box.getTopPen().getLineWidth();
return (int) Math.round(target);
}
/**
* Возврашает минимальный размер поля по горизонтали, который
* вмещает в себя эту строку без переносов.
* @param line
* @return
*/
@Override
public double getFieldLenght(String line){
double target = getStringLength(line);
JRLineBox box = normalStyle.getLineBox();
target += box.getLeftPadding();
target += box.getRightPadding();
target += box.getLeftPen().getLineWidth();
target += 1;
return target;
}
/**
* Возвращает высоту заголовка отчета.
* @return
*/
int getHeaderHeight(){
return (int)Math.round(getFieldHeigth() + 3);
}
@Override
public JRDesignBand getColomnHeaderBand() {
if (colomnHeaderBand == null){
colomnHeaderBand = new JRDesignBand();
getTargetDesting().setColumnHeader(colomnHeaderBand);
}
return colomnHeaderBand;
}
@Override
public JRDesignBand getDetalsBand() {
if (detalsBand == null){
detalsBand = new JRDesignBand();
getTargetDesting().setDetail(detalsBand);
}
return detalsBand;
}
@Override
public JRDesignStyle getNormalStyle() {
return normalStyle;
}
@Override
public JasperDesign getTargetDesting() {
return targetDesting;
}
/**
* Создает новый пустой шаблон отчета, также инициализирует ему все стили,
* банды, и тп.
* @throws net.sf.jasperreports.engine.JRException
*/
void initDesting() throws JRException{
targetDesting = new JasperDesign();
targetDesting.setWhenNoDataType(JasperDesign.WHEN_NO_DATA_TYPE_ALL_SECTIONS_NO_DETAIL);
targetDesting.setName("Auto Generated Report");
targetDesting.setProperty(AUTO_GENERATED_PROPERTY, Boolean.toString(true));
initStyles();
initBands();
initDestingSizes();
}
/**
* Инициализирует размеры отчета в соотведствии с текущими параметрами отчета (preferences)
*/
void initDestingSizes(){
if (options.getOrentation() == TableReportOptions.PageOrentation.vertical){
targetDesting.setOrientation(JasperDesign.ORIENTATION_PORTRAIT);
}
else if (options.getOrentation() == TableReportOptions.PageOrentation.horizontal){
targetDesting.setOrientation(JasperDesign.ORIENTATION_LANDSCAPE);
}
else {
throw new IllegalArgumentException("PageOptions.getOrentation() has uncnown value");
}
targetDesting.setPageHeight(options.reportHeight);
targetDesting.setPageWidth(options.reportWidht);
targetDesting.setTopMargin(options.topMargin);
targetDesting.setBottomMargin(options.bottomMargin);
targetDesting.setLeftMargin(options.leftMargin);
targetDesting.setRightMargin(options.rightMargin);
// Устанавливаю переменную класса с размером отчета
destingWidth = targetDesting.getPageWidth()
- targetDesting.getLeftMargin()
- targetDesting.getRightMargin();
targetDesting.setColumnWidth(destingWidth);
targetDesting.setColumnSpacing(0);
targetDesting.setPrintOrder(JasperDesign.PRINT_ORDER_VERTICAL);
}
/**
* инициализирует все стили отчета, также создает в соодтведствии со стилем Normal
* стандартный Java шриф, c помощью которого вычесляются размеры строк
* @throws net.sf.jasperreports.engine.JRException
*/
@SuppressWarnings("unchecked")
void initStyles() throws JRException{
normalStyle = new JRDesignStyle();
normalStyle.setName("Normal");
normalStyle.setDefault(true);
normalStyle.setForecolor(new Color(0, 0, 0));
normalStyle.setBlankWhenNull(true);
normalStyle.setFontSize(options.textSize);
normalStyle.setMode(JRElement.MODE_TRANSPARENT);
normalStyle.getLineBox().setPadding(options.padding);
normalStyle.setPdfEmbedded(true);
normalStyle.setPdfEncoding("Cp1251");
normalStyle.setPdfFontName("/usr/share/fonts/truetype/freefont/lucon.ttf");
targetDesting.addStyle(normalStyle);
targetDesting.setDefaultStyle(normalStyle);
headerStyle = new JRDesignStyle();
headerStyle.setName("Header");
headerStyle.setDefault(false);
headerStyle.setParentStyle(normalStyle);
headerStyle.setBold(true);
headerStyle.setFontSize(options.textSize + 2);
headerStyle.setHorizontalAlignment(JRTextElement.HORIZONTAL_ALIGN_CENTER);
targetDesting.addStyle(headerStyle);
JRStyleContainer tmpContener = new JRStyleContainer() {
@Override
public JRDefaultStyleProvider getDefaultStyleProvider() {
return null;
}
@Override
public JRStyle getStyle() {
return normalStyle;
}
@Override
public String getStyleNameReference() {
return normalStyle.getName();
}
};
JRBaseFont font = new JRBaseFont(null, null, tmpContener, null);
Map attributes = new HashMap();
JRFontUtil.getAttributes(attributes, font, Locale.getDefault());
//JRStyledText text = new JRStyledText();
normalJavaFont = new Font(attributes);
}
/**
* Инициализирует бандов отчета
*/
void initBands(){
if (topExtraFields != null || title != null){
reportHeaderBand = new JRDesignBand();
reportHeaderBand.setHeight(0);
reportHeaderBand.setSplitAllowed(true);
targetDesting.setTitle(reportHeaderBand);
}
if (bottomExtraFields != null){
reportFooterBand = new JRDesignBand();
reportFooterBand.setHeight(0);
reportFooterBand.setSplitAllowed(true);
//reportFooterBand.
//targetDesting.set
targetDesting.setSummary(reportFooterBand);
}
}
/**
* Создает JRExpression которое содержит строку в качестве формулы переданную строку,
* результатом вачесления формулы должна быть строка
* @param str - строка содержащая фрмулу. Если null то заначением выражения будет пустая строка.
* @return - JRDesignExpression
*/
@Override
public JRDesignExpression createExpression(String str){
JRDesignExpression expression = new JRDesignExpression();
expression.setValueClass(java.lang.String.class);
if (str == null) {
str = "\"\"";
}
expression.setText(str);
return expression;
}
/**
* Создает JRExpression - результатом вычесления которого будет переданная строка
* @param str - поростая строка текста
* @return - JRDesignExpression
*/
@Override
public JRDesignExpression createStringExpression(String str){
if (str == null) {
str = "";
}
str = "\"" + screenString(str) + "\"";
return createExpression(str);
}
/**
* Создает JRDesignExpression на основе выражения результатом вычеслеия которого будет тип boolean.
* @param str - строка содержащая выражение, результатом вычесления которого будет тип boolean
* @return JRDesignExpression
*/
@Override
public JRDesignExpression createBooleanExpression(String str){
if (str == null) {
throw new IllegalArgumentException("Пустая строка выражения");
}
JRDesignExpression exp = new JRDesignExpression();
exp.setValueClass(Boolean.class);
exp.setText("new Boolean(" + str + ")");
return exp;
}
/**
* Создает елкмент "текстовое поле" с заданными параметрами.
* @param type - тип текстового поля, от типа поля зависит его стиль,
* а так же некоторые особенности форматирования.
* @param x - горизонтальная координата текстового поля.
* @param y - вертикальная координата текстового поля.
* @param w - высота поля
* @param h - высота поля
* @param fieldExpression - выродение которе должно отображать поле
* @return - текстовое поле с заданными параметрами
*/
@Override
public JRDesignTextField createItem(FieldTypes type, int x, int y, int w, int h, JRExpression fieldExpression){
JRDesignTextField textField = new JRDesignTextField();
textField.setX(x);
textField.setY(y);
textField.setWidth(w);
textField.setHeight(h);
textField.setExpression(fieldExpression);
textField.setBlankWhenNull(true);
textField.setPositionType(JRDesignTextField.POSITION_TYPE_FLOAT);
textField.setStretchWithOverflow(true);
switch (type){
case header:
textField.setStyle(headerStyle);
break;
case firstPrage:
textField.setStyle(normalStyle);
break;
}
return textField;
}
public static String screenString(String str){
StringBuilder builder = new StringBuilder(str.length() << 1);
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
switch (ch){
case '\n':
builder.append("\\n");
break;
case '\r':
builder.append("\\r");
break;
case '\\':
case '\"':
case '\'':
builder.append('\\');
builder.append(ch);
break;
default:
builder.append(ch);
}
}
return builder.toString();
}
/**
* Содает выражение результатом которого является имя поля отображаетмое пльзователю
* (взятое из ExtraField)
* @param val - значение типа ExtraField
* @return - строка с выражением добавленн
*/
String expressionFieldName(ExtraField val, boolean withPluss){
if (val != null && val.fieldName != null) {
if (withPluss) {
return "\"" + screenString(val.fieldName) + " \" + ";
}
else {
return "\"" + screenString(val.fieldName) + "\"";
}
}
return "";
}
/**
* Создает выражение, результатом которого является заначение параметра,
* если параметр null, то создается статичная строка.
* @param param - уже созданный параметр отчета
* @param val - занчение поля, нужно если параметр null
* @return - строка с с формулой
*/
String expressionParamNullCheck(JRDesignParameter param, Object val){
if (param == null){
if (val != null) {
return "\"" + screenString(ReporterFactory.convertDataToString(val)) + "\"";
}
else {
return "\"\"";
}
}
return "($P{" + param.getName() + "} == null? \"\": $P{" + param.getName() + "})" ;
}
/**
* Возвращае выражение результатом которого является суффикс поля взятый из ExtraField
* @param val - значение типа ExtraField
* @return - строка с выражением, добавлени которой к выражению с данными
* приведет к добавлению суфикса
*/
String expressionFieldSufix(ExtraField val){
if (val != null && val.fieldSufix != null && val.fieldSufix.length() > 0) {
return " + \"" + screenString(val.fieldSufix) + "\"";
}
return "";
}
/**
* Созадет выражение, результатом вычесления которого будут данные поля,
* в зависимости от типа поля.
* @param param - параметр с исходными данными, если null то поле будет статическим.
* @param val - заначение
* @return - стррковое выражение, результатом вычесления которго будет
*/
String expressionField(JRDesignParameter param, ExtraField val){
String exp;
switch (val.alignmentType){
case left:
case center:
case right:
case compact:
default:
exp = expressionFieldName(val, true) + expressionParamNullCheck(param, val)
+ expressionFieldSufix(val);
break;
case dataInOneColoumnByLeft:
case dataInOneColoumnByRight:
case dataInOneColoumnByRightAndRigthAlign:
case dataInOneColoumnByRightAndHalfRigthAlign:
exp = expressionParamNullCheck(param, val) + expressionFieldSufix(val);
break;
}
return exp;
}
/**
* Создает параметр отчета, с именем ключа Map.Entry, если ключь null тогда
* она возвращает Null, если параметр с таким именем уже был создан возврящает его.
* @param entry - рараметр отчета
* @return - возвращает созданый и уже добавленный в отчет парметр.
* @throws net.sf.jasperreports.engine.JRException- по идее не когда
*/
JRDesignParameter createFieldParam(Map.Entry<String, Object> entry) throws JRException{
if (entry.getKey() == null) {
return null;
}
JRDesignParameter param = (JRDesignParameter) targetDesting.getParametersMap().get(entry.getKey());
if (param == null){
param = new JRDesignParameter();
param.setValueClass(String.class);
param.setName(entry.getKey());
targetDesting.addParameter(param);
}
return param;
}
/**
* Создает выражение для поля, по параметру отчета.
* Автоматически меняет выражеие в зависимости от типа поля.
* @param entry - параметр очета
* @return - выражение используещее этот параметр, или статичное выражение,
* если ключ был равен null
* @throws net.sf.jasperreports.engine.JRException - по идее не когда
*/
JRDesignExpression createFieldExpression(Map.Entry<String, Object> entry) throws JRException{
JRDesignParameter param = createFieldParam(entry);
String exp;
Object val = entry.getValue();
if (val != null && val instanceof ExtraField){
ExtraField data = (ExtraField) val;
exp = expressionField(param, data);
}
else {
exp = expressionParamNullCheck(param, val);
}
return createExpression(exp);
}
/**
* Создает набор полей по массиву праметров отчета, где все элементы имеют простое выравниание.
* @param startPosition - позиция начиная с которой будут созданны элементы
* @param band - бэнд в котором будут создоватся поля
* @param efields - массив параметров отчета, где заначения должны быть типа ExtraField
* @return - вертикальная позиция после самой нижней точки среди всех созданных элементов
* @throws net.sf.jasperreports.engine.JRException
*/
double createFieldPackSamle(double startPosition, JRDesignBand band, ArrayList<Map.Entry<String, Object>> efields) throws JRException{
for (Map.Entry<String, Object> entry : efields) {
JRDesignExpression exp = createFieldExpression(entry);
JRDesignTextField field = createItem(FieldTypes.firstPrage, 0, (int)Math.round(startPosition),
destingWidth, (int)Math.round(getFieldHeigth()), exp);
switch (((ExtraField)entry.getValue()).alignmentType){
case left:
field.setHorizontalAlignment(JRDesignTextField.HORIZONTAL_ALIGN_LEFT);
break;
case center:
field.setHorizontalAlignment(JRDesignTextField.HORIZONTAL_ALIGN_CENTER);
break;
case right:
field.setHorizontalAlignment(JRDesignTextField.HORIZONTAL_ALIGN_RIGHT);
break;
}
band.addElement(field);
startPosition += field.getHeight();
}
return startPosition;
}
/**
* Создает набор полей по массиву праметров отчета,
* все элементы должны быть с независимым выравниванием данных и имени поля.
* Функция находит размер самого большого имени поля, или самого большого значения
* и меняет расположение имен и занчений таким образом, чтобы они оказались выравнены по одному краю.
* @param startPosition - позиция начиная с которой будут созданны элементы
* @param band - бэнд в котором будут создоватся поля
* @param efields - массив параметров отчета, где заначение должно бьыть типа ExtraField
* @return - вертикальная позиция после самой нижней точки среди всех созданных элементов
* @throws net.sf.jasperreports.engine.JRException
*/
double createFieldPackAligned(double startPosition, JRDesignBand band, ArrayList<Map.Entry<String, Object>> efields) throws JRException{
double nameSize = 0;
double valSize = 0;
AlignmentType atype = null;
for (Map.Entry<String, Object> entry : efields) {
ExtraField val = (ExtraField) entry.getValue();
nameSize = Math.max(nameSize, getFieldLenght(val.getNNFieldName()));
valSize = Math.max(valSize, getFieldLenght(val.getNNFieldData() + val.getNNFieldSufix()));
atype = val.alignmentType;
}
if (nameSize + valSize > destingWidth){
if (nameSize > (double)destingWidth / 3d){
//nameSize = (double)destingWidth / 3d;
valSize = ((double)destingWidth * 2) / 3d;
nameSize = (double)destingWidth - valSize;
}
else{
valSize = (double)destingWidth - nameSize;
}
}
double leftPos = 0;
switch (atype){
case dataInOneColoumnByRight:
case dataInOneColoumnByRightAndRigthAlign:
case dataInOneColoumnByRightAndHalfRigthAlign:
leftPos = (double)destingWidth - nameSize - valSize;
break;
case dataInOneColoumnByLeft:
valSize = (double) destingWidth - nameSize;
break;
}
for (Map.Entry<String, Object> entry : efields){
ExtraField val = (ExtraField) entry.getValue();
JRDesignExpression nameExp = createExpression(expressionFieldName(val, false));
JRDesignExpression dataExp = createFieldExpression(entry);
JRDesignTextField nameField = createItem(FieldTypes.firstPrage,
(int)Math.round(leftPos), 0,
(int)Math.round(nameSize), (int)Math.round(getFieldHeigth()), nameExp);
JRDesignTextField dataField = createItem(FieldTypes.firstPrage,
(int)Math.round(leftPos + nameSize), 0,
(int)Math.round(valSize), (int)Math.round(getFieldHeigth()), dataExp);
nameField.setStretchType(JRDesignTextField.STRETCH_TYPE_RELATIVE_TO_BAND_HEIGHT);
dataField.setStretchType(JRDesignTextField.STRETCH_TYPE_RELATIVE_TO_BAND_HEIGHT);
JRDesignFrame farme = new JRDesignFrame();
farme.setX(0);
farme.setY((int)Math.round(startPosition));
farme.setWidth(destingWidth);
farme.getLineBox().setPadding(0);
farme.setHeight((int)Math.round(getFieldHeigth()));
farme.setStyle(normalStyle);
farme.setPositionType(JRDesignFrame.POSITION_TYPE_FLOAT);
farme.addElement(nameField);
farme.addElement(dataField);
switch (val.alignmentType){
case dataInOneColoumnByRightAndHalfRigthAlign:
nameField.setHorizontalAlignment(JRDesignTextField.HORIZONTAL_ALIGN_RIGHT);
break;
case dataInOneColoumnByRightAndRigthAlign:
nameField.setHorizontalAlignment(JRDesignTextField.HORIZONTAL_ALIGN_RIGHT);
dataField.setHorizontalAlignment(JRDesignTextField.HORIZONTAL_ALIGN_RIGHT);
break;
}
band.addElement(farme);
startPosition += dataField.getHeight();
}
return startPosition;
}
/**
* Создает поле в котором собраны все данные, всех преданных в массиве efields параметров
* @param startPosition - позиция начиная с которой будут созданны элементы
* @param band - бэнд в котором будут создоватся поля
* @param efields - массив параметров отчета, где заначение должно бьыть типа ExtraField
* @return - вертикальная позиция после самой нижней точки среди всех созданных элементов
* @throws net.sf.jasperreports.engine.JRException
*/
double createFieldPackCompact(double startPosition, JRDesignBand band, ArrayList<Map.Entry<String, Object>> efields) throws JRException{
String exp = "";
boolean fistPass = true;
for (Map.Entry<String, Object> entry : efields) {
ExtraField val = (ExtraField) entry.getValue();
if (!fistPass) {
exp += " + \" \" + ";
}
else {
fistPass = false;
}
JRDesignParameter param = createFieldParam(entry);
exp += expressionField(param, val);
}
JRDesignExpression dexp = createExpression(exp);
JRDesignTextField field = createItem(FieldTypes.firstPrage, 0,
(int)Math.round(startPosition), destingWidth,
(int)Math.round(getFieldHeigth()), dexp);
band.addElement(field);
startPosition += field.getHeight();
return startPosition;
}
/**
* Функция создает создает набор полей по параметром отчета,
* их обекты должны быть типа ExtraField, и
* все параметры должны иметь одинаковый тип выравнивания.
* (в принцепе в зависимости от выравнивания поля отправляет на соодтведствующие подфункции)
* @param startPosition - позиция начиная с которой будут созданны элементы
* @param band - бэнд в котором будут создоватся поля
* @param efields - массив параметров отчета, где заначение должно бьыть типа ExtraField
* @return - вертикальная позиция после самой нижней точки среди всех созданных элементов
* @throws net.sf.jasperreports.engine.JRException
*/
double createFieldPack(double startPosition, JRDesignBand band, ArrayList<Map.Entry<String, Object>> efields) throws JRException{
if (efields.size() <= 0) {
return startPosition;
}
ExtraField val = (ExtraField) efields.get(0).getValue();
switch (val.alignmentType){
case left:
case center:
case right:
return createFieldPackSamle(startPosition, band, efields);
case dataInOneColoumnByLeft:
case dataInOneColoumnByRight:
case dataInOneColoumnByRightAndRigthAlign:
case dataInOneColoumnByRightAndHalfRigthAlign:
return createFieldPackAligned(startPosition, band, efields);
case compact:
return createFieldPackSamle(startPosition, band, efields);
default:
throw new RuntimeException("Неизвестный тип выравнивания.");
}
}
/**
* Создает приметивное поле содержащие переданный параметр с выравниванивание по левому краю
* @param startPosition - позиция начиная с которой будут отрисованны элементы
* @param band - бэнд в котором будут создоватся поля
* @param data - параметр отчета, на который будет ссылатся поле,
* если ключ null то будет созданно поле со статическими даныыми,
* если заначение null то будет созданно пустое поле высотой в одну строку
* @return - вертикальная позиция после самой нижней точки среди всех созданных элементов
* @throws net.sf.jasperreports.engine.JRException
*/
double createSampleField(double startPosition, JRDesignBand band, Map.Entry<String, Object> data) throws JRException{
JRDesignExpression dexp = createFieldExpression(data);
JRDesignTextField field = createItem(FieldTypes.firstPrage, 0,
(int)Math.round(startPosition), destingWidth,
(int)Math.round(getFieldHeigth()), dexp);
band.addElement(field);
startPosition += field.getHeight();
return startPosition;
}
/**
* Заполняет банд параметрами отчета
*
* Разделяет массив fields на подмассивы соотведстви с форматом выравнивания
* поля скармливает подмассивы функции createFieldPack если они имеют тип ExtraField,
* или функции createSampleField если это не ExtraField
*
* @param startPosition - позиция начиная с которой будут отрисованны элементы
* @param band - бэнд в котором будут создоватся поля
* @param fields - массив параметров отчета, где заначение должно бьыть типа ExtraField
* @return
* @throws net.sf.jasperreports.engine.JRException
*/
double createReportFields(double startPosition, JRDesignBand band, Collection<Map.Entry<String, Object>> fields) throws JRException{
double posistion = startPosition;
ExtraField startField = null;
ArrayList<Map.Entry<String, Object>> efields = new ArrayList<Map.Entry<String, Object>>();
for (Iterator<Map.Entry<String, Object>> it = fields.iterator(); it.hasNext();) {
Map.Entry<String, Object> entry = it.next();
Object val = entry.getValue();
if (val != null && val instanceof ExtraField){
if (startField != null && startField.formatEqual((ExtraField) val)){
efields.add(entry);
}
else{
if (efields.size() > 0) {
posistion = createFieldPack(posistion, band, efields);
}
startField = (ExtraField) val;
efields.clear();
efields.add(entry);
}
}
else{
if (efields.size() > 0) {
posistion = createFieldPack(posistion, band, efields);
}
startField = null;
efields.clear();
posistion = createSampleField(posistion, band, entry);
}
}
if (efields.size() > 0) {
posistion = createFieldPack(posistion, band, efields);
}
return posistion;
}
/**
* Создает элемент заголовка отчета
* @param startPosition - верхняя точка заголовка
* @param band бэнд в котором будет создан заголовок
* @param text - текст заголовка
* @return незанятую линию сразу после заголовка
*/
double createTitle(double startPosition, JRDesignBand band, String text){
JRDesignExpression dexp = createStringExpression(text);
JRDesignTextField field = createItem(FieldTypes.header, 0,
(int)Math.round(startPosition), destingWidth,
getHeaderHeight(), dexp);
band.addElement(field);
startPosition += field.getHeight();
return startPosition;
}
}