I'm using iText 7 to create a PDF document, with a rather complex header.
This header will show a complex table on the first page and a different table on the remaining pages. This table will contain different information that is passed in and will contain the page number and total number of pages.
I know how to create a header with a table.
I know how to create Page X of Y.
I do not know how to create different headers (different tables with different height) that change on some logic when using iText 7:
If page 1 use Table A, if page > 1 use Table B.
Is there some way to solve this with iText 7? Any help would be appreciated.
Btw:
In iText 5 i solved this and have no problem doing this, but I want to use the latest version of iText (7).
you need to implement IEventHandler and add it as an event listener for adding new page
simple example :
public class PdfEventHandler implements IEventHandler {
#Override
public void handleEvent(Event event) {
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdfDoc = docEvent.getDocument();
PdfPage page = docEvent.getPage();
PdfDocumentEvent docEvent = (PdfDocumentEvent) event;
PdfDocument pdfDoc = docEvent.getDocument();
PdfPage page = docEvent.getPage();
int pageNum = pdfDoc.getPageNumber(page)
if(pageNum> 1 )
//add table1
else
//add Table 2
}
}
and then add this event handler to you document event listener like this
PdfEventHandler handler = new PdfEventHandler();
pdf.addEventHandler(PdfDocumentEvent.START_PAGE, handler);
Related
So I'm generating tables with cells based on some data that I get from a database.
And my question is simple, how do I know when to create a new page? I would have to calculate the height of each table and make sure that they're within the size of the page, and if the next table isn't, well then create a new page and add it to that one.
The issue is I'm not sure if this is the right approach. Is this how you would do it? And if so, how do I calculate the height of a table because myTable.GetHeight().GetValue(); throws a nullreference exception because GetHeight() returns null.
First of all table.GetHeight().GetValue() returns null because you are %99 not setting your table's height.
For Example :
var table1 = new Table(1);
var height1 = table1.GetHeight().GetValue(); // This throws exception because we are not setting the height in here.
var table2 = new Table(1).SetHeight(20);
var height2 = table2.GetHeight().GetValue(); // This line returns 20, because you have set the value of height
For your main issue,
You can take the default page size with the below code, and set your table's height
var defaultPageHeight = pdfDocument.GetDefaultPageSize().GetHeight();
var table = new Table(1).UseAllAvailableWidth().SetHeight(defaultPageHeight);
But this wouldnt be a good approach, I think a good approach would be using a TableRenderer
Little Example:
public class CustomTableRenderer : TableRenderer
{
protected Document document;
public class CustomTableRenderer(Table modelElement, Document document) : base(modelElement)
{
this.document = document;
}
public override IRenderer GetNextRenderer()
{
// Add a header everytime a new page is created with this renderer
var header = new Table(1).UseAllAvailableWidth();
header.AddCell(new Cell().Add(new Paragraph("Title")));
document.Add(header);
return new CustomTableRenderer((Table)GetModelElement())
}
public override void Draw(DrawContext drawContext)
{
// This is the part where you create your layout for every time this renderer calls.
var defaultPageHeight = drawContext.GetDocument().GetDefaultPageSize().GetHeight();
// And you can do other things
}
}
I'm using iTextSharp to display images in a pdf report. Here I want display two images in a row and it's working as expected but having a issue when end of the page reaches. The issue is that last row images get shrink to fit in same page, it doesn't automatically add it to the next page. All images having same dimension and resolution.
Please, provide us with the code.
I wrote the test below (although it's in java, there should be no problem) and the results seem to be correct.
public void tableWithImagesTest01() throws IOException, InterruptedException {
String testName = "tableWithImagesTest01.pdf";
String outFileName = destinationFolder + testName;
String cmpFileName = sourceFolder + "cmp_" + testName;
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(outFileName));
Document doc = new Document(pdfDoc, PageSize.A3);
Image image1 = new Image(ImageDataFactory.create(sourceFolder + "itis.jpg"));
Table table = new Table(2);
for (int i = 0; i < 20; i++) {
table.addCell(new Cell().add(image1));
table.addCell(new Cell().add(image1));
table.addCell(new Cell().add(new Paragraph("Hello")));
table.addCell(new Cell().add(new Paragraph("World")));
}
doc.add(table);
doc.close();
Assert.assertNull(new CompareTool().compareByContent(outFileName, cmpFileName, destinationFolder, "diff"));
}
The result pdf looks like this:
Maybe you use summat image1.setAutoScale(true);? Still we need your code to look at.
The easiest solution (considering all images have the same dimension and resolution) would be to manually insert a new page and pagebreak every time you have inserted the maximum number of images to a page.
Taken from a comment below, the solution that works is, on the individual images you need to set:
image.ScaleToFitHeight = false;
Likely to happen when keeping rows together
Ok, so I have a pretty specific and to me quite complicated issue, as I'm a GWT newbie.
I have a GWT flex table, which I use to dynamically add rows, whose cells contain GWT widgets. The row number changes, but the number of columns in static, always 6. Each row contains a cell with a remove button and five cells each with their own textbox.
What I need to do is somehow code a kind of relationship between the textbox in cell 6 of one row and the textbox in cell 5 in the next row (and vice versa).
To illustrate: when something changes in the textbox at [1,6] the content of textbox at [2,5] needs to be overwritten with the same value. If the textbox at [2,5] changes the textbox at [1,6] needs to change as well. I cannot use a button to commit the changes, it needs to happen via onValueChange or Blur or something similar, which doesn't require the user to perform a specific action.
My problem stems mostly from trying to figure out how to address specific cells in the flex table and their content. For the remove button the solution was easy enough with a click event handler, but for this issue I just can't seem to be able to come up with a solution.
Sadly I also cannot provide any of the code which I have up until now, since it's a business secret. I can only give a broad description of the problem like the one above.
EDIT:
Actually, it's probably more a problem of not having much code in terms of this specific problem.
What I have is a flex table, which has initially only the header row. Upon clicking a button below this table the addNewField() method is called, which just contains the creation, setting of default values and adding of the text fields into a new row.
addNewField() {
int rows = flextable.getRowCount();
Button removeBtn = new Button("x");
removeBtn.getElement().setId(Integer.toString(rows));
//then the button's event handler
TextBox name = new TextBox();
name.setText("something");
flextable.setWidget(rows, 0, "name");
//repeat 4 more times with incrementing columns for the other widgets
}
This way I add entire rows of editable TextBoxes. What I need is a way to influence the values of the 6th column TextBox of a chosen row and the 5th column TextBox of chosen row + 1.
EDIT2: I've tried the dirty option just to see how it would go and somehow the compare inside the if breaks the app. The compiler detects a nullpointerexception and I can't even debug it with breakpoints because it fails to compile and won't start. I can't figure out why though. I threw the code directly into the event for testing purposes, so pardon the ugliness.
TextBox bis = new TextBox();
bis.setText(rows + ":10:00");
subs.setWidget(rows, 5, bis);
bis.addValueChangeHandler(new ValueChangeHandler<String>()
{
#Override
public void onValueChange(ValueChangeEvent<String> event)
{
allRows: for (int i = 0; i < subs.getRowCount(); i++)
{
for (int j = 0; j < subs.getCellCount(i); j++)
{
if ( subs.getWidget(i, j) == bis )
{
TextBox widgetAtColumnSix = ((TextBox) subs.getWidget(i, 5));
String text = widgetAtColumnSix.getText();
TextBox widgetAtColumnFiveRowPlusOne = ((TextBox) subs.getWidget(i + 1, 4));
widgetAtColumnFiveRowPlusOne.setText(text);
break allRows;
}
}
}
}
});
EDIT: Since you edited your question and you dont want to use EventBus you could iterate over your FlexTable and set your TextBox value depending on your current rowIndex and cellIndex... Its not nice but it should work:
public class CellWidget extends Composite {
private TextBox nameBox;
public CellWidget() {
FlowPanel flowPanel = new FlowPanel();
Button deleteButton = new Button("x");
nameBox = new TextBox();
nameBox.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
notifiyTextBox(CellWidget.this, event.getValue());
}
});
flowPanel.add(nameBox);
flowPanel.add(deleteButton);
initWidget(flowPanel);
}
public void setText(String text) {
nameBox.setText(text);
}
}
public void notifiyTextBox(CellWidget source, String string) {
rows: for (int i = 0; i < flextable.getRowCount(); i++) {
columns: for (int j = 0; j < flextable.getCellCount(i); j++) {
if (flextable.getWidget(i, j) == source) {
CellWidget widgetAtColumnSix = ((CellWidget) flextable.getWidget(i, 5));
widgetAtColumnSix.setText(string);
CellWidget widgetAtColumnFiveRowPlusOne = ((CellWidget) flextable.getWidget(i + 1, 4));
widgetAtColumnFiveRowPlusOne.setText(string);
break rows;
}
}
}
}
I still would recommend using an eventbus. To make it even more convenient there is the GWT Event Binder lib, which makes using events a breeze.
So when you change a value in your textbox[2,5] it also fires your CustomEvent. All Widgets, that need to change their textbox value just need to catch...
Using iTextSharp, how can I insert a new page at the beginning of the page, when the PdfWriter has been writing pages already? Suppose the case of an index page which should be the first page of the document, but you wouldn't know its contents until you write the whole document. Particularly, on which page is each section/chapter written.
You can't go back to the first page while you're creating a document, but there are different ways to solve your problem.
If you don't expect to have many pages, you could consider the solution that is explained in chapter 5 of iText in Action - Second Edition, more specifically in the MovieHistory1.java example.
In this example, we reorder the pages right before we close the document:
// step 1
Document document = new Document();
// step 2
PdfWriter writer
= PdfWriter.getInstance(document, new FileOutputStream(RESULT));
// IMPORTANT: set linear page mode!
writer.setLinearPageMode();
// step 3
document.open();
// step 4
// Add all your content
// Create a new order for the pages
int total = writer.reorderPages(null);
// change the order
int[] order = new int[total];
for (int i = 0; i < total; i++) {
order[i] = i + toc;
if (order[i] > total)
order[i] -= total;
}
// apply the new order
writer.reorderPages(order);
// step 5
document.close();
Why do I only recommend this for documents with a limited number of pages? For this functionality to work we need to create a linear page tree:
writer.setLinearPageMode();
A linear page tree is not really a tree (it's a tree without any branches) and that is not optimal in PDF.
It is better to reorder the pages in a second go. This is explained in two questions that are bundled in The Best iText Questions on StackOverflow (a free ebook).
The questions were:
Create Index File(TOC) for merged pdf using itext library in java
PDF Page re-ordering using itext
I know that having redundant info on SO is not ideal, but this is the code you'd need:
PdfReader reader = new PdfReader(baos.toByteArray());
int n = reader.getNumberOfPages();
reader.selectPages(String.format("%d, 1-%d", n, n-1));
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(filename));
stamper.close();
I need to implement a feature in GWT which is already existing in smartgwt. In smartgwt, we can set a maximum limit of records in a grid is 75. When the record count reaches 75 while scrolling, it again requests the server and fetches another 75 records. Similar functionality I have to implement in GWT. ie, while scrolling, i have to fetch records from server for every 75 records. Is it possible?? Please assist.
You can use the ScrollPanel for check when the user reache the end of the scoll.
You can try this example of code, and adapt it to your case :
String loremIpsum = "a long text..."; // add a long text here for test
ScrollPanel sPanelTest = new ScrollPanel(loremIpsum);
sPanelTest.addScrollHandler(new ScrollHandler() {
#Override
public void onScroll(ScrollEvent event) {
int maxPosition = sPanelTest.getMaximumVerticalScrollPosition();
int currentPosition = sPanelTest.getVerticalScrollPosition();
if(currentPosition == maxPosition)
Window.alert("Tadam !"); // end of the scroll
}
});
Doc of ScrollPanel.
Another example of use.