using System;
using System.Collections.Generic;
namespace FastReport.Engine
{
public partial class ReportEngine
{
#region Fields
private BandBase outputBand;
#endregion Fields
#region Private Methods
private void PrepareBand(BandBase band, bool getData)
{
if (band.Visible)
{
if (getData)
{
band.GetData();
}
TranslateObjects(band);
RenderInnerSubreports(band);
band.CalcHeight();
}
}
private float CalcHeight(BandBase band)
{
// band is already prepared, its Height is ready to use
if (band.IsRunning)
return band.Height;
band.SaveState();
try
{
PrepareBand(band, true);
return band.Height;
}
finally
{
band.RestoreState();
}
}
private BandBase CloneBand(BandBase band)
{
// clone a band and all its objects
BandBase cloneBand = Activator.CreateInstance(band.GetType()) as BandBase;
cloneBand.Assign(band);
cloneBand.SetReport(Report);
cloneBand.SetRunning(true);
foreach (ReportComponentBase obj in band.Objects)
{
ReportComponentBase cloneObj = Activator.CreateInstance(obj.GetType()) as ReportComponentBase;
cloneObj.AssignAll(obj);
cloneBand.Objects.Add(cloneObj);
}
return cloneBand;
}
private void AddToOutputBand(BandBase band, bool getData)
{
band.SaveState();
try
{
PrepareBand(band, getData);
if (band.Visible)
{
outputBand.SetRunning(true);
BandBase cloneBand = CloneBand(band);
cloneBand.Left = CurX;
cloneBand.Top = CurY;
cloneBand.Parent = outputBand;
CurY += cloneBand.Height;
}
}
finally
{
band.RestoreState();
}
}
private void ShowBandToPreparedPages(BandBase band, bool getData)
{
// handle "StartNewPage". Skip if it's the first row, avoid empty first page.
if ((band.StartNewPage && !(band.Parent is PageHeaderBand || band.Parent is PageFooterBand)) && band.FlagUseStartNewPage && (band.RowNo != 1 || band.FirstRowStartsNewPage) &&
!band.Repeated)
{
EndColumn();
}
band.SaveState();
try
{
PrepareBand(band, getData);
if (band.Visible)
{
if (BandHasHardPageBreaks(band))
{
foreach (var b in SplitHardPageBreaks(band))
{
if (b.StartNewPage)
EndColumn();
AddToPreparedPages(b);
}
}
else
{
AddToPreparedPages(band);
}
}
}
finally
{
band.RestoreState();
}
}
private void ShowBand(BandBase band, BandBase outputBand, float offsetX, float offsetY)
{
float saveCurX = CurX;
float saveCurY = CurY;
BandBase saveOutputBand = this.outputBand;
CurX = offsetX;
CurY = offsetY;
try
{
this.outputBand = outputBand;
ShowBand(band);
}
finally
{
this.outputBand = saveOutputBand;
CurX = saveCurX;
CurY = saveCurY;
}
}
///
/// Shows band at the current position.
///
/// Band to show.
///
/// After the band is shown, the current position is advanced by the band's height.
///
public void ShowBand(BandBase band)
{
if (band != null)
for (int i = 0; i < band.RepeatBandNTimes; i++)
ShowBand(band, true);
}
private void ShowBand(BandBase band, bool getData)
{
if (band == null)
return;
BandBase saveCurBand = curBand;
curBand = band;
try
{
// do we need to keep child?
ChildBand child = band.Child;
bool showChild = child != null && !(band is DataBand && child.CompleteToNRows > 0) && !child.FillUnusedSpace &&
!(band is DataBand && child.PrintIfDatabandEmpty);
if (showChild && band.KeepChild)
{
StartKeep(band);
}
if (outputBand != null)
{
AddToOutputBand(band, getData);
}
else
{
ShowBandToPreparedPages(band, getData);
}
ProcessTotals(band);
if (band.Visible)
{
RenderOuterSubreports(band);
}
// show child band. Skip if child is used to fill empty space: it was processed already
if (showChild)
{
ShowBand(child);
if (band.KeepChild)
{
EndKeep();
}
}
}
finally
{
curBand = saveCurBand;
}
}
private void ProcessTotals(BandBase band)
{
Report.Dictionary.Totals.ProcessBand(band);
}
#endregion Private Methods
#region Internal Methods
internal bool CanPrint(ReportComponentBase obj)
{
// Apply visible expression if needed.
if (!String.IsNullOrEmpty(obj.VisibleExpression))
{
object expression = null;
// Calculate expressions with TotalPages only on FinalPass.
if (!obj.VisibleExpression.Contains("TotalPages") || (Report.DoublePass && FinalPass))
{
expression = Report.Calc(Code.CodeUtils.FixExpressionWithBrackets(obj.VisibleExpression));
}
if (expression != null && expression is bool)
{
if (!obj.VisibleExpression.Contains("TotalPages"))
{
obj.Visible = (bool)expression;
}
else if (FirstPass)
{
obj.Visible = true;
}
else
{
obj.Visible = (bool)expression;
}
}
}
// Apply exportable expression if needed.
if (!String.IsNullOrEmpty(obj.ExportableExpression))
{
object expression = null;
expression = Report.Calc(Code.CodeUtils.FixExpressionWithBrackets(obj.ExportableExpression));
if (expression is bool)
{
obj.Exportable = (bool)expression;
}
}
// Apply printable expression if needed.
if (!String.IsNullOrEmpty(obj.PrintableExpression))
{
object expression = null;
expression = Report.Calc(Code.CodeUtils.FixExpressionWithBrackets(obj.PrintableExpression));
if (expression is bool)
{
obj.Printable = (bool)expression;
}
}
if (!obj.Visible || !obj.FlagPreviewVisible)
{
return false;
}
bool isFirstPage = CurPage == firstReportPage;
bool isLastPage = CurPage == TotalPages - 1;
bool isRepeated = obj.Band != null && obj.Band.Repeated;
bool canPrint = false;
if ((obj.PrintOn & PrintOn.OddPages) > 0 && CurPage % 2 == 1)
{
canPrint = true;
}
if ((obj.PrintOn & PrintOn.EvenPages) > 0 && CurPage % 2 == 0)
{
canPrint = true;
}
if (isLastPage)
{
if ((obj.PrintOn & PrintOn.LastPage) == 0)
{
canPrint = false;
}
if (obj.PrintOn == PrintOn.LastPage || obj.PrintOn == (PrintOn.LastPage | PrintOn.SinglePage) ||
obj.PrintOn == (PrintOn.FirstPage | PrintOn.LastPage))
{
canPrint = true;
}
}
if (isFirstPage)
{
if ((obj.PrintOn & PrintOn.FirstPage) == 0)
{
canPrint = false;
}
if (obj.PrintOn == PrintOn.FirstPage || obj.PrintOn == (PrintOn.FirstPage | PrintOn.SinglePage) ||
obj.PrintOn == (PrintOn.FirstPage | PrintOn.LastPage))
{
canPrint = true;
}
}
if (isFirstPage && isLastPage)
{
canPrint = (obj.PrintOn & PrintOn.SinglePage) > 0;
}
if (isRepeated)
{
canPrint = (obj.PrintOn & PrintOn.RepeatedBand) > 0;
}
return canPrint;
}
internal void AddToPreparedPages(BandBase band)
{
bool isReportSummary = band is ReportSummaryBand;
// check if band is service band (e.g. page header/footer/overlay).
BandBase mainBand = band;
// for child bands, check its parent band.
if (band is ChildBand)
{
mainBand = (band as ChildBand).GetTopParentBand;
}
bool isPageBand = mainBand is PageHeaderBand || mainBand is PageFooterBand || mainBand is OverlayBand;
bool isColumnBand = mainBand is ColumnHeaderBand || mainBand is ColumnFooterBand;
// check if we have enough space for a band.
bool checkFreeSpace = !isPageBand && !isColumnBand && band.FlagCheckFreeSpace;
if (checkFreeSpace && FreeSpace < band.Height)
{
// we don't have enough space. What should we do?
// - if band can break, break it
// - if band cannot break, check the band height:
// - it's the first row of a band and is bigger than page: break it immediately.
// - in other case, add a new page/column and tell the band that it must break next time.
if (band.CanBreak || band.FlagMustBreak || (band.AbsRowNo == 1 && band.Height > PageHeight - PageFooterHeight))
{
// since we don't show the column footer band in the EndLastPage, do it here.
if (isReportSummary)
{
ShowReprintFooters();
ShowBand(page.ColumnFooter);
}
BreakBand(band);
return;
}
else
{
EndColumn();
band.FlagMustBreak = true;
AddToPreparedPages(band);
band.FlagMustBreak = false;
return;
}
}
else
{
// since we don't show the column footer band in the EndLastPage, do it here.
if (isReportSummary)
{
if ((band as ReportSummaryBand).KeepWithData)
{
EndKeep();
}
ShowReprintFooters(false);
ShowBand(page.ColumnFooter);
}
}
// check if we have a child band with FillUnusedSpace flag
if (band.Child != null && band.Child.FillUnusedSpace)
{
// if we reprint a data/group footer, do not include the band height into calculation:
// it is already counted in FreeSpace
float bandHeight = band.Height;
if (band.Repeated)
{
bandHeight = 0;
}
while (FreeSpace - bandHeight - band.Child.Height >= 0)
{
float saveCurY = CurY;
ShowBand(band.Child);
// nothing was printed, break to avoid an endless loop
if (CurY == saveCurY)
{
break;
}
}
}
// adjust the band location
if (band is PageFooterBand && !UnlimitedHeight)
{
CurY = PageHeight - GetBandHeightWithChildren(band);
}
if (!isPageBand)
{
band.Left += originX + CurX;
}
if (band.PrintOnBottom)
{
CurY = PageHeight - PageFooterHeight - ColumnFooterHeight;
// if PrintOnBottom is applied to a band like DataFooter, print it with all its child bands
// if PrintOnBottom is applied to a child band, print this band only.
if (band is ChildBand)
{
CurY -= band.Height;
}
else
{
CurY -= GetBandHeightWithChildren(band);
}
}
band.Top = CurY;
// shift the band and decrease its width when printing hierarchy
float saveLeft = band.Left;
float saveWidth = band.Width;
if (!isPageBand && !isColumnBand)
{
band.Left += hierarchyIndent;
band.Width -= hierarchyIndent;
}
// add outline
AddBandOutline(band);
// add bookmarks
band.AddBookmarks();
// put the band to prepared pages. Do not put page bands twice
// (this may happen when we render a subreport, or append a report to another one).
bool bandAdded = true;
bool bandAlreadyExists = false;
if (isPageBand)
{
if (band is ChildBand)
{
bandAlreadyExists = PreparedPages.ContainsBand(band.Name);
}
else
{
bandAlreadyExists = PreparedPages.ContainsBand(band.GetType());
}
}
if (!bandAlreadyExists)
{
bandAdded = PreparedPages.AddBand(band);
}
// shift CurY
if (bandAdded && !(mainBand is OverlayBand))
{
CurY += band.Height;
}
// set left&width back
band.Left = saveLeft;
band.Width = saveWidth;
}
#endregion Internal Methods
}
}