/*!
* 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 java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import java.util.HashSet;
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;
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);
}
}