using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Drawing;
using System.ComponentModel;
using FastReport.Utils;
namespace FastReport.Preview
{
///
/// Specifies an action that will be performed on PreparedPages.AddPage method call.
///
public enum AddPageAction
{
///
/// Do not add the new prepared page if possible, increment the CurPage instead.
///
WriteOver,
///
/// Add the new prepared page.
///
Add
}
///
/// Represents the pages of a prepared report.
///
///
/// Prepared page is a page that you can see in the preview window. Prepared pages can be
/// accessed via property.
/// The common scenarios of using this object are:
///
/// -
/// Working with prepared pages after the report is finished: load
/// () or save () pages
/// from/to a .fpx file, get a page with specified index to work with its objects
/// (); modify specified page ().
///
///
/// -
/// Using the , ,
/// methods while report is generating to produce an output.
///
///
///
///
///
[ToolboxItem(false)]
public partial class PreparedPages : IDisposable
{
#region Fields
private SourcePages sourcePages;
private List preparedPages;
private Dictionary dictionary;
private Bookmarks bookmarks;
private Outline outline;
private BlobStore blobStore;
private int curPage;
private AddPageAction addPageAction;
private Report report;
private PageCache pageCache;
private FileStream tempFile;
private bool canUpload;
private string tempFileName;
private XmlItem cutObjects;
private Dictionary macroValues;
private int firstPassPage;
private int firstPassPosition;
#endregion
#region Properties
internal Report Report
{
get { return report; }
}
internal SourcePages SourcePages
{
get { return sourcePages; }
}
internal Dictionary Dictionary
{
get { return dictionary; }
}
internal Bookmarks Bookmarks
{
get { return bookmarks; }
}
internal Outline Outline
{
get { return outline; }
}
internal BlobStore BlobStore
{
get { return blobStore; }
}
internal FileStream TempFile
{
get { return tempFile; }
}
internal Dictionary MacroValues
{
get { return macroValues; }
}
internal int CurPosition
{
get
{
if (CurPage < 0 || CurPage >= Count)
return 0;
return preparedPages[CurPage].CurPosition;
}
}
internal int CurPage
{
get { return curPage; }
set { curPage = value; }
}
///
/// Gets the number of pages in the prepared report.
///
public int Count
{
get { return preparedPages.Count; }
}
///
/// Gets the XML for rendering the outline of the report
///
public XmlItem OutlineXml
{
get => outline.Xml;
}
///
/// Specifies an action that will be performed on method call.
///
public AddPageAction AddPageAction
{
get { return addPageAction; }
set { addPageAction = value; }
}
///
/// Gets or sets a value indicating whether the prepared pages can be uploaded to the file cache.
///
///
/// This property is used while report is generating.
/// Default value for this property is true. That means the prepared pages may be uploaded to
/// the file cache if needed. To prevent this (for example, if you need to access some objects
/// on previously generated pages), set the property value to false.
///
public bool CanUploadToCache
{
get { return canUpload; }
set
{
if (canUpload != value)
{
canUpload = value;
if (value)
UploadPages();
}
}
}
#endregion
#region Private Methods
private void UploadPages()
{
if (Report.UseFileCache)
{
for (int i = 0; i < Count - 1; i++)
{
preparedPages[i].Upload();
}
}
}
#endregion
#region Protected Methods
///
public void Dispose()
{
Clear();
if (tempFile != null)
{
tempFile.Dispose();
tempFile = null;
if (File.Exists(tempFileName))
File.Delete(tempFileName);
}
BlobStore.Dispose();
}
#endregion
#region Public Methods
internal void SetReport(Report report)
{
this.report = report;
}
///
/// Adds a source page to the prepared pages dictionary.
///
/// The template page to add.
///
/// Call this method before using AddPage and AddBand methods. This method adds
/// a page to the dictionary that will be used to decrease size of the prepared report.
///
public void AddSourcePage(ReportPage page)
{
SourcePages.Add(page);
}
///
/// Adds a new page.
///
/// The original (template) page to add.
///
/// Call the method before adding a page. This method creates
/// a new output page with settings based on page parameter.
///
public void AddPage(ReportPage page)
{
CurPage++;
if (CurPage >= Count || AddPageAction != AddPageAction.WriteOver)
{
PreparedPage preparedPage = new PreparedPage(page, this);
preparedPages.Add(preparedPage);
// upload previous page to the file cache if enabled
if (CanUploadToCache && Count > 1)
preparedPages[Count - 2].Upload();
AddPageAction = AddPageAction.WriteOver;
CurPage = Count - 1;
Report.Engine.IncLogicalPageNumber();
}
}
///
/// Prints a band with all its child objects.
///
/// The band to print.
/// true if band was printed; false if it can't be printed
/// on current page due to its PrintOn property value.
///
/// Call the method before adding a band.
///
public bool AddBand(BandBase band)
{
return preparedPages[CurPage].AddBand(band);
}
///
/// Gets a page with specified index.
///
/// Zero-based index of page.
/// The page with specified index.
public ReportPage GetPage(int index)
{
if (index >= 0 && index < preparedPages.Count)
{
macroValues["Page#"] = index + Report.InitialPageNumber;
macroValues["TotalPages#"] = preparedPages.Count + Report.InitialPageNumber - 1;
ReportPage page = preparedPages[index].GetPage();
if (page.MirrorMargins && (index + 1) % 2 == 0)
{
float f = page.LeftMargin;
page.LeftMargin = page.RightMargin;
page.RightMargin = f;
}
return page;
}
else
return null;
}
internal PreparedPage GetPreparedPage(int index)
{
if (index >= 0 && index < preparedPages.Count)
{
macroValues["Page#"] = index + Report.InitialPageNumber;
macroValues["TotalPages#"] = preparedPages.Count + Report.InitialPageNumber - 1;
return preparedPages[index];
}
else
return null;
}
internal ReportPage GetCachedPage(int index)
{
return pageCache.Get(index);
}
///
/// Gets the size of specified page, in pixels.
///
/// Index of page.
/// the size of specified page, in pixels.
public SizeF GetPageSize(int index)
{
return preparedPages[index].PageSize;
}
///
/// Replaces the prepared page with specified one.
///
/// The index of prepared page to replace.
/// The new page to replace with.
public void ModifyPage(int index, ReportPage newPage)
{
PreparedPage preparedPage = new PreparedPage(newPage, this);
foreach (Base obj in newPage.ChildObjects)
{
if (obj is BandBase)
preparedPage.AddBand(obj as BandBase);
}
preparedPages[index].Dispose();
preparedPages[index] = preparedPage;
pageCache.Remove(index);
}
///
/// Modify the prepared page with new sizes.
///
/// The name of prepared page to reSize.
public void ModifyPageSize(string name)
{
foreach (PreparedPage page in preparedPages)
{
if (String.Equals(name, page.GetName(), StringComparison.InvariantCultureIgnoreCase))
{
page.ReCalcSizes();
}
}
}
///
/// Removes a page with the specified index.
///
/// The zero-based index of page to remove.
public void RemovePage(int index)
{
preparedPages[index].Dispose();
preparedPages.RemoveAt(index);
pageCache.Clear();
}
///
/// Creates a copy of a page with specified index and inserts it after original one.
///
/// The zero-based index of original page.
public void CopyPage(int index)
{
// insert a new empty page at specified index
PreparedPage newPage = new PreparedPage(null, this);
if (index == preparedPages.Count - 1)
preparedPages.Add(newPage);
else
preparedPages.Insert(index + 1, newPage);
// and copy source page into it
ModifyPage(index + 1, GetPage(index));
pageCache.Clear();
}
internal void InterleaveWithBackPage(int backPageIndex)
{
PreparedPage page = preparedPages[backPageIndex];
int count = backPageIndex - 1;
for (int i = 0; i < count; i++)
{
preparedPages.Insert(i * 2 + 1, page);
}
}
internal void ApplyWatermark(Watermark watermark)
{
SourcePages.ApplyWatermark(watermark);
pageCache.Clear();
}
internal void CutObjects(int index)
{
cutObjects = preparedPages[CurPage].CutObjects(index);
}
internal void PasteObjects(float x, float y)
{
preparedPages[CurPage].PasteObjects(cutObjects, x, y);
}
internal float GetLastY()
{
return preparedPages[CurPage].GetLastY();
}
internal void PrepareToFirstPass()
{
firstPassPage = CurPage;
firstPassPosition = CurPosition;
Outline.PrepareToFirstPass();
}
internal void ClearFirstPass()
{
Bookmarks.ClearFirstPass();
Outline.ClearFirstPass();
// clear all pages after specified FFirstPassPage
while (firstPassPage < Count - 1)
{
RemovePage(Count - 1);
}
// if position is at begin, clear all pages
if (firstPassPage == 0 && firstPassPosition == 0)
RemovePage(0);
// delete objects on the FFirstPassPage
if (firstPassPage >= 0 && firstPassPage < Count)
preparedPages[firstPassPage].CutObjects(firstPassPosition).Dispose();
CurPage = firstPassPage;
}
internal bool ContainsBand(Type bandType)
{
return preparedPages[CurPage].ContainsBand(bandType);
}
internal bool ContainsBand(string bandName)
{
return preparedPages[CurPage].ContainsBand(bandName);
}
///
/// Saves prepared pages to a stream.
///
/// The stream to save to.
public void Save(Stream stream)
{
if (Config.PreparedCompressed)
stream = Compressor.Compress(stream);
using (XmlDocument doc = new XmlDocument())
{
doc.AutoIndent = true;
doc.Root.Name = "preparedreport";
// save ReportInfo
doc.Root.SetProp("ReportInfo.Name", Report.ReportInfo.Name);
doc.Root.SetProp("ReportInfo.Author", Report.ReportInfo.Author);
doc.Root.SetProp("ReportInfo.Description", Report.ReportInfo.Description);
doc.Root.SetProp("ReportInfo.Created", SystemFake.DateTime.Now.ToString());
doc.Root.SetProp("ReportInfo.Modified", SystemFake.DateTime.Now.ToString());
doc.Root.SetProp("ReportInfo.CreatorVersion", Report.ReportInfo.CreatorVersion);
XmlItem pages = doc.Root.Add();
pages.Name = "pages";
// attach each page's xml to the doc
foreach (PreparedPage page in preparedPages)
{
page.Load();
pages.AddItem(page.Xml);
}
XmlItem sourcePages = doc.Root.Add();
sourcePages.Name = "sourcepages";
SourcePages.Save(sourcePages);
XmlItem dictionary = doc.Root.Add();
dictionary.Name = "dictionary";
Dictionary.Save(dictionary);
XmlItem bookmarks = doc.Root.Add();
bookmarks.Name = "bookmarks";
Bookmarks.Save(bookmarks);
doc.Root.AddItem(Outline.Xml);
XmlItem blobStore = doc.Root.Add();
blobStore.Name = "blobstore";
BlobStore.Save(blobStore);
doc.Save(stream);
// detach each page's xml from the doc
foreach (PreparedPage page in preparedPages)
{
page.Xml.Parent = null;
page.ClearUploadedXml();
}
Outline.Xml.Parent = null;
}
if (Config.PreparedCompressed)
stream.Dispose();
}
///
/// Saves prepared pages to a .fpx file.
///
/// The name of the file to save to.
public void Save(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
Save(stream);
}
}
///
/// Loads prepared pages from a stream.
///
/// The stream to load from.
public void Load(Stream stream)
{
Clear();
if (stream.Length == 0)
return;
if (!stream.CanSeek)
{
MemoryStream tempStream = new MemoryStream();
const int BUFFER_SIZE = 32768;
stream.CopyTo(tempStream, BUFFER_SIZE);
tempStream.Position = 0;
stream = tempStream;
}
bool compressed = Compressor.IsStreamCompressed(stream);
if (compressed)
stream = Compressor.Decompress(stream, false);
try
{
using (XmlDocument doc = new XmlDocument())
{
doc.Load(stream);
XmlItem sourcePages = doc.Root.FindItem("sourcepages");
SourcePages.Load(sourcePages);
XmlItem dictionary = doc.Root.FindItem("dictionary");
Dictionary.Load(dictionary);
XmlItem bookmarks = doc.Root.FindItem("bookmarks");
Bookmarks.Load(bookmarks);
XmlItem outline = doc.Root.FindItem("outline");
Outline.Xml = outline;
XmlItem blobStore = doc.Root.FindItem("blobstore");
BlobStore.LoadDestructive(blobStore);
XmlItem pages = doc.Root.FindItem("pages");
while (pages.Count > 0)
{
XmlItem pageItem = pages[0];
PreparedPage preparedPage = new PreparedPage(null, this);
preparedPages.Add(preparedPage);
preparedPage.Xml = pageItem;
}
// load ReportInfo
Report.ReportInfo.Name = doc.Root.GetProp("ReportInfo.Name");
Report.ReportInfo.Author = doc.Root.GetProp("ReportInfo.Author");
Report.ReportInfo.Description = doc.Root.GetProp("ReportInfo.Description");
DateTime createDate;
if (DateTime.TryParse(doc.Root.GetProp("ReportInfo.Created"), out createDate))
Report.ReportInfo.Created = createDate;
if (DateTime.TryParse(doc.Root.GetProp("ReportInfo.Modified"), out createDate))
Report.ReportInfo.Modified = createDate;
Report.ReportInfo.CreatorVersion = doc.Root.GetProp("ReportInfo.CreatorVersion");
}
}
finally
{
if (compressed)
stream.Dispose();
}
}
///
/// Loads prepared pages from a .fpx file.
///
/// The name of the file to load from.
public void Load(string fileName)
{
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
Load(stream);
}
}
///
/// Clears the prepared report's pages.
///
public void Clear()
{
sourcePages.Clear();
pageCache.Clear();
foreach (PreparedPage page in preparedPages)
{
page.Dispose();
}
preparedPages.Clear();
dictionary.Clear();
bookmarks.Clear();
outline.Clear();
blobStore.Clear();
curPage = 0;
}
internal void ClearPageCache()
{
pageCache.Clear();
}
#endregion
///
/// Creates the pages of a prepared report
///
///
public PreparedPages(Report report)
{
this.report = report;
sourcePages = new SourcePages(this);
preparedPages = new List();
dictionary = new Dictionary(this);
bookmarks = new Bookmarks();
outline = new Outline();
blobStore = new BlobStore(report != null ? report.UseFileCache : false);
pageCache = new PageCache(this);
macroValues = new Dictionary();
if (this.report != null && this.report.UseFileCache)
{
tempFileName = Config.CreateTempFile("");
tempFile = new FileStream(tempFileName, FileMode.OpenOrCreate, FileAccess.ReadWrite);
}
}
}
}