Conflict of tables, when footer one is firmly set to the bottom - java

The following screen shot demonstrates the problem I am experiencing:
NOTE: I want to have that green table only on the very end of the whole pdf file, not on every single page!
Is there some elegant solution to find the X,Y location on the page and manually create new page?
This is my code (using iText):
private static PdfPTable createHeaderTable() throws DocumentException {
int[] columnWidths = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
PdfPTable datatable = new PdfPTable(columnWidths.length);
datatable.setWidthPercentage(100);
datatable.setWidths(columnWidths);
datatable.getDefaultCell().setPadding(5);
datatable.getDefaultCell().setHorizontalAlignment(alignment);
datatable.getDefaultCell().setVerticalAlignment(alignment);
for (int i = 0; i < 90; i++) {
addCellToTable(datatable, horizontalAlignmentLeft,
verticalAlignmentMiddle,"Přehledová tabulka", columnWidths.length,
1, fontTypeBold, fontSizeRegular,cellLayout_Bottom);
}
private static PdfPTable createFooterTable() throws DocumentException {
int[] columnWidths = new int[] { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
PdfPTable datatable = new PdfPTable(columnWidths.length);
// datatable.setKeepTogether(true);
datatable.setWidthPercentage(100);
datatable.setWidths(columnWidths);
datatable.getDefaultCell().setPadding(5);
datatable.getDefaultCell().setHorizontalAlignment(alignment);
datatable.getDefaultCell().setVerticalAlignment(alignment);
//.... added cells identically as by header table (higher here) ...
return datatable;
}
public static void main(String[] args)
throws FileNotFoundException, DocumentException {
Document document = new Document(PageSize.A4);
PdfWriter writer = null;
try {
writer = PdfWriter.getInstance(document,
new FileOutputStream("C:/radek-folder/calendar.pdf"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
document.open();
PdfPTable datatable = createHeaderTable();
document.add(datatable);
datatable = createFooterTable();
drawTableAtTheEndOfPage(document, writer, datatable);
document.close();
System.out.println("done");
}
private static void drawTableAtTheEndOfPage(Document document, PdfWriter writer,
PdfPTable datatable) {
datatable.setTotalWidth(
document.right(document.rightMargin()) -
document.left(document.leftMargin()));
datatable.writeSelectedRows(0, -1, document.left(document.leftMargin()),
datatable.getTotalHeight() + document.bottom(document.bottomMargin()),
writer.getDirectContent());
}

I closed your question as a duplicate of Why is my content overlapping with my footer? because I (wrongly) assumed that you wanted to add a table to each page of the document.
You updated your question with a clarification, and it is now a duplicate of this question: How to find out the current cursor position on a page?
Stack Overflow doesn't allow me to close a question as duplicate twice, hence I have to copy/paste my previous answer here:
There is a very old method called getVerticalPosition() that takes a
boolean as parameter. I'm not proud of that method as it is a
getter method that not only will give you the Y position on the page after using a series of document.add() operations, it can also
change the current Y position (and that is not what a getter method
should do).
If you pass false as a parameter, it will give you the current Y,
which could be the position of the baseline of the last Chunk you've
added.
If you pass true as a parameter, the method will first add a newline
and give you the position of the baseline of the "next" line of text
you'll be adding.
Note that many design flaws (some of which that date back to my original design of iText dating from the year 2000) are fixed in iText 7; iText 7 is a complete rewrite of iText.

My solution:
private static void drawTableAtTheEndOfPageAndWholeDocument
(Document document, PdfWriter writer, PdfPTable datatable)
{
datatable.setTotalWidth(document.right() - document.left());
if (writer.getVerticalPosition(false) - datatable.getTotalHeight()
- document.bottom() < 0) {
// new page if there is too little space for the final table on
// current page
document.newPage();
}
datatable.writeSelectedRows(0, -1, document.left(),
datatable.getTotalHeight() + document.bottom(),
writer.getDirectContent());
}

Related

How to selectively apply borders to a docx table in Apache POI?

In Microsoft Word, if you go to the properties of a table, and then the "Borders and Shading" section, you will see that you are able to apply borders to a table on 8 of its aspects. top, bottom, left, right, center-vertical, center-horizontal, diagonal-left, and diagonal-right
How can I turn them on selectively using POI?
In current apache poi 4.1.0 the class XWPFTable provides methods for this.
For example XWPFTable.setTopBorder:
public void setTopBorder(XWPFTable.XWPFBorderType type,
int size,
int space,
java.lang.String rgbColor)
Set Top borders for table
Parameters:
type - - XWPFTable.XWPFBorderType e.g. single, double, thick
size - - Specifies the width of the current border. The width of this border is
specified in measurements of eighths of a point, with a minimum value of two
(onefourth of a point) and a maximum value of 96 (twelve points).
Any values outside this range may be reassigned to a more appropriate value.
space - - Specifies the spacing offset that shall be used to place this border
on the table
rgbColor - - This color may either be presented as a hex value (in RRGGBB format),
or auto to allow a consumer to automatically determine the border color
as appropriate.
See XWPFTable.XWPFBorderType for possible border types.
Complete example:
import java.io.FileOutputStream;
import org.apache.poi.xwpf.usermodel.*;
public class CreateWordTableBorders {
public static void main(String[] args) throws Exception {
XWPFDocument document= new XWPFDocument();
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run=paragraph.createRun();
run.setText("The table:");
//create the table
XWPFTable table = document.createTable(3,3);
table.setWidth("100%");
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
table.getRow(row).getCell(col).setText("row " + row + ", col " + col);
}
}
//set borders
table.setTopBorder(XWPFTable.XWPFBorderType.THICK_THIN_LARGE_GAP, 32, 0, "FF0000");
table.setBottomBorder(XWPFTable.XWPFBorderType.THICK_THIN_LARGE_GAP, 32, 0, "FF0000");
table.setLeftBorder(XWPFTable.XWPFBorderType.THICK_THIN_LARGE_GAP, 32, 0, "FF0000");
table.setRightBorder(XWPFTable.XWPFBorderType.THICK_THIN_LARGE_GAP, 32, 0, "FF0000");
table.setInsideHBorder(XWPFTable.XWPFBorderType.DOT_DASH, 16, 0, "00FF00");
table.setInsideVBorder(XWPFTable.XWPFBorderType.DOTTED, 24, 0, "0000FF");
paragraph = document.createParagraph();
FileOutputStream fileOut = new FileOutputStream("create_table.docx");
document.write(fileOut);
fileOut.close();
document.close();
}
}

using iText pdf api arrange data into multiple columns like below image attachment [duplicate]

Please, how i can add titles of the Chapters in ColumnText?
I need make PDF like this:
| ColumnText column1 | ColumnText column2 |
| PdfPTable with content | PdfPTable with content |
| | Chapter 2 title |
| Chapter 1 title | |
And then add TOC to this document.
I make document with ColumnText and table in it. But can't add Chapter in table.
I can add Chapter only to the document body, but in this case title of Chapter not in ColumnText.
Image of one page of the result document here
Your question isn't clear in the sense that you don't tell us if you want a TOC like this:
If this is the case, you are using the wrong terminology, as what you see in the Bookmarks panel can be referred to as Outlines or bookmarks.
If you say you want a TOC, you want something like this:
I mention both, because you talk about the Chapter (a class you should no longer use) and that class creates bookmarks/outlines, not a TOC.
I have create a PDF file that has both, bookmarks and a TOC: columns_with_toc.pdf. Please take a look at the CreateTOCinColumn example to find out how it's done.
Just like you, I create a ColumnText object with titles and tables:
ColumnText ct = new ColumnText(writer.getDirectContent());
int start;
int end;
for (int i = 0; i <= 20; ) {
start = (i * 10) + 1;
i++;
end = i * 10;
String title = String.format("Numbers from %s to %s", start, end);
Chunk c = new Chunk(title);
c.setGenericTag(title);
ct.addElement(c);
ct.addElement(createTable(start, end));
}
int column = 0;
do {
if (column == 3) {
document.newPage();
column = 0;
}
ct.setSimpleColumn(COLUMNS[column++]);
} while (ColumnText.hasMoreText(ct.go()));
The result looks like this:
In spite of the rules for posting a question on StackOverflow, you didn't post a code sample, but there is at least one difference between your code and mine:
c.setGenericTag(title);
In this line, we declare a generic tag. This tag is used by the TOCEntry class that looks like this:
public class TOCCreation extends PdfPageEventHelper {
protected PdfOutline root;
protected List<TOCEntry> toc = new ArrayList<TOCEntry>();
public TOCCreation() {
}
public void setRoot(PdfOutline root) {
this.root = root;
}
public List<TOCEntry> getToc() {
return toc;
}
#Override
public void onGenericTag(PdfWriter writer, Document document, Rectangle rect, String text) {
PdfDestination dest = new PdfDestination(PdfDestination.XYZ, rect.getLeft(), rect.getTop(), 0);
new PdfOutline(root, dest, text);
TOCEntry entry = new TOCEntry();
entry.action = PdfAction.gotoLocalPage(writer.getPageNumber(), dest, writer);
entry.title = text;
toc.add(entry);
}
}
As you can see, we create a PdfDestination based on the position of the title:
PdfDestination dest = new PdfDestination(PdfDestination.XYZ, rect.getLeft(), rect.getTop(), 0);
If you want bookmarks, you can create a PdfOutline like this:
new PdfOutline(root, dest, text);
If you want a TOC, you can store a String and a PdfAction in a List:
TOCEntry entry = new TOCEntry();
entry.action = PdfAction.gotoLocalPage(writer.getPageNumber(), dest, writer);
entry.title = text;
toc.add(entry);
Now that we understand the TOCCreation class, we take a look at how to use it:
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(dest));
TOCCreation event = new TOCCreation();
writer.setPageEvent(event);
document.open();
event.setRoot(writer.getRootOutline())
We create an event object, pass it to the writer and after we've opened the document, we pass the root of the outline tree to the event. The bookmarks will be created automatically, the TOC won't. If you want to add the TOC, you need something like this:
document.newPage();
for (TOCEntry entry : event.getToc()) {
Chunk c = new Chunk(entry.title);
c.setAction(entry.action);
document.add(new Paragraph(c));
}
You now have a list of titles which you can click to jump to the corresponding table.

How to auto stretch detail band when print order is set to "horizontal" in JasperReport?

I have a main report which is printed horizontally. It has 5 columns.
On every column i want to put a sub report. So i created this:
And the sub-report just like this:
The problem is, when i run i get the following exception:
net.sf.jasperreports.engine.JRRuntimeException: Subreport overflowed on a band that does not support overflow.
Looks like jasper reports can't stretch the detail band vertically when there is a sub-report in it and the print order is set to horizontal.
What can I do to avoid this error and achieve what i want?
I found the solution for this problem. After a deep search i found that, sadly, there's no way to do this on Jasper Reports because, no matter what, when you have a report printed horizontally, the "Detail" band will never change it's height. So, subreports or text fields which overflows will throw an exception.
The workaround for this problem is to work without reports, with a PDF generator like iText, for example.
This is the code i did to achive what i wanted with iText if somebody needs it:
Document document = new Document();
File arquivo = new File("C:\\Users\\Mateus\\Desktop\\testezãozarãozão.pdf");
PdfWriter.getInstance(document, new FileOutputStream(arquivo));
document.open();
LinkedHashMap<Produto, LinkedHashMap<String, List<PrePedidoItem>>> produtos = createStructuredHashMap();
for (Produto produto : produtos.keySet()) {
PdfPTable table = new PdfPTable(5);
PdfPCell cellProduto = new PdfPCell();
Phrase phraseProduto = new Phrase(String.valueOf(produto));
phraseProduto.setFont(new Font(Font.FontFamily.HELVETICA, 11, Font.BOLD|Font.UNDERLINE, new BaseColor(50, 65, 200)));
cellProduto.addElement(phraseProduto);
cellProduto.setColspan(5);
cellProduto.setHorizontalAlignment(PdfPCell.ALIGN_MIDDLE);
cellProduto.setBorder(Rectangle.NO_BORDER);
cellProduto.setPaddingBottom(10);
cellProduto.setPaddingTop(20);
table.addCell(cellProduto);
LinkedHashMap<String, List<PrePedidoItem>> mapas = produtos.get(produto);
int mapasAdicionados = 0;
for (String mapa : mapas.keySet()) {
PdfPCell cellMapa = new PdfPCell();
Phrase phraseMapa = new Phrase(mapa);
phraseMapa.setFont(new Font(Font.FontFamily.HELVETICA, 9, Font.BOLD, new BaseColor(215, 100, 0)));
cellMapa.addElement(phraseMapa);
List<PrePedidoItem> itensDoMapa = mapas.get(mapa);
for (PrePedidoItem item : itensDoMapa) {
DecimalFormat df = new DecimalFormat("###,##0.00");
Phrase phraseItem = new Phrase(df.format(item.getLargura()) + " x " + df.format(item.getComprimento()));
phraseItem.setFont(new Font(Font.FontFamily.HELVETICA, 9, Font.NORMAL, BaseColor.BLACK));
cellMapa.addElement(phraseItem);
}
cellMapa.setBorder(Rectangle.NO_BORDER);
table.addCell(cellMapa);
mapasAdicionados ++;
if(mapasAdicionados == 5) {
mapasAdicionados = 0;
}
}
PdfPCell celulaPreenchimentoMapas = new PdfPCell();
celulaPreenchimentoMapas.setColspan(5 - mapasAdicionados);
celulaPreenchimentoMapas.setBorder(Rectangle.NO_BORDER);
table.addCell(celulaPreenchimentoMapas);
document.add(table);
}
document.close();
Desktop.getDesktop().open(arquivo);

iText - avoid first row to cut tables on page split [duplicate]

I am working on itext 5 using java. I have pages with mutiple tables with dynamic rows. In some instances, the table last row is splitted into next page with the folowing header. I am using setHeaderRows() and setSkipFirstHeader() to manage continuation of next page. The last row has enough space to fit on earlier page. I would like to fit that last row in same page instead of next page.
For example, on page 1, the last row is splitted into first row of next page. Instead I would like to fit that row in page 1 so save one extra page with all blanks.
I tried using setExtendLastRow(), but its not working. Does anyone know how to fix this problem. I am attaching a working sample code.
public class ProposalItextSplitLastRow {
public static void main(String[] args) {
try {
Document document = new Document();
document.setPageSize(PageSize.LETTER);
document.setMargins(16, 14, 14, 14);
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("C:/SplitLastRow.pdf"));
document.open();
document.setPageSize(PageSize.LETTER);
document.setMargins(16, 14, 42, 38);
for (int m = 1; m < 20; m++) {
int row = 0;
PdfPTable table = new PdfPTable(1);
table.setSpacingAfter(0);
table.setSpacingBefore(0);
table.setWidthPercentage(100);
table.setHeaderRows(1);
table.setSkipFirstHeader(true);
add(table, "Header Row continued " + m, BaseColor.LIGHT_GRAY, row++);
add(table, "Header Row normal " + m, BaseColor.LIGHT_GRAY, row++);
add(table, "Text Row 1 ", BaseColor.WHITE, row++);
add(table, "Text Row 2 ", BaseColor.WHITE, row++);
add(table, "Text Row 3 ", BaseColor.WHITE, row++);
addPadding(table);
document.add(table);
}
document.close();
} catch (Exception de) {
de.printStackTrace();
}
}
private static void add(PdfPTable table, String text, BaseColor color, int row) {
PdfPCell pdfCellHeader = new PdfPCell();
pdfCellHeader.setBackgroundColor(color);
pdfCellHeader.addElement(new Paragraph(new Phrase(text)));
table.addCell(pdfCellHeader);
}
private static void addPadding(PdfPTable table) {
PdfPCell cell = new PdfPCell();
cell.setFixedHeight(2f);
cell.setBorder(Rectangle.NO_BORDER);
cell.setColspan(table.getNumberOfColumns());
table.addCell(cell);
}
}
you can table.setKeepRowsTogather(true);
table.setHeaderRows(1) as well alongwith it
setKeepRowsTogather() checks if it can keep all the rows in page but splits the rows in case the table spans multiple pages. In that case setHeaderRows(1) will put the header rows again in the next page.
I had to execute the example to understand your question. You confused me by talking about a header that isn't a header (the rows with "Header Row normal" aren't header rows!) and your reference to setExtendLastRow() didn't help either (mentioning that method doesn't make sense to me; it's very confusing).
This being said, the solution to your problem is a no-brainer. I've rewritten the main class:
public static void main(String[] args) {
try {
Document document = new Document();
document.setPageSize(PageSize.LETTER);
document.setMargins(16, 14, 14, 14);
PdfWriter writer = PdfWriter.getInstance(document,
new FileOutputStream("SplitLastRow.pdf"));
document.open();
document.setPageSize(PageSize.LETTER);
document.setMargins(16, 14, 42, 38);
for (int m = 1; m < 20; m++) {
int row = 0;
PdfPTable table = new PdfPTable(1);
table.setSpacingAfter(0);
table.setSpacingBefore(0);
table.setTotalWidth(document.right() - document.left());
table.setLockedWidth(true);
table.setHeaderRows(1);
table.setSkipFirstHeader(true);
add(table, "Header Row continued " + m, BaseColor.LIGHT_GRAY, row++);
add(table, "Header Row normal " + m, BaseColor.LIGHT_GRAY, row++);
add(table, "Text Row 1 ", BaseColor.WHITE, row++);
add(table, "Text Row 2 ", BaseColor.WHITE, row++);
add(table, "Text Row 3 ", BaseColor.WHITE, row++);
addPadding(table);
if (writer.getVerticalPosition(true) - table.getRowHeight(0) - table.getRowHeight(1) < document.bottom()) {
document.newPage();
}
document.add(table);
}
document.close();
} catch (Exception de) {
de.printStackTrace();
}
}
Make sure you define a total width instead of a width percentage, and lock the width. As documented (and as common sense tells you), a PdfPTable object doesn't know its actual width if you define a width percentage. It goes without saying that you can't calculate the height of a table that doesn't know it's actual width.
Then use getVerticalPosition() method to get the current position of the cursor, and check if the first two rows fit on the page. If they don't go to a new page before adding the table. If you want to check if the complete table fits, use the getTotalHeight() method instead of the getRowHeight() method.
You can do
table.setSplitRows(false);
But I believe that when there is a row that wont fit it just wont be shown. It's worth a shot though

Blackberry Java TableView: calculateVerticalScrollAmount Exception?

I'm getting a "TableView(ScrollView).calculateVerticalScrollAmount(XYRect)" exception when trying to create a table using the following code. I've tried simplifying the fields, but nothing seems to help, any thoughts? The code is similar to that in the Tables Demo supplied with the BB 6 SDK.
It looks like a layout issue, but I can't seem to pin down the error.
// Create and apply style
RegionStyles style = new RegionStyles(BorderFactory.createSimpleBorder(new XYEdges(1, 1, 1, 1), Border.STYLE_SOLID), null, null,
null, RegionStyles.ALIGN_LEFT, RegionStyles.ALIGN_TOP);
// Create the view and controller
TableView tableView = new TableView(_tableModel);
TableController tableController = new TableController(_tableModel, tableView);
// Set the controller focus policy to highlight rows
tableController.setFocusPolicy(TableController.ROW_FOCUS);
// Set the behaviour of the controller when a table item is clicked
tableController.setCommand(new CommandHandler()
{
/**
* #see CommandHandler#execute(ReadOnlyCommandMetadata, Object)
*/
public void execute(ReadOnlyCommandMetadata metadata, Object context)
{
Dialog.alert("Command Executed");
}
}, null, null);
tableView.setController(tableController);
// Create a DataTemplate that suppresses the third column
DataTemplate dataTemplate = new DataTemplate(tableView, 2, 3)
{
/**
* #see DataTemplate#getDataFields(int)
*/
public Field[] getDataFields(int modelRowIndex)
{
Object[] data = (Object[]) ((TableModel) getView().getModel()).getRow(modelRowIndex);
Field[] fields = new Field[4];
fields[0] = new BitmapField((Bitmap) data[0]);
fields[1] = new LabelField(data[1], Field.FOCUSABLE);
fields[2] = new LabelField(data[2], Field.FOCUSABLE);
fields[3] = new LabelField(data[3], Field.FOCUSABLE);
return fields;
}
};
// Set up regions
dataTemplate.createRegion(new XYRect(0, 0, 1, 2), style);
dataTemplate.createRegion(new XYRect(1, 0, 2, 1), style);
dataTemplate.createRegion(new XYRect(1, 1, 1, 1), style);
dataTemplate.createRegion(new XYRect(2, 1, 1, 1), style);
// Specify the size of each column by percentage, and the height of a row
dataTemplate.setColumnProperties(0, new TemplateColumnProperties(15, TemplateColumnProperties.PERCENTAGE_WIDTH));
dataTemplate.setColumnProperties(1, new TemplateColumnProperties(15, TemplateColumnProperties.PERCENTAGE_WIDTH));
dataTemplate.setColumnProperties(2, new TemplateColumnProperties(70, TemplateColumnProperties.PERCENTAGE_WIDTH));
dataTemplate.setRowProperties(0, new TemplateRowProperties(ROW_HEIGHT));
dataTemplate.setRowProperties(1, new TemplateRowProperties(ROW_HEIGHT));
// Apply the template to the view
tableView.setDataTemplate(dataTemplate);
dataTemplate.useFixedHeight(true);
add(tableView);
Not sure if you are still struggling with this - may be benefits for others
in the statement
DataTemplate dataTemplate = new DataTemplate(tableView, 2, 3)
you have initialized the DataTemplate with 2 rows and 3 columns (assuming you want to suppress 4th column). But inside the function getDataFields you are returning 4 fields.
This is causing the crash (the internal code is not monkey proof).
Drop the 4th field from array and it should work.

Categories

Resources