public void testOrphan4() throws Exception { final MasterReport masterReport = DebugReportRunner.parseGoldenSampleReport("Prd-2087-Orphan-4.prpt"); final LogicalPageBox box = DebugReportRunner.layoutPage(masterReport, 0); final RenderNode srs[] = MatchFactory.findElementsByElementType(box, SubReportType.INSTANCE); assertEquals(1, srs.length); assertEquals(StrictGeomUtility.toInternalValue(20), srs[0].getY()); final RenderNode elementByName = MatchFactory.findElementByName(box, "outer-group"); assertEquals(StrictGeomUtility.toInternalValue(20), elementByName.getY()); }
@Test public void testCanvasWithPrePostPad() throws Exception { final MasterReport report = new MasterReport(); report.setDataFactory(new TableDataFactory("query", new DefaultTableModel(10, 1))); report.setQuery("query"); final Band table = TableTestUtil.createTable(1, 1, 6, new CustomProducer()); table.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, 200f); table.getStyle().setStyleProperty(ElementStyleKeys.POS_X, 100f); table.getStyle().setStyleProperty(ElementStyleKeys.POS_Y, 10f); table.setName("table"); report.getReportHeader().addElement(TableTestUtil.createDataItem("Pre-Padding", 100, 10)); report.getReportHeader().addElement(table); Element postPaddingItem = TableTestUtil.createDataItem("Post-Padding", 100, 10); postPaddingItem.getStyle().setStyleProperty(ElementStyleKeys.POS_X, 300f); report.getReportHeader().addElement(postPaddingItem); report.getReportHeader().setLayout("canvas"); PdfReportUtil.createPDF(report, "test-output/PRD-3857-output-canvas.pdf"); List<LogicalPageBox> pages = DebugReportRunner.layoutPages(report, 0, 1, 2); assertPageValid(pages, 0, StrictGeomUtility.toInternalValue(10)); assertPageValid(pages, 1); assertPageValid(pages, 2); }
public void testPagebreakHonoredOnFirstPage() throws Exception { final MasterReport masterReport = DebugReportRunner.parseGoldenSampleReport("Pre-492.prpt"); final LogicalPageBox page0 = DebugReportRunner.layoutPage(masterReport, 0); final RenderNode[] elementsByElementType = MatchFactory.findElementsByElementType(page0.getContentArea(), AutoLayoutBoxType.INSTANCE); assertEquals(31, elementsByElementType.length); assertEquals( StrictGeomUtility.toInternalValue(199), elementsByElementType[elementsByElementType.length - 1].getY()); final LogicalPageBox page1 = DebugReportRunner.layoutPage(masterReport, 1); final RenderNode[] elementsPage1 = MatchFactory.findElementsByElementType(page1.getContentArea(), AutoLayoutBoxType.INSTANCE); assertEquals(34, elementsPage1.length); assertEquals( StrictGeomUtility.toInternalValue(211), elementsPage1[elementsPage1.length - 1].getY()); // ModelPrinter.INSTANCE.print(page1); }
/** * Canvas elements do not shift content. Therefore the widow definition is not effective. * * @throws Exception */ public void testOrphan5() throws Exception { final MasterReport masterReport = DebugReportRunner.parseGoldenSampleReport("Prd-2087-Orphan-5.prpt"); // masterReport.setCompatibilityLevel(ClassicEngineBoot.computeVersionId(3, 8, 0)); // DebugReportRunner.createXmlPageable(masterReport); final LogicalPageBox box = DebugReportRunner.layoutPage(masterReport, 0); final RenderNode elementByName = MatchFactory.findElementByName(box, "outer-group"); assertEquals(StrictGeomUtility.toInternalValue(20), elementByName.getY()); // ModelPrinter.INSTANCE.print(box); // DebugReportRunner.showDialog(masterReport); }
public void alignCenter() { final long farLeftPostion = computeFarLeftPosition(); final long farRightPostion = computeFarRightPostion(); final long currentPageWidth = StrictGeomUtility.toInternalValue(currentPageDefinition.getWidth()); final long remainingRightSpace = currentPageWidth - farRightPostion; final long normalizedSpace = (farLeftPostion + remainingRightSpace) / 2; long requiredShift = normalizedSpace - farLeftPostion; if (remainingRightSpace > farLeftPostion) { // move to the Right requiredShift = Math.abs(requiredShift); } else { // move to the Left requiredShift = 0 - Math.abs(requiredShift); } final int shiftInPoints = (int) StrictGeomUtility.toExternalValue(requiredShift); align(shiftInPoints, visualElements); registerChanges(); }
@Test public void testBlockWithPrePostPad() throws Exception { final MasterReport report = new MasterReport(); report.setDataFactory(new TableDataFactory("query", new DefaultTableModel(10, 1))); report.setQuery("query"); final Band table = TableTestUtil.createTable(1, 1, 6, true); table.setName("table"); report.getReportHeader().addElement(TableTestUtil.createDataItem("Pre-Padding", 100, 10)); report.getReportHeader().addElement(table); report.getReportHeader().addElement(TableTestUtil.createDataItem("Post-Padding", 100, 10)); report.getReportHeader().setLayout("block"); PdfReportUtil.createPDF(report, "test-output/PRD-3857-output-block.pdf"); List<LogicalPageBox> pages = DebugReportRunner.layoutPages(report, 0, 1, 2); assertPageValid(pages, 0, StrictGeomUtility.toInternalValue(10)); assertPageValid(pages, 1); assertPageValid(pages, 2); // assertPageValid(report, 3); // assertPageValid(report, 4); }
public void testWeirdTocLayout() throws ReportProcessingException, ContentProcessingException { Element textField = new Element(); textField.setName("textField"); textField.getStyle().setStyleProperty(TextStyleKeys.FONT, "Arial"); textField.getStyle().setStyleProperty(TextStyleKeys.FONTSIZE, 14); textField.getStyle().setStyleProperty(TextStyleKeys.TEXT_WRAP, TextWrap.NONE); textField.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, 97f); textField.getStyle().setStyleProperty(ElementStyleKeys.MIN_HEIGHT, 20f); textField.getStyle().setStyleProperty(ElementStyleKeys.POS_X, 0f); textField.getStyle().setStyleProperty(ElementStyleKeys.POS_Y, 0f); textField.setElementType(LabelType.INSTANCE); textField.setAttribute( AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, "Classic Cars"); Element dotField = new Element(); dotField.setName("dotField"); dotField.getStyle().setStyleProperty(TextStyleKeys.FONT, "Arial"); dotField.getStyle().setStyleProperty(TextStyleKeys.FONTSIZE, 14); dotField.getStyle().setStyleProperty(ElementStyleKeys.ALIGNMENT, ElementAlignment.RIGHT); dotField.getStyle().setStyleProperty(ElementStyleKeys.VALIGNMENT, ElementAlignment.TOP); dotField.getStyle().setStyleProperty(ElementStyleKeys.POS_X, 97f); dotField.getStyle().setStyleProperty(ElementStyleKeys.POS_Y, 0f); dotField.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, 628.463f); dotField.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, 20f); dotField.getStyle().setStyleProperty(ElementStyleKeys.WIDTH, 100f); dotField.getStyle().setStyleProperty(ElementStyleKeys.MAX_WIDTH, 100f); dotField.setElementType(LabelType.INSTANCE); dotField.setAttribute( AttributeNames.Core.NAMESPACE, AttributeNames.Core.VALUE, " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + " . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . " + ". . . . . . . . . . . . . . . . . ."); Band band = new Band(); band.setName("outer-box"); band.setLayout("inline"); band.getStyle().setStyleProperty(ElementStyleKeys.BOX_SIZING, BoxSizing.CONTENT_BOX); band.getStyle().setStyleProperty(ElementStyleKeys.OVERFLOW_X, false); band.getStyle().setStyleProperty(ElementStyleKeys.OVERFLOW_Y, false); band.getStyle().setStyleProperty(TextStyleKeys.LINEHEIGHT, 1f); band.getStyle() .setStyleProperty(TextStyleKeys.WHITE_SPACE_COLLAPSE, WhitespaceCollapse.PRESERVE_BREAKS); band.getStyle().setStyleProperty(ElementStyleKeys.MIN_WIDTH, 708f); band.getStyle().setStyleProperty(ElementStyleKeys.MIN_HEIGHT, 12f); band.getStyle().setStyleProperty(ElementStyleKeys.MAX_HEIGHT, 20f); band.addElement(textField); band.addElement(dotField); final MasterReport report = new MasterReport(); report.getReportHeader().addElement(band); LogicalPageBox logicalPageBox = DebugReportRunner.layoutSingleBand(report, report.getReportHeader(), false, false); // ModelPrinter.INSTANCE.print(logicalPageBox); RenderBox outerBox = (RenderBox) MatchFactory.findElementByName(logicalPageBox, "outer-box"); RenderNode dotFieldBox = MatchFactory.findElementByName(logicalPageBox, "dotField"); RenderNode textFieldBox = MatchFactory.findElementByName(logicalPageBox, "textField"); assertNotNull(outerBox); assertNotNull(dotFieldBox); assertNotNull(textFieldBox); assertEquals(0, outerBox.getY()); assertEquals(0, dotFieldBox.getY()); assertEquals(0, textFieldBox.getY()); // box only contains one line, and min-size is set to 8, max size = 20, so the line-height of // 14.024 is used. assertEquals(StrictGeomUtility.toInternalValue(14.024), outerBox.getHeight()); assertEquals(StrictGeomUtility.toInternalValue(14.024), outerBox.getFirstChild().getHeight()); assertEquals(StrictGeomUtility.toInternalValue(14), dotFieldBox.getHeight()); assertEquals(StrictGeomUtility.toInternalValue(14), textFieldBox.getHeight()); }
public void update(final Point2D normalizedPoint, final double zoomFactor) { final SnapPositionsModel horizontalSnapModel = getHorizontalSnapModel(); final Element[] selectedVisualElements = getSelectedVisualElements(); final long originPointX = getOriginPointX(); final long[] elementWidth = getElementWidth(); final long px = StrictGeomUtility.toInternalValue(normalizedPoint.getX()); final long dx = px - originPointX; for (int i = 0; i < selectedVisualElements.length; i++) { final Element element = selectedVisualElements[i]; if (element instanceof RootLevelBand) { continue; } final ElementStyleSheet styleSheet = element.getStyle(); final double elementMinWidth = styleSheet.getDoubleStyleProperty(ElementStyleKeys.MIN_WIDTH, 0); // this is where I want the element on a global scale... final long targetWidth = elementWidth[i] + dx; final CachedLayoutData data = ModelUtility.getCachedLayoutData(element); final long elementX = data.getX(); final long targetX2 = elementX + targetWidth; if (elementMinWidth >= 0) { // absolute position; resolving is easy here final long snapPosition = horizontalSnapModel.getNearestSnapPosition(targetX2, element.getObjectID()); if (Math.abs(snapPosition - targetX2) > snapThreshold) { final long localWidth = Math.max(0, targetX2 - elementX); final float position = (float) StrictGeomUtility.toExternalValue(localWidth); styleSheet.setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(position)); } else { final long localWidth = Math.max(0, snapPosition - elementX); final float position = (float) StrictGeomUtility.toExternalValue(localWidth); styleSheet.setStyleProperty(ElementStyleKeys.MIN_WIDTH, new Float(position)); } } else { final Element parent = element.getParentSection(); final CachedLayoutData parentData = ModelUtility.getCachedLayoutData(parent); final long parentBase = parentData.getWidth(); if (parentBase > 0) { // relative position; resolve the percentage against the height of the parent. final long snapPosition = horizontalSnapModel.getNearestSnapPosition(targetX2, element.getObjectID()); if (Math.abs(snapPosition - targetX2) > snapThreshold) { final long localWidth = Math.max(0, targetX2 - elementX); // strict geometry: all values are multiplied by 1000 // percentages in the engine are represented by floats betwen 0 and 100. final long percentage = StrictGeomUtility.toInternalValue(localWidth * 100 / parentBase); styleSheet.setStyleProperty( ElementStyleKeys.MIN_WIDTH, new Float(StrictGeomUtility.toExternalValue(-percentage))); } else { final long localWidth = Math.max(0, snapPosition - elementX); // strict geometry: all values are multiplied by 1000 // percentages in the engine are represented by floats betwen 0 and 100. final long percentage = StrictGeomUtility.toInternalValue(localWidth * 100 / parentBase); styleSheet.setStyleProperty( ElementStyleKeys.MIN_WIDTH, new Float(StrictGeomUtility.toExternalValue(-percentage))); } } } element.notifyNodePropertiesChanged(); } }
static { final long value = StrictGeomUtility.toInternalValue(1); conversionFactor = value / org.pentaho.reporting.libraries.fonts.tools.StrictGeomUtility.toInternalValue(1); }
/** * Another static processing step which validates the table structure and computes the cell * positions within the table. * * @author Thomas Morgner */ public class TableValidationStep extends IterateStructuralProcessStep { private static final long MAX_AUTO = StrictGeomUtility.toInternalValue(0x80000000000L); private static class TableInfoStructure { private TableRenderBox table; private TableInfoStructure parent; private TableColumnModel columnModel; private TableSectionRenderBox sectionRenderBox; private IntList rowSpans; private TableRowModel rowModel; protected int tableCellPosition; protected int rowCount; private boolean bodySection; public TableInfoStructure(final TableRenderBox table, final TableInfoStructure parent) { this.table = table; this.parent = parent; this.columnModel = table.getColumnModel(); this.rowSpans = new IntList(10); } public void resetCellPosition() { this.tableCellPosition = 0; } private boolean isCellAreaClear(final int pos, final int colSpan) { final int maxIdx = Math.min(pos + colSpan, rowSpans.size()); for (int i = pos; i < maxIdx; i++) { if (rowSpans.get(tableCellPosition) > 0) { return false; } } return true; } public int increaseCellPosition(final int colSpan, final int rowSpan) { // find insert-position for the cell. This skips cells that block the location via a row-span. while (true) { // we are past the point of defined cells. Adding new cells is guaranteed to not have // row-spans. if (tableCellPosition >= rowSpans.size()) { break; } if (isCellAreaClear(tableCellPosition, colSpan)) { break; } tableCellPosition += 1; } final int retval = tableCellPosition; // set the cell... for (int i = tableCellPosition; i < tableCellPosition + colSpan; i++) { if (i < rowSpans.size()) { rowSpans.set(i, Math.max(rowSpan, rowSpans.get(i))); } else { rowSpans.add(rowSpan); } } tableCellPosition += colSpan; return retval; } public TableInfoStructure pop() { return parent; } public TableSectionRenderBox getSectionRenderBox() { return sectionRenderBox; } public void setSectionRenderBox(final TableSectionRenderBox sectionRenderBox) { this.rowSpans.clear(); this.sectionRenderBox = sectionRenderBox; if (this.sectionRenderBox != null) { this.rowModel = sectionRenderBox.getRowModel(); this.bodySection = (sectionRenderBox.getDisplayRole() == TableSectionRenderBox.Role.BODY); } else { this.rowModel = null; this.bodySection = false; } this.rowCount = -1; } public boolean isBodySection() { return bodySection; } public TableRenderBox getTable() { return table; } public TableColumnModel getColumnModel() { return columnModel; } public void updateDefinedSize(final int rowSpan, final long preferredSize) { rowModel.updateDefinedSize(rowCount, rowSpan, preferredSize); } } private TableInfoStructure currentTable; private TableColumnGroup currentColumnGroup; public TableValidationStep() {} public void validate(final LogicalPageBox box) { currentTable = null; startProcessing(box); if (currentTable != null) { throw new IllegalStateException(); } } private boolean abortIfNoTable(final RenderBox box) { if (box.getTableRefCount() == 0) { return false; } if (box.getTableValidationAge() == box.getChangeTracker()) { return false; } box.setTableValidationAge(box.getChangeTracker()); return true; } protected boolean startCanvasBox(final CanvasRenderBox box) { return abortIfNoTable(box); } protected boolean startBlockBox(final BlockRenderBox box) { return abortIfNoTable(box); } protected boolean startInlineBox(final InlineRenderBox box) { return abortIfNoTable(box); } protected boolean startOtherBox(final RenderBox box) { return abortIfNoTable(box); } protected boolean startRowBox(final RenderBox box) { return abortIfNoTable(box); } protected boolean startAutoBox(final RenderBox box) { if (currentTable != null) { return true; } return abortIfNoTable(box); } protected boolean startTableBox(final TableRenderBox table) { final long changeTracker = table.getChangeTracker(); final long age = table.getTableValidationAge(); if (changeTracker == age) { return false; } currentTable = new TableInfoStructure(table, currentTable); return true; } protected void finishTableBox(final TableRenderBox table) { final long changeTracker = table.getChangeTracker(); final long age = table.getTableValidationAge(); if (changeTracker == age) { return; } // currentTable.columnModel.validateSizes(table); table.setTableValidationAge(age); table.setPredefinedColumnsValidated(true); currentTable = currentTable.pop(); } protected boolean startTableColumnGroupBox(final TableColumnGroupNode box) { if (currentTable == null) { return false; } if (currentTable.table.isPredefinedColumnsValidated()) { return false; } currentColumnGroup = new TableColumnGroup(box.getBoxDefinition().getBorder()); currentColumnGroup.setColSpan(box.getColSpan()); return true; } protected void processTableColumn(final TableColumnNode node) { if (currentTable == null) { return; } if (currentTable.table.isPredefinedColumnsValidated()) { return; } final Border border = node.getBoxDefinition().getBorder(); final RenderLength length = node.getBoxDefinition().getMinimumWidth(); if (currentColumnGroup != null) { currentColumnGroup.addColumn(new TableColumn(border, length, false)); } else { final TableColumnGroup currentColumnGroup = new TableColumnGroup(BoxDefinition.EMPTY.getBorder()); currentColumnGroup.addColumn(new TableColumn(border, length, false)); currentTable.columnModel.addColumnGroup(currentColumnGroup); } } protected void finishTableColumnGroupBox(final TableColumnGroupNode box) { if (currentTable == null) { return; } if (currentTable.table.isPredefinedColumnsValidated()) { return; } while (currentColumnGroup.getColumnCount() < box.getColSpan()) { currentColumnGroup.addColumn( new TableColumn(currentColumnGroup.getBorder(), RenderLength.AUTO, false)); } currentTable.columnModel.addColumnGroup(currentColumnGroup); currentColumnGroup = null; } protected boolean startTableSectionBox(final TableSectionRenderBox box) { if (currentTable == null) { return false; } if (currentTable.getSectionRenderBox() != null) { return true; } currentTable.setSectionRenderBox(box); box.getRowModel().initialize(currentTable.getTable()); return true; } protected void finishTableSectionBox(final TableSectionRenderBox box) { if (currentTable == null) { return; } if (currentTable.getSectionRenderBox() != box) { return; } final IntList rowSpans = currentTable.rowSpans; int missingRows = 0; for (int i = 0; i < rowSpans.size(); i++) { final int value = rowSpans.get(i); if (missingRows < value) { missingRows = value; } } for (int i = 0; i < missingRows; i += 1) { currentTable.rowModel.addRow(); } box.getRowModel().validateSizes(box); currentTable.setSectionRenderBox(null); } protected boolean startTableRowBox(final TableRowRenderBox box) { if (currentTable == null) { return false; } if (currentTable.getSectionRenderBox() == null) { return false; } currentTable.resetCellPosition(); box.setBodySection(currentTable.isBodySection()); // check if this is the first row ... if (currentTable.rowCount == -1) { if (box.getRowIndex() != -1) { currentTable.rowCount = box.getRowIndex(); return true; } } currentTable.rowCount += 1; box.setRowIndex(currentTable.rowCount); if (currentTable.rowCount <= currentTable.rowModel.getRowCount()) { currentTable.rowModel.addRow(); } return true; } protected void finishTableRowBox(final TableRowRenderBox box) { if (currentTable == null) { return; } if (currentTable.getSectionRenderBox() == null) { return; } final IntList rowSpans = currentTable.rowSpans; int maxRowSpan = 0; for (int i = 0; i < rowSpans.size(); i++) { final int value = rowSpans.get(i); maxRowSpan = Math.max(maxRowSpan, value); } for (int i = 0; i < rowSpans.size(); i++) { final int value = rowSpans.get(i); rowSpans.set(i, Math.max(0, value - 1)); } } protected boolean startTableCellBox(final TableCellRenderBox box) { if (currentTable == null) { return false; } if (currentTable.getSectionRenderBox() == null) { return false; } final int rowSpan = box.getRowSpan(); final int colSpan = box.getColSpan(); final int startPos = currentTable.increaseCellPosition(colSpan, rowSpan); while (currentTable.columnModel.getColumnCount() <= startPos) { currentTable.columnModel.addAutoColumn(); } box.setColumnIndex(startPos); box.setBodySection(currentTable.isBodySection()); final BoxDefinition boxDefinition = box.getBoxDefinition(); final long preferredHeight = boxDefinition.getPreferredHeight().resolve(0); final long minHeight = boxDefinition.getMinimumHeight().resolve(0); final long maxHeight = boxDefinition.getMaximumHeight().resolve(0, MAX_AUTO); final long preferredSize = ProcessUtility.computeLength(minHeight, maxHeight, preferredHeight); currentTable.updateDefinedSize(rowSpan, preferredSize); return true; } }