iText7 large table autoLayout() - autolayout

According to the docs
public Table(int numColumns,
boolean largeTable)
Constructs a Table with specified number of columns. The final column widths depend on selected table layout. Since 7.0.2 table layout algorithms were introduced. Auto layout is default, except large tables. For large table fixed layout set implicitly. Since 7.1 table will have undefined column widths, that will be determined during layout. In oder to set equal percent width as column width, use UnitValue.createPercentArray(int)
I render a large table using https://developers.itextpdf.com/examples/tables/clone-large-tables
Is there a way to define autoLayout? Maybe after adding the first row, get the cell widths and set them on the table, but that doesn't seem possible, because the column widths are null because I am using the constructor with number of columns.
Or adding some sort of autoLayout when end page is reached.
I don't want to define the widths for the columns because we have lots of tables.

First of all I would like to mention that auto layout requires the content of the whole table. The content is used when calculating the column widths. But you are using large table, which probably means you have a lot of data and you don't want to keep everything in memory (if that's not the case, just don't use large tables).
Thus, all you can do is calculate an approximation of the automatic column widths given some initial cells. Basically, it is possible to implement your first idea, however, it takes some code to be written. But if you have very different content in cells across different rows (e.g. images vs inner tables vs some text), then this method might not work very well because as I said, to estimate column widths well you need all the content.
Please also bear in mind that this approach is quite dirty and might not work for some corner cases. But it does solve the goal and frees you of the necessity to define column widths.
To describe the solution in a few words, we take cells of several initial rows, add them to a temporary table and layout it (estimate positions etc), without actually drawing it anywhere. Then we extract the cell widths from the layout step information and can use them for the large table constructor.
The method estimating column widths looks like this:
private UnitValue[] estimateWidths(Document document, Cell[][] cells) {
int numOfColumns = cells[0].length;
Table table = new Table(numOfColumns);
for (int i = 0; i < cells.length; i++) {
for (int j = 0; j < cells[i].length; j++) {
table.addCell(cells[i][j]);
}
}
LayoutContext context = new LayoutContext(document.getRenderer().getCurrentArea().clone());
TableRenderer tableRenderer = (TableRenderer)table.createRendererSubTree();
LayoutResult result = tableRenderer.setParent(document.getRenderer()).layout(context);
if (result.getStatus() == LayoutResult.PARTIAL) {
tableRenderer = (TableRenderer) result.getSplitRenderer();
}
UnitValue[] widths = new UnitValue[numOfColumns];
List<IRenderer> subList = tableRenderer.getChildRenderers().subList(0, numOfColumns);
for (int i = 0; i < subList.size(); i++) {
IRenderer cell = subList.get(i);
widths[i] = UnitValue.createPointValue(cell.getOccupiedArea().getBBox().getWidth());
}
return widths;
}
So assuming you have a Cell[][] cells array of cells for initial couple of rows (can be one row as well, but the more the better), where cells[i][j] refers to the cell at row i and column j, you can create your large table like this:
Table table = new Table(estimateWidths(doc, cells), true);
But don't forget to explicitly add cells from cells array to the large table before adding new content.

Related

How to change the limit on the number of list templates in the AAOS car-app

When I run the code below, the maximum number of lists is limited to 6, is there any way to change this?
listLimit = getCarContext().getCarService(ConstraintManager.class).getContentLimit(
ConstraintManager.CONTENT_LIMIT_TYPE_LIST);
As in the sample code below, if 6 or more items are added and executed, 7th list is not visible. The sample code shows the 7th list in a new screen by adding a more button. Is there a way to show more than 6 lists on one screen?
public Template onGetTemplate() {
ItemList.Builder listBuilder = new ItemList.Builder();
Row[] screenArray = new Row[]{
createRow(getCarContext().getString(R.string.pane_template_demo_title),
new PaneTemplateDemoScreen(getCarContext())),
createRow(getCarContext().getString(R.string.list_template_demo_title),
new ListTemplateDemoScreen(getCarContext())),
createRow(getCarContext().getString(R.string.place_list_template_demo_title),
new PlaceListTemplateBrowseDemoScreen(getCarContext())),
createRow(getCarContext().getString(R.string.search_template_demo_title),
new SearchTemplateDemoScreen(getCarContext())),
createRow(getCarContext().getString(R.string.msg_template_demo_title),
new MessageTemplateDemoScreen(getCarContext())),
createRow(getCarContext().getString(R.string.grid_template_demo_title),
new GridTemplateDemoScreen(getCarContext())),
createRow(getCarContext().getString(R.string.long_msg_template_demo_title),
new LongMessageTemplateDemoScreen(getCarContext()))
};
...
int currentItemStartIndex = mPage * mItemLimit;
int currentItemEndIndex = Math.min(currentItemStartIndex + mItemLimit,
screenArray.length);
for (int i = currentItemStartIndex; i < currentItemEndIndex; i++) {
listBuilder.addItem(screenArray[i]);
There's no way for you as a developer to be able to change the number of list items that can be shown as these numbers have been chosen to meet safety regulations and can vary by region. Using the ConstraintManager as you're doing is the best practice since it will automatically give you the appropriate limit (vs. hard-coding this limit).
Since the number of items may vary (with 6 as the minimum), it's recommended to include the most relevant/important items first for dynamic lists.

itextsharp leaving first page empty and printing table conent in following table

I have three part in my PDF generating document using iTextSharp library.
The Header and footer I am printing using OnEndPage() of PdfPageEventHelper class. The header and footer printing well in all pages.But problem in printing large table content from middle of the page.
Now, I am facing problem when I have more that 100 table rows content to print on middle of the page.
On first page (middle of the page) I am printing table with more than 100 rows, but in this case it leave the first page empty and start printing table content on second page. Here is my table that I am trying to print on first page
PdfPTable table = new PdfPTable(5);
table.HeaderRows = 1;
table.SplitLate = false;
table.SplitRows = false;
table.SetTotalWidth(new float[] { 100, 75, 75, 75, 75 });
table.LockedWidth = true;
for (int i = 0; i < 150; i++)
{
PdfPCell cell = new PdfPCell(new phrase());
cell.Colspan = 5;
table.AddCell(cell);
}
I am using iTextSharp version: 5.4.5.0
Is there any configuration need to do, that will prevent page break?
But I am getting actual result in this format
Allow me to comment on these two lines:
table.SplitLate = false;
table.SplitRows = false;
The first line tells iTextSharp what it should do if a row doesn't fit a page. If you set this value to false, rows will be split late. For instance: you have a big row that doesn't fit the current page. In that case, the row will be forwarded to the next page. If it still doesn't fit the page, then another decision needs to be made: should the row be split or not?
The second line gives iTextSharp the answer to that question. If the value of SplitRows is true, then the row will be split. If the value is false, the row will be dropped. Allow me to quote the official documentation (p115 of "iText in Action - Second Edition"):
Ths is a dangerous line, because now not one row will be split. Rows that are too high to fit on a page will be dropped from the table!
I have the feeling that you want all the rows to show up in the table, so I suggest that you change the two lines I mentioned to:
table.SplitLate = true;
table.SplitRows = true;
Actually: why don't you just remove those two lines? The default value of SplitLate and of SplitRows is true.
Same thing happened to me using nested tables.
I solved this problem using .SplitLate = false; in the first table :)

dynamically resize columns in fastreport

I simply want to resize the columns in my grid based on its content. The code below works 100% for each individual row but it will not change the width of the rows above it. Is there anyways to change the rows above the rows that did change?
int wCol1 = 25;
public String resizeCol1(){
String sCol1 = ((String)Report.GetColumnValue("resultSet.column1"));
int test = Convert.ToInt32(Math.Round(sCol1.Length * 9.2));
if (test > wCol1) wCol1= test;
Text3.Width = wCol1;
return sCol1;
}
Set the TfrxReport.EngineOptions.DoublePass property to True.
Calculate the width in the report script and store it in variable on the first pass.
Use Engine.FinalPass flag in the script to detect whether it's the final (second) pass and apply the widths.

Sizing a spark list

I'm using spark Lists and PopupAnchors to build a drop down menu system, but I'm having trouble getting it to size reliably - the list always seems to want to take up 5 itemRenderers worth of space, but some of the menus I need to implement can be 3 or less items long. How can I have the list dynamically size to the number of elements in it, and no larger?
This is a fun one. You need to set the property on the VerticalLayout of the spark list.
Try this snippet:
(yourSparkList.layout as VerticalLayout).requestedRowCount = yourDataProvider.length;
This assumes you've got a list named yourSparkList and a dataprovider called yourDataProvider which is populating the list.
If your lists get long, you should set a MAXIMUM constant like so:
public static const MAXIMUM:int = 5;
if(yourDataProvider.length <= MAXIMUM){
(yourSparkList.layout as VerticalLayout).requestedRowCount = yourDataProvider.length;
}else{
(yourSparkList.layout as VerticalLayout).requestedRowCount = MAXIMUM;
}
BTW, there's also a requestedMaxRowCount and a requestedMinRowCount property.

Flex - sorting a datagrid column by the row's label

I'm creating a table that displays information from a MySQL database, I'm using foreignkeys all over the place to cross-reference data.
Basically I have a datagrid with a column named 'system.' The system is an int that represents the id of an object in another table. I've used lableFunction to cross-reference the two and rename the column. But now sorting doesn't work, I understand that you have to create a custom sorting function. I have tried cross-referencing the two tables again, but that takes ~30sec to sort 1200 rows. Now I'm just clueless as to what I should try next.
Is there any way to access the columns field label inside the sort function?
public function order(a:Object,b:Object):int
{
var v1:String = a.sys;
var v2:String = b.sys;
if ( v1 < v2 ){
trace(-1);
return -1;
}else if ( v1 > v2 ){
trace(1);
return 1;
}else {
trace(0);
return 0;
}
}
One way to handle this is to go through the objects you received and add the label as a property on each of them based on the cross-referenced id. Then you can specify your label property to display in your data grid column instead of using a label function. That way you would get sorting as you'd expect rather than having to create your own sort function.
The way that DataGrids, and other list based classes work is by using itemRenderers. Renderers are only created for the data that is shown on screen. In most cases there is a lot more data in your dataProvider than what is seen on screen.
Trying to sort your data based on something displayed by the dataGrid will most likely not give you the results you want.
But, there is no reason you can't call the same label function on your data objects in the sortFunction.
One way is to use the itemToLabel function of the dataGrid:
var v1:String = dataGrid.itemToLabel(a);
var v2:String = dataGrid.itemToLabel(b);
A second way is to just call the labelFunction explicitly:
var v1:String = labelFunction(a);
var v2:String = = labelFunction(b);
In my experience I have found sorting to be extremely quick, however you're recordset is slightly larger than what I usually load in memory at a single time.

Resources