/*!
* 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) 2002-2013 Pentaho Corporation.. All rights reserved.
*/
package org.pentaho.reporting.designer.core.editor.report;
import org.pentaho.reporting.designer.core.model.ModelUtility;
import org.pentaho.reporting.designer.core.settings.WorkspaceSettings;
import org.pentaho.reporting.engine.classic.core.PageFooter;
import org.pentaho.reporting.engine.classic.core.PageHeader;
import org.pentaho.reporting.engine.classic.core.RootLevelBand;
import org.pentaho.reporting.engine.classic.core.Section;
import org.pentaho.reporting.engine.classic.core.SubReport;
import org.pentaho.reporting.engine.classic.core.Watermark;
import org.pentaho.reporting.engine.classic.core.layout.model.BlockRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.CanvasRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.InlineRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.LayoutNodeTypes;
import org.pentaho.reporting.engine.classic.core.layout.model.LogicalPageBox;
import org.pentaho.reporting.engine.classic.core.layout.model.ParagraphRenderBox;
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.RenderableReplacedContentBox;
import org.pentaho.reporting.engine.classic.core.layout.model.WatermarkAreaBox;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableCellRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableRowRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.model.table.TableSectionRenderBox;
import org.pentaho.reporting.engine.classic.core.layout.output.OutputProcessorMetaData;
import org.pentaho.reporting.engine.classic.core.modules.output.pageable.graphics.internal.LogicalPageDrawable;
import org.pentaho.reporting.engine.classic.core.util.InstanceID;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictBounds;
import org.pentaho.reporting.engine.classic.core.util.geom.StrictGeomUtility;
import org.pentaho.reporting.libraries.resourceloader.ResourceManager;
import java.awt.*;
import java.awt.geom.Rectangle2D;
import java.util.HashSet;
public class DesignerPageDrawable extends LogicalPageDrawable {
private enum SectionSubType {
NORMALFLOW, WATERMARK, HEADER, FOOTER
}
private DesignerCollectSelectedNodesStep collectSelectedNodesStep;
private StrictBounds rootElementBounds;
private HashSet<InstanceID> rootElementIds;
private boolean insideRenderedElement;
private SectionSubType subType;
private HashSet<InstanceID> renderableParents;
public DesignerPageDrawable( final LogicalPageBox rootBox,
final OutputProcessorMetaData metaData,
final ResourceManager resourceManager,
final Section section ) {
init( rootBox, metaData, resourceManager );
setDrawPageBackground( false );
rootElementIds = new HashSet<InstanceID>();
rootElementIds.add( section.getObjectID() );
subType = determineSubType( section );
if ( section instanceof RootLevelBand ) {
final RootLevelBand rlb = (RootLevelBand) section;
final SubReport[] subReports = rlb.getSubReports();
for ( int i = 0; i < subReports.length; i++ ) {
final SubReport subReport = subReports[ i ];
rootElementIds.add( subReport.getObjectID() );
}
}
renderableParents = new HashSet<InstanceID>();
Section parent = section.getParentSection();
while ( parent != null ) {
renderableParents.add( parent.getObjectID() );
parent = parent.getParentSection();
}
final SelectLayoutNodes layoutNodes = new SelectLayoutNodes();
this.rootElementBounds = layoutNodes.select( rootElementIds, rootBox, section );
collectSelectedNodesStep = new DesignerCollectSelectedNodesStep();
collectSelectedNodesStep.setRootNodes( rootElementIds );
}
private SectionSubType determineSubType( final Section s ) {
if ( s.getReportDefinition() != s.getMasterReport() ) {
return SectionSubType.NORMALFLOW;
}
if ( s instanceof Watermark ) {
return SectionSubType.WATERMARK;
}
if ( s instanceof PageFooter ) {
return SectionSubType.FOOTER;
}
if ( s instanceof PageHeader ) {
return SectionSubType.HEADER;
}
return SectionSubType.NORMALFLOW;
}
public StrictBounds getRootElementBounds() {
return rootElementBounds;
}
/**
* Draws the object.
*
* @param g2 the graphics device.
* @param area the area inside which the object should be drawn. This is the clipping area for the page.
*/
public void draw( final Graphics2D g2, final Rectangle2D area ) {
setOutlineMode( WorkspaceSettings.getInstance().isAlwaysDrawElementFrames() );
super.draw( g2, area );
}
protected void processRootBand( final StrictBounds pageBounds ) {
if ( subType == SectionSubType.WATERMARK ) {
final WatermarkAreaBox box = getRootBox().getWatermarkArea();
setDrawArea( new StrictBounds( box.getX(), box.getY(), box.getWidth(), box.getHeight() ) );
getGraphics().clip( createClipRect( getDrawArea() ) );
startProcessing( box );
} else if ( subType == SectionSubType.HEADER ) {
final BlockRenderBox box = getRootBox().getHeaderArea();
setDrawArea( new StrictBounds( box.getX(), box.getY(), box.getWidth(), box.getHeight() ) );
getGraphics().clip( createClipRect( getDrawArea() ) );
startProcessing( box );
} else if ( subType == SectionSubType.FOOTER ) {
final BlockRenderBox box = getRootBox().getFooterArea();
setDrawArea( new StrictBounds( box.getX(), box.getY(), box.getWidth(), box.getHeight() ) );
getGraphics().clip( createClipRect( getDrawArea() ) );
startProcessing( box );
} else {
final RenderBox box = getRootBox();
setDrawArea( new StrictBounds( box.getX(), box.getY(), box.getWidth(), box.getHeight() ) );
getGraphics().clip( createClipRect( getDrawArea() ) );
processBoxChilds( getRootBox() );
}
}
private boolean isValidDrawTarget( RenderNode node ) {
if ( renderableParents.contains( node.getInstanceId() ) ) {
return true;
}
while ( node != null ) {
if ( rootElementIds.contains( node.getInstanceId() ) ) {
return true;
}
node = node.getParent();
}
return false;
}
protected boolean startBox( final RenderBox box ) {
if ( box.getLayoutNodeType() != LayoutNodeTypes.TYPE_BOX_LOGICALPAGE ) {
final StrictBounds bounds = new StrictBounds( box.getX(), box.getY(), box.getWidth(), box.getHeight() );
if ( StrictBounds.intersects( rootElementBounds, bounds ) == false ) {
return false;
}
}
return super.startBox( box );
}
private void finishBox( final RenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = false;
}
}
public boolean startCanvasBox( final CanvasRenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startCanvasBox( box );
}
protected void finishCanvasBox( final CanvasRenderBox box ) {
finishBox( box );
}
protected boolean startBlockBox( final BlockRenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startBlockBox( box );
}
protected void finishBlockBox( final BlockRenderBox box ) {
finishBox( box );
}
protected boolean startRowBox( final RenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startRowBox( box );
}
protected void finishRowBox( final RenderBox box ) {
finishBox( box );
}
protected boolean startInlineBox( final InlineRenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startInlineBox( box );
}
protected void finishInlineBox( final InlineRenderBox box ) {
finishBox( box );
}
protected boolean startTableCellBox( final TableCellRenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startTableCellBox( box );
}
protected void finishTableCellBox( final TableCellRenderBox box ) {
finishBox( box );
}
protected boolean startTableRowBox( final TableRowRenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startTableRowBox( box );
}
protected void finishTableRowBox( final TableRowRenderBox box ) {
finishBox( box );
}
protected boolean startTableSectionBox( final TableSectionRenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startTableSectionBox( box );
}
protected void finishTableSectionBox( final TableSectionRenderBox box ) {
finishBox( box );
}
protected boolean startTableBox( final TableRenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startTableBox( box );
}
protected void finishTableBox( final TableRenderBox box ) {
finishBox( box );
}
protected boolean startOtherBox( final RenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startOtherBox( box );
}
protected void finishOtherBox( final RenderBox box ) {
finishBox( box );
}
protected boolean startAutoBox( final RenderBox box ) {
if ( rootElementIds.contains( box.getInstanceId() ) ) {
insideRenderedElement = true;
}
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return false;
}
if ( isValidDrawTarget( box ) == false ) {
return true;
}
return super.startAutoBox( box );
}
protected void finishAutoBox( final RenderBox box ) {
finishBox( box );
}
protected void processOtherNode( final RenderNode node ) {
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( node ) ) {
return;
}
if ( isValidDrawTarget( node ) == false ) {
return;
}
super.processOtherNode( node );
}
protected void processRenderableContent( final RenderableReplacedContentBox box ) {
if ( insideRenderedElement && ModelUtility.isHideInLayoutGui( box ) ) {
return;
}
if ( isValidDrawTarget( box ) == false ) {
return;
}
super.processRenderableContent( box );
}
protected void processParagraphChilds( final ParagraphRenderBox box ) {
if ( box.getFirstChild() == null ) {
if ( box.getPoolSize() > 0 ) {
final Graphics2D graphics1 = getGraphics();
graphics1.setFont( new Font( "Serif", Font.PLAIN, 10 ) ); // NON-NLS
graphics1.drawString( "Your box is too small ...", // NON-NLS : TODO _ Change the way we handle this case
(int) StrictGeomUtility.toExternalValue( box.getX() ),
(int) StrictGeomUtility.toExternalValue( box.getY() ) + 10 );
}
} else {
super.processParagraphChilds( box );
}
}
/**
* Retries the nodes under the given coordinate which have a given attribute set. If name and namespace are null, all
* nodes are returned. The nodes returned are listed in their respective hierarchical order.
*
* @param x the x coordinate
* @param y the y coordinate
* @param namespace the namespace on which to filter on
* @param name the name on which to filter on
* @return the ordered list of nodes.
*/
public RenderNode[] getNodesAt( final double x, final double y, final String namespace, final String name ) {
return collectSelectedNodesStep.getNodesAt
( getRootBox(), StrictGeomUtility.createBounds( x, y, 1, 1 ), namespace, name );
}
public RenderNode[] getNodesAt( final double x,
final double y,
final double width,
final double height,
final String namespace,
final String name ) {
return collectSelectedNodesStep.getNodesAt
( getRootBox(), StrictGeomUtility.createBounds( x, y, width, height ), namespace, name );
}
protected boolean isIgnoreBorderWhenDrawingOutline() {
return true;
}
protected void drawOutlineBox( final Graphics2D g2, final RenderBox box ) {
if ( box.getNodeType() == LayoutNodeTypes.TYPE_BOX_LINEBOX ) {
return;
} else {
g2.setPaint( Color.lightGray );
}
final double x = StrictGeomUtility.toExternalValue( box.getX() );
final double y = StrictGeomUtility.toExternalValue( box.getY() );
final double w = StrictGeomUtility.toExternalValue( box.getWidth() );
final double h = StrictGeomUtility.toExternalValue( box.getHeight() );
final Rectangle2D boxArea = getBoxArea();
boxArea.setFrame( x, y, w, h );
g2.draw( boxArea );
}
}