/* * This program is free software; you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License, version 2.1 as published by the Free Software * Foundation. * * You should have received a copy of the GNU Lesser General Public License along with this * program; if not, you can obtain a copy at http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html * or from the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * Copyright (c) 2001 - 2013 Object Refinery Ltd, Pentaho Corporation and Contributors.. All rights reserved. */ package org.pentaho.reporting.engine.classic.core.layout.process.alignment; import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes; import org.pentaho.reporting.engine.classic.core.layout.model.RenderBox; import org.pentaho.reporting.engine.classic.core.layout.model.RenderNode; import org.pentaho.reporting.engine.classic.core.layout.model.SplittableRenderNode; import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.InlineBoxSequenceElement; import org.pentaho.reporting.engine.classic.core.layout.process.layoutrules.InlineSequenceElement; /** * Right alignment strategy. Not working yet, as this is unimplemented right now. * * @author Thomas Morgner */ public final class RightAlignmentProcessor extends AbstractAlignmentProcessor { public RightAlignmentProcessor() { } /** * Handle the next input chunk. * * @param start * the start index * @param count * the number of elements in the sequence * @return the index of the last element that will fit on the current line. */ protected int handleElement( final int start, final int count ) { final RenderNode[] nodes = getNodes(); final InlineSequenceElement[] sequenceElements = getSequenceElements(); final long[] elementDimensions = getElementDimensions(); final long[] elementPositions = getElementPositions(); // if we reached that method, then this means, that the elements may fit // into the available space. (Assuming that there is no inner pagebreak; // a thing we do not handle yet) final int endIndex = start + count; long usedWidth = 0; int contentIndex = start; InlineSequenceElement contentElement = null; for ( int i = 0; i < endIndex; i++ ) { final InlineSequenceElement element = sequenceElements[i]; final RenderNode node = nodes[i]; usedWidth += element.getMaximumWidth( node ); if ( isBorderMarker( element ) ) { continue; } contentElement = element; contentIndex = i; } final long nextPosition = ( getStartOfLine() + usedWidth ); final long lastPageBreak = getPageBreak( getPagebreakCount() - 1 ); if ( nextPosition > lastPageBreak ) { // The contents we processed so far will not fit on the current line. That's dangerous. // We have to right align the content up to the element denoted with 'start'. // Ignore the retval, we know that it fits (or at least that it is correct some how ..) rightAlign( start, sequenceElements, nodes, elementPositions, elementDimensions ); // we cross a pagebreak. Stop working on it - we bail out here. if ( nodes[contentIndex] instanceof SplittableRenderNode ) { // the element may be splittable. Test, and if so, give a hint to the // outside world .. setSkipIndex( endIndex ); setBreakableIndex( contentIndex ); setBreakableMaxAllowedWidth( nextPosition - lastPageBreak ); return ( start ); } // This is the first element and it still does not fit. How evil. if ( start == 0 ) { if ( contentElement instanceof InlineBoxSequenceElement ) { final RenderNode node = nodes[contentIndex]; if ( ( node.getNodeType() & LayoutNodeTypes.MASK_BOX ) == LayoutNodeTypes.MASK_BOX ) { // OK, limit the size of the box to the maximum line width and // revalidate it. final long contentPosition = elementPositions[contentIndex]; final RenderBox box = (RenderBox) node; final long maxWidth = ( getEndOfLine() - contentPosition ); computeInlineBlock( box, contentPosition, maxWidth ); elementDimensions[endIndex - 1] = node.getCachedWidth(); } } setSkipIndex( endIndex ); } return ( start ); } // This implementation does not handle inline-block elements correctly. // but for the classic engine, this is less important, as we do not allow them anyway. if ( rightAlign( endIndex, sequenceElements, nodes, elementPositions, elementDimensions ) ) { return endIndex; } return start; } private boolean rightAlign( final int endIndex, final InlineSequenceElement[] sequenceElements, final RenderNode[] nodes, final long[] elementPositions, final long[] elementDimensions ) { // iterate backwards .. // The left-edge. This one is fixed; crossing this edge will be punished .. final long startOfLine = getStartOfLine(); // the current segment. int segment = getPagebreakCount() - 1; long endPosition = getEndOfLine(); long segmentStart = getStartOfSegment( segment ); for ( int i = endIndex - 1; i >= 0; i-- ) { final InlineSequenceElement element = sequenceElements[i]; final long elementWidth = element.getMaximumWidth( nodes[i] ); long elementStart = endPosition - elementWidth; if ( elementStart < startOfLine ) { // this element will not fit. Skip it. return false; } while ( segment > 0 && elementStart < segmentStart ) { // the element will not fit into the current segment. Move it to the next segment. elementStart = segmentStart - elementWidth; segment -= 1; segmentStart = getStartOfSegment( segment ); } if ( elementStart < segmentStart ) { // the element will not fit into any of the remaining segments. So skip it. return false; } elementPositions[i] = elementStart; elementDimensions[i] = elementWidth; endPosition = elementStart; } return true; } private long getStartOfSegment( final int segment ) { if ( segment == 0 ) { return getStartOfLine(); } return getPageBreak( segment - 1 ); } }