FastReport
2870 строк · 99.2 Кб
1using FastReport.Code;
2using FastReport.CrossView;
3using FastReport.Data;
4using FastReport.Dialog;
5using FastReport.Engine;
6using FastReport.Export;
7using FastReport.Utils;
8using System;
9using System.Collections;
10using System.Collections.Generic;
11using System.ComponentModel;
12using System.Data;
13using System.Diagnostics;
14using System.Drawing;
15using System.Drawing.Text;
16using System.IO;
17using System.Linq;
18using System.Linq.Expressions;
19using System.Security;
20using System.Text;
21using System.Threading;
22using System.Threading.Tasks;
23using System.Windows.Forms;
24
25namespace FastReport
26{
27/// <summary>
28/// Specifies the language of the report's script.
29/// </summary>
30public enum Language
31{
32/// <summary>
33/// The C# language.
34/// </summary>
35CSharp,
36
37/// <summary>
38/// The VisualBasic.Net language.
39/// </summary>
40Vb
41}
42
43/// <summary>
44/// Specifies the quality of text rendering.
45/// </summary>
46public enum TextQuality
47{
48/// <summary>
49/// The default text quality, depends on system settings.
50/// </summary>
51Default,
52
53/// <summary>
54/// The regular quality.
55/// </summary>
56Regular,
57
58/// <summary>
59/// The "ClearType" quality.
60/// </summary>
61ClearType,
62
63/// <summary>
64/// The AntiAlias quality. This mode may be used to produce the WYSIWYG text.
65/// </summary>
66AntiAlias,
67
68/// <summary>
69/// The "SingleBitPerPixel" quality.
70/// </summary>
71SingleBPP,
72
73
74/// <summary>
75/// The "SingleBitPerPixelGridFit" quality.
76/// </summary>
77SingleBPPGridFit
78}
79
80/// <summary>
81/// Specifies the report operation.
82/// </summary>
83public enum ReportOperation
84{
85/// <summary>
86/// Specifies no operation.
87/// </summary>
88None,
89
90/// <summary>
91/// The report is running.
92/// </summary>
93Running,
94
95/// <summary>
96/// The report is printing.
97/// </summary>
98Printing,
99
100/// <summary>
101/// The report is exporting.
102/// </summary>
103Exporting
104}
105
106/// <summary>
107/// Specifies the page range to print/export.
108/// </summary>
109public enum PageRange
110{
111/// <summary>
112/// Print all pages.
113/// </summary>
114All,
115
116/// <summary>
117/// Print current page.
118/// </summary>
119Current,
120
121/// <summary>
122/// Print pages specified in the <b>PageNumbers</b> property of the <b>PrintSettings</b>.
123/// </summary>
124PageNumbers
125}
126
127/// <summary>
128/// Represents a report object.
129/// </summary>
130/// <remarks>
131/// <para>The instance of this class contains a report. Here are some common
132/// actions that can be performed with this object:</para>
133/// <list type="bullet">
134/// <item>
135/// <description>To load a report, use the <see cref="Load(string)"/>
136/// method or call static <see cref="FromFile"/> method. </description>
137/// </item>
138/// <item>
139/// <description>To save a report, call the <see cref="Save(string)"/> method.</description>
140/// </item>
141/// <item>
142/// <description>To register application dataset for use it in a report, call one of the
143/// <b>RegisterData</b> methods.</description>
144/// </item>
145/// <item>
146/// <description>To pass some parameter to a report, use the
147/// <see cref="SetParameterValue"/> method.</description>
148/// </item>
149/// <item>
150/// <description>To design a report, call the <see cref="Design()"/> method.</description>
151/// </item>
152/// <item>
153/// <description>To run a report and preview it, call the <see cref="Show()"/> method.
154/// Another way is to call the <see cref="Prepare()"/> method, then call the
155/// <see cref="ShowPrepared()"/> method.</description>
156/// </item>
157/// <item>
158/// <description>To run a report and print it, call the <see cref="Print"/> method.
159/// Another way is to call the <see cref="Prepare()"/> method, then call the
160/// <see cref="PrintPrepared()"/> method.</description>
161/// </item>
162/// <item>
163/// <description>To load/save prepared report, use one of the <b>LoadPrepared</b> and
164/// <b>SavePrepared</b> methods.</description>
165/// </item>
166/// <item>
167/// <description>To set up some global properties, use the <see cref="Config"/> static class
168/// or <see cref="EnvironmentSettings"/> component that you can use in the Visual Studio IDE.
169/// </description>
170/// </item>
171/// </list>
172/// <para/>The report consists of one or several report pages (pages of the
173/// <see cref="ReportPage"/> type) and/or dialog forms (pages of the <see cref="DialogPage"/> type).
174/// They are stored in the <see cref="Pages"/> collection. In turn, each page may contain report
175/// objects. See the example below how to create a simple report in code.
176/// </remarks>
177/// <example>This example shows how to create a report instance, load it from a file,
178/// register the application data, run and preview.
179/// <code>
180/// Report report = new Report();
181/// report.Load("reportfile.frx");
182/// report.RegisterData(application_dataset);
183/// report.Show();
184/// </code>
185/// <para/>This example shows how to create simple report in code.
186/// <code>
187/// Report report = new Report();
188/// // create the report page
189/// ReportPage page = new ReportPage();
190/// page.Name = "ReportPage1";
191/// // set paper width and height. Note: these properties are measured in millimeters.
192/// page.PaperWidth = 210;
193/// page.PaperHeight = 297;
194/// // add a page to the report
195/// report.Pages.Add(page);
196/// // create report title
197/// page.ReportTitle = new ReportTitleBand();
198/// page.ReportTitle.Name = "ReportTitle1";
199/// page.ReportTitle.Height = Units.Millimeters * 10;
200/// // create Text object and put it to the title
201/// TextObject text = new TextObject();
202/// text.Name = "Text1";
203/// text.Bounds = new RectangleF(0, 0, Units.Millimeters * 100, Units.Millimeters * 5);
204/// page.ReportTitle.Objects.Add(text);
205/// // create data band
206/// DataBand data = new DataBand();
207/// data.Name = "Data1";
208/// data.Height = Units.Millimeters * 10;
209/// // add data band to a page
210/// page.Bands.Add(data);
211/// </code>
212/// </example>
213
214public partial class Report : Base, IParent, ISupportInitialize
215{
216#region Fields
217
218private PageCollection pages;
219private Dictionary dictionary;
220private ReportInfo reportInfo;
221private string baseReport;
222private Report baseReportObject;
223private string baseReportAbsolutePath;
224private string fileName;
225private string scriptText;
226private Language scriptLanguage;
227private bool compressed;
228private bool useFileCache;
229private TextQuality textQuality;
230private bool smoothGraphics;
231private string password;
232private bool convertNulls;
233private bool doublePass;
234private bool autoFillDataSet;
235private int initialPageNumber;
236private int maxPages;
237private string startReportEvent;
238private string finishReportEvent;
239private StyleCollection styles;
240private CodeHelperBase codeHelper;
241private GraphicCache graphicCache;
242private string[] referencedAssemblies;
243private Hashtable cachedDataItems;
244private AssemblyCollection assemblies;
245private FastReport.Preview.PreparedPages preparedPages;
246private ReportEngine engine;
247private bool aborted;
248private Bitmap measureBitmap;
249private IGraphics measureGraphics;
250private bool storeInResources;
251private PermissionSet scriptRestrictions;
252private ReportOperation operation;
253private bool needCompile;
254private bool scriptChanged = false;
255private bool needRefresh;
256private bool isParameterChanged = false;
257private bool initializing;
258private object initializeData;
259private string initializeDataName;
260private object tag;
261private bool isLoadPrepared = false;
262
263#endregion Fields
264
265#region Properties
266
267/// <summary>
268/// Occurs when calc execution is started.
269/// </summary>
270public event CustomCalcEventHandler CustomCalc;
271
272/// <summary>
273/// Occurs when report is inherited and trying to load a base report.
274/// </summary>
275/// <remarks>
276/// Typical use of this event is to load the base report from a database instead of a file.
277/// </remarks>
278public event CustomLoadEventHandler LoadBaseReport;
279
280/// <summary>
281/// Occurs when report execution is started.
282/// </summary>
283public event EventHandler StartReport;
284
285/// <summary>
286/// Occurs when report execution is finished.
287/// </summary>
288public event EventHandler FinishReport;
289
290/// <summary>
291/// Occurs before export to set custom export parameters.
292/// </summary>
293public event EventHandler<ExportParametersEventArgs> ExportParameters;
294
295/// <summary>
296/// Gets the pages contained in this report.
297/// </summary>
298/// <remarks>
299/// This property contains pages of all types (report and dialog). Use the <b>is/as</b> operators
300/// if you want to work with pages of <b>ReportPage</b> type.
301/// </remarks>
302/// <example>The following code demonstrates how to access the first report page:
303/// <code>
304/// ReportPage page1 = report1.Pages[0] as ReportPage;
305/// </code>
306/// </example>
307[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
308public PageCollection Pages
309{
310get { return pages; }
311}
312
313/// <summary>
314/// Gets the report's data.
315/// </summary>
316/// <remarks>
317/// The dictionary contains all data items such as connections, data sources, parameters,
318/// system variables.
319/// </remarks>
320[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
321public Dictionary Dictionary
322{
323get { return dictionary; }
324set
325{
326SetProp(dictionary, value);
327dictionary = value;
328}
329}
330
331/// <summary>
332/// Gets the collection of report parameters.
333/// </summary>
334/// <remarks>
335/// <para>Parameters are displayed in the "Data" window under the "Parameters" node.</para>
336/// <para>Typical use of parameters is to pass some static data from the application to the report.
337/// You can print such data, use it in the data row filter, script etc. </para>
338/// <para>Another way to use parameters is to define some reusable piece of code, for example,
339/// to define an expression that will return the concatenation of first and second employee name.
340/// In this case, you set the parameter's <b>Expression</b> property to something like this:
341/// [Employees.FirstName] + " " + [Employees.LastName]. Now this parameter may be used in the report
342/// to print full employee name. Each time you access such parameter, it will calculate the expression
343/// and return its value. </para>
344/// <para>You can create nested parameters. To do this, add the new <b>Parameter</b> to the
345/// <b>Parameters</b> collection of the root parameter. To access the nested parameter, you may use the
346/// <see cref="GetParameter"/> method.</para>
347/// <para>To get or set the parameter's value, use the <see cref="GetParameterValue"/> and
348/// <see cref="SetParameterValue"/> methods. To set the parameter's expression, use the
349/// <see cref="GetParameter"/> method that returns a <b>Parameter</b> object and set its
350/// <b>Expression</b> property.</para>
351/// </remarks>
352[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
353public ParameterCollection Parameters
354{
355get { return dictionary.Parameters; }
356}
357
358/// <summary>
359/// Gets or sets the report information such as report name, author, description etc.
360/// </summary>
361[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
362[SRCategory("Design")]
363public ReportInfo ReportInfo
364{
365get { return reportInfo; }
366set { reportInfo = value; }
367}
368
369/// <summary>
370/// Gets or sets the base report file name.
371/// </summary>
372/// <remarks>
373/// This property contains the name of a report file this report is inherited from.
374/// <b>Note:</b> setting this property to non-empty value will clear the report and
375/// load the base file into it.
376/// </remarks>
377[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
378public string BaseReport
379{
380get { return baseReport; }
381set { SetBaseReport(value); }
382}
383
384/// <summary>
385/// Gets a value indicating whether Report is prepared
386/// </summary>
387[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
388public bool IsPrepared
389{
390get { return !isParameterChanged && PreparedPages != null && PreparedPages.Count != 0; }
391}
392/// <summary>
393/// Gets or sets the absolute path to the parent report.
394/// </summary>
395/// <remarks>
396/// This property contains the absolute path to the parent report.
397/// </remarks>
398[Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
399public string BaseReportAbsolutePath
400{
401get { return baseReportAbsolutePath; }
402set { baseReportAbsolutePath = value; }
403}
404
405/// <summary>
406/// Gets or sets the name of a file the report was loaded from.
407/// </summary>
408/// <remarks>
409/// This property is used to support the FastReport.Net infrastructure;
410/// typically you don't need to use it.
411/// </remarks>
412[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
413public string FileName
414{
415get { return fileName; }
416set { fileName = value; }
417}
418
419/// <summary>
420/// Gets or sets the report script.
421/// </summary>
422/// <remarks>
423/// <para>The script contains the <b>ReportScript</b> class that contains all report objects'
424/// event handlers and own items such as private fields, properties, methods etc. The script
425/// contains only items written by you. Unlike other report generators, the script does not
426/// contain report objects declarations, initialization code. It is added automatically when
427/// you run the report.</para>
428/// <para>By default this property contains an empty script text. You may see it in the designer
429/// when you switch to the Code window.</para>
430/// <para>If you set this property programmatically, you have to declare the <b>FastReport</b>
431/// namespace and the <b>ReportScript</b> class in it. Do not declare report items (such as bands,
432/// objects, etc) in the <b>ReportScript</b> class: the report engine does this automatically when
433/// you run the report.</para>
434/// <para><b>Security note:</b> since the report script is compiled into .NET assembly, it allows
435/// you to do ANYTHING. For example, you may create a script that will read/write files from/to a disk.
436/// To restrict such operations, use the <see cref="ScriptRestrictions"/> property.</para>
437/// </remarks>
438[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
439public string ScriptText
440{
441get { return scriptText; }
442set
443{
444scriptText = value;
445scriptChanged = scriptText != codeHelper.EmptyScript();
446}
447}
448
449/// <summary>
450/// Gets or sets the script language of this report.
451/// </summary>
452/// <remarks>
453/// Note: changing this property will reset the report script to default empty script.
454/// </remarks>
455[DefaultValue(Language.CSharp)]
456[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
457[SRCategory("Script")]
458public Language ScriptLanguage
459{
460get { return scriptLanguage; }
461set
462{
463bool needClear = scriptLanguage != value;
464scriptLanguage = value;
465if (scriptLanguage == Language.CSharp)
466codeHelper = new CsCodeHelper(this);
467else
468codeHelper = new VbCodeHelper(this);
469if (needClear)
470{
471scriptText = codeHelper.EmptyScript();
472scriptChanged = false;
473}
474}
475}
476
477/// <summary>
478/// Gets or sets a value indicating whether the null DB value must be converted to zero, false or
479/// empty string depending on the data column type.
480/// </summary>
481/// <remarks>
482/// This property is <b>true</b> by default. If you set it to <b>false</b>, you should check
483/// the DB value before you do something with it (for example, typecast it to any type, use it
484/// in a expression etc.)
485/// </remarks>
486[DefaultValue(true)]
487[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
488[SRCategory("Engine")]
489public bool ConvertNulls
490{
491get { return convertNulls; }
492set { convertNulls = value; }
493}
494
495/// <summary>
496/// Gets or sets a value that specifies whether the report engine should perform the second pass.
497/// </summary>
498/// <remarks>
499/// <para>Typically the second pass is necessary to print the number of total pages. It also
500/// may be used to perform some calculations on the first pass and print its results on the
501/// second pass.</para>
502/// <para>Use the <b>Engine.FirstPass</b>, <b>Engine.FinalPass</b> properties to determine which
503/// pass the engine is performing now.</para>
504/// </remarks>
505[DefaultValue(false)]
506[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
507[SRCategory("Engine")]
508public bool DoublePass
509{
510get { return doublePass; }
511set { doublePass = value; }
512}
513
514/// <summary>
515/// Gets or sets a value that specifies whether to compress the report file.
516/// </summary>
517/// <remarks>
518/// The report file is compressed using the Gzip algorithm. So you can open the
519/// compressed report in any zip-compatible archiver.
520/// </remarks>
521[DefaultValue(false)]
522[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
523[SRCategory("Misc")]
524public bool Compressed
525{
526get { return compressed; }
527set { compressed = value; }
528}
529
530/// <summary>
531/// Returns a bool value depending on the .frx or .fpx report was loaded
532/// </summary>
533public bool IsLoadPrepared
534{
535get => isLoadPrepared;
536}
537
538/// <summary>
539/// Gets or sets a value that specifies whether to use the file cache rather than memory
540/// to store the prepared report pages.
541/// </summary>
542[DefaultValue(false)]
543[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
544[SRCategory("Engine")]
545public bool UseFileCache
546{
547get { return useFileCache; }
548set { useFileCache = value; }
549}
550
551/// <summary>
552/// Gets or sets a value that specifies the quality of text rendering.
553/// </summary>
554/// <remarks>
555/// <b>Note:</b> the default property value is <b>TextQuality.Default</b>. That means the report
556/// may look different depending on OS settings. This property does not affect the printout.
557/// </remarks>
558[DefaultValue(TextQuality.Default)]
559[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
560[SRCategory("Misc")]
561public TextQuality TextQuality
562{
563get { return textQuality; }
564set { textQuality = value; }
565}
566
567/// <summary>
568/// Gets or sets a value that specifies if the graphic objects such as bitmaps
569/// and shapes should be displayed smoothly.
570/// </summary>
571[DefaultValue(false)]
572[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
573[SRCategory("Misc")]
574public bool SmoothGraphics
575{
576get { return smoothGraphics; }
577set { smoothGraphics = value; }
578}
579
580/// <summary>
581/// Gets or sets the report password.
582/// </summary>
583/// <remarks>
584/// <para>When you try to load the password-protected report, you will be asked
585/// for a password. You also may specify the password in this property before loading
586/// the report. In this case the report will load silently.</para>
587/// <para>Password-protected report file is crypted using Rijndael algorithm.
588/// Do not forget your password! It will be hard or even impossible to open
589/// the protected file in this case.</para>
590/// </remarks>
591[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
592public string Password
593{
594get { return password; }
595set { password = value; }
596}
597
598/// <summary>
599/// Gets or sets a value indicating whether it is necessary to automatically fill
600/// DataSet registered with <b>RegisterData</b> call.
601/// </summary>
602/// <remarks>
603/// If this property is <b>true</b> (by default), FastReport will automatically fill
604/// the DataSet with data when you trying to run a report. Set it to <b>false</b> if
605/// you want to fill the DataSet by yourself.
606/// </remarks>
607[DefaultValue(true)]
608[SRCategory("Misc")]
609public bool AutoFillDataSet
610{
611get { return autoFillDataSet; }
612set { autoFillDataSet = value; }
613}
614
615/// <summary>
616/// Gets or sets the maximum number of generated pages in a prepared report.
617/// </summary>
618/// <remarks>
619/// Use this property to limit the number of pages in a prepared report.
620/// </remarks>
621[DefaultValue(0)]
622[SRCategory("Misc")]
623public int MaxPages
624{
625get { return maxPages; }
626set { maxPages = value; }
627}
628
629/// <summary>
630/// Gets or sets the collection of styles used in this report.
631/// </summary>
632[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
633[SRCategory("Misc")]
634public StyleCollection Styles
635{
636get { return styles; }
637set { styles = value; }
638}
639
640/// <summary>
641/// Gets or sets an array of assembly names that will be used to compile the report script.
642/// </summary>
643/// <remarks>
644/// By default this property contains the following assemblies: "System.dll", "System.Drawing.dll",
645/// "System.Windows.Forms.dll", "System.Data.dll", "System.Xml.dll". If your script uses some types
646/// from another assemblies, you have to add them to this property.
647/// </remarks>
648[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
649[SRCategory("Script")]
650public string[] ReferencedAssemblies
651{
652get { return referencedAssemblies; }
653set
654{
655if (value != null)
656{
657// fix for old reports with "System.Windows.Forms.DataVisualization" in referenced assemblies
658for (int i = 0; i < value.Length; i++)
659{
660value[i] = value[i].Replace("System.Windows.Forms.DataVisualization", "FastReport.DataVisualization");
661}
662}
663referencedAssemblies = value;
664}
665}
666
667/// <summary>
668/// Gets or sets a script event name that will be fired when the report starts.
669/// </summary>
670[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
671[SRCategory("Build")]
672public string StartReportEvent
673{
674get { return startReportEvent; }
675set { startReportEvent = value; }
676}
677
678/// <summary>
679/// Gets or sets a script event name that will be fired when the report is finished.
680/// </summary>
681[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
682[SRCategory("Build")]
683public string FinishReportEvent
684{
685get { return finishReportEvent; }
686set { finishReportEvent = value; }
687}
688
689/// <summary>
690/// Gets a value indicating that report execution was aborted.
691/// </summary>
692[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
693public bool Aborted
694{
695get
696{
697Config.DoEvent();
698return aborted;
699}
700}
701
702/// <summary>
703/// Gets or sets a value that determines whether to store the report in the application resources.
704/// Use this property in the MS Visual Studio IDE only.
705/// </summary>
706/// <remarks>
707/// By default this property is <b>true</b>. When set to <b>false</b>, you should store your report
708/// in a file.
709/// </remarks>
710[DefaultValue(true)]
711[SRCategory("Design")]
712public bool StoreInResources
713{
714get { return storeInResources; }
715set { storeInResources = value; }
716}
717
718/// <summary>
719/// Gets or sets the resource string that contains the report.
720/// </summary>
721/// <remarks>
722/// This property is used by the MS Visual Studio to store the report. Do not use it directly.
723/// </remarks>
724[Browsable(false)]
725[Localizable(true)]
726public string ReportResourceString
727{
728get
729{
730if (!StoreInResources)
731return "";
732return SaveToString();
733}
734set
735{
736if (String.IsNullOrEmpty(value))
737{
738Clear();
739return;
740}
741LoadFromString(value);
742}
743}
744
745/// <summary>
746/// Gets a value indicating that this report contains dialog forms.
747/// </summary>
748[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
749public bool HasDialogs
750{
751get
752{
753foreach (PageBase page in Pages)
754{
755if (page is DialogPage)
756return true;
757}
758return false;
759}
760}
761
762/// <summary>
763/// Gets or sets a set of permissions that will be restricted for the script code.
764/// </summary>
765/// <remarks>
766/// Since the report script is compiled into .NET assembly, it allows you to do ANYTHING.
767/// For example, you may create a script that will read/write files from/to a disk. This property
768/// is used to restrict such operations.
769/// <example>This example shows how to restrict the file IO operations in a script:
770/// <code>
771/// using System.Security;
772/// using System.Security.Permissions;
773/// ...
774/// PermissionSet ps = new PermissionSet(PermissionState.None);
775/// ps.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
776/// report1.ScriptRestrictions = ps;
777/// report1.Prepare();
778/// </code>
779/// </example>
780/// </remarks>
781[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
782public PermissionSet ScriptRestrictions
783{
784get { return scriptRestrictions; }
785set { scriptRestrictions = value; }
786}
787
788/// <summary>
789/// Gets a reference to the graphics cache for this report.
790/// </summary>
791/// <remarks>
792/// This property is used to support the FastReport.Net infrastructure. Do not use it directly.
793/// </remarks>
794[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
795public GraphicCache GraphicCache
796{
797get { return graphicCache; }
798}
799
800/// <summary>
801/// Gets a pages of the prepared report.
802/// </summary>
803[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
804public Preview.PreparedPages PreparedPages
805{
806get { return preparedPages; }
807}
808
809/// <summary>
810/// Gets a reference to the report engine.
811/// </summary>
812/// <remarks>
813/// This property can be used when report is running. In other cases it returns <b>null</b>.
814/// </remarks>
815[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
816public ReportEngine Engine
817{
818get { return engine; }
819}
820
821/// <summary>
822/// Gets or sets the initial page number for PageN/PageNofM system variables.
823/// </summary>
824[DefaultValue(1)]
825[SRCategory("Engine")]
826public int InitialPageNumber
827{
828get { return initialPageNumber; }
829set { initialPageNumber = value; }
830}
831
832/// <summary>
833/// This property is not relevant to this class.
834/// </summary>
835[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
836public new string Name
837{
838get { return base.Name; }
839}
840
841/// <summary>
842/// This property is not relevant to this class.
843/// </summary>
844[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
845public new Restrictions Restrictions
846{
847get { return base.Restrictions; }
848set { base.Restrictions = value; }
849}
850
851/// <summary>
852/// Gets the report operation that is currently performed.
853/// </summary>
854[Browsable(false)]
855public ReportOperation Operation
856{
857get { return operation; }
858}
859
860/// <summary>
861/// Gets or sets the Tag object of the report.
862/// </summary>
863[Browsable(false)]
864public object Tag
865{
866get { return tag; }
867set { tag = value; }
868}
869
870private string[] DefaultAssemblies
871{
872get
873{
874return new string[] {
875"System.dll",
876
877"System.Drawing.dll",
878
879"System.Data.dll",
880
881"System.Xml.dll",
882
883"FastReport.Compat.dll",
884#if !CROSSPLATFORM && !(WPF || AVALONIA)
885"System.Windows.Forms.dll",
886#endif
887
888#if WPF
889"FastReport.Forms.WPF.dll",
890#endif
891
892#if AVALONIA
893"FastReport.Forms.Avalonia.dll",
894#endif
895
896#if CROSSPLATFORM || COREWIN
897"System.Drawing.Primitives",
898#endif
899
900#if MSCHART
901"FastReport.DataVisualization.dll"
902#endif
903};
904}
905}
906
907internal CodeHelperBase CodeHelper
908{
909get { return codeHelper; }
910}
911
912public IGraphics MeasureGraphics
913{
914get
915{
916if (measureGraphics == null)
917{
918#if CROSSPLATFORM || MONO
919measureBitmap = new Bitmap(1, 1);
920measureGraphics = new GdiGraphics(measureBitmap);
921#else
922measureGraphics = GdiGraphics.FromGraphics(Graphics.FromHwnd(IntPtr.Zero));
923#endif
924}
925return measureGraphics;
926}
927}
928
929public string GetReportName
930{
931get
932{
933string result = ReportInfo.Name;
934if (String.IsNullOrEmpty(result))
935result = Path.GetFileNameWithoutExtension(FileName);
936return result;
937}
938}
939
940/// <summary>
941/// Gets or sets the flag for refresh.
942/// </summary>
943public bool NeedRefresh
944{
945get { return needRefresh; }
946set { needRefresh = value; }
947}
948
949internal ObjectCollection AllNamedObjects
950{
951get
952{
953ObjectCollection allObjects = AllObjects;
954// data objects are not included into AllObjects list. Include named items separately.
955foreach (Base c in Dictionary.AllObjects)
956{
957if (c is DataConnectionBase || c is DataSourceBase || c is Relation || c is CubeSourceBase)
958allObjects.Add(c);
959}
960
961return allObjects;
962}
963}
964
965#endregion Properties
966
967#region Private Methods
968
969private bool ShouldSerializeReferencedAssemblies()
970{
971return Converter.ToString(ReferencedAssemblies) != Converter.ToString(DefaultAssemblies);
972}
973
974// convert absolute path to the base report to relative path (based on the main report path).
975private string GetRelativePathToBaseReport()
976{
977string path = "";
978if (!String.IsNullOrEmpty(FileName))
979{
980try
981{
982path = Path.GetDirectoryName(FileName);
983}
984catch
985{
986}
987}
988
989if (!String.IsNullOrEmpty(path))
990{
991try
992{
993return FileUtils.GetRelativePath(BaseReport, path);
994}
995catch
996{
997}
998}
999return BaseReport;
1000}
1001
1002private void SetBaseReport(string value)
1003{
1004baseReport = value;
1005if (baseReportObject != null)
1006{
1007baseReportObject.Dispose();
1008baseReportObject = null;
1009}
1010
1011// detach the base report
1012if (String.IsNullOrEmpty(value))
1013{
1014foreach (Base c in AllObjects)
1015{
1016c.SetAncestor(false);
1017}
1018SetAncestor(false);
1019return;
1020}
1021
1022string saveFileName = fileName;
1023if (LoadBaseReport != null)
1024{
1025LoadBaseReport(this, new CustomLoadEventArgs(value, this));
1026}
1027else
1028{
1029// convert the relative path to absolute path (based on the main report path).
1030if (!Path.IsPathRooted(value))
1031{
1032var fullPath = Path.GetFullPath(Path.GetDirectoryName(FileName));
1033// since directory path separator for Win OS is '\' and for Unix OS is '/'
1034// we have to modify the incoming path string with actual for current OS path separator
1035value = Path.Combine(fullPath, GetFixedSeparatedPath(value));
1036}
1037if (!File.Exists(value) && File.Exists(BaseReportAbsolutePath))
1038{
1039value = BaseReportAbsolutePath;
1040}
1041Load(value);
1042}
1043
1044fileName = saveFileName;
1045baseReport = "";
1046Password = "";
1047baseReportObject = Activator.CreateInstance(GetType()) as Report;
1048baseReportObject.AssignAll(this, true);
1049
1050// set Ancestor & CanChangeParent flags
1051foreach (Base c in AllObjects)
1052{
1053c.SetAncestor(true);
1054}
1055SetAncestor(true);
1056baseReport = value;
1057}
1058
1059private static string GetFixedSeparatedPath(string baseReport)
1060{
1061return baseReport.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
1062}
1063
1064private void GetDiff(object sender, DiffEventArgs e)
1065{
1066if (baseReportObject != null)
1067{
1068if (e.Object is Report)
1069e.DiffObject = baseReportObject;
1070else if (e.Object is Base)
1071e.DiffObject = baseReportObject.FindObject((e.Object as Base).Name);
1072}
1073}
1074
1075private void ClearReportProperties()
1076{
1077ReportInfo.Clear();
1078Dictionary.Clear();
1079if (IsDesigning)
1080{
1081ScriptLanguage = Config.ReportSettings.DefaultLanguage;
1082}
1083else
1084{
1085ScriptLanguage = Language.CSharp;
1086}
1087// not property, only field!
1088scriptText = codeHelper.EmptyScript();
1089scriptChanged = false;
1090BaseReport = "";
1091BaseReportAbsolutePath = "";
1092DoublePass = false;
1093ConvertNulls = true;
1094Compressed = false;
1095TextQuality = TextQuality.Default;
1096SmoothGraphics = false;
1097Password = "";
1098InitialPageNumber = 1;
1099MaxPages = 0;
1100ClearDesign();
1101Styles.Clear();
1102Styles.Name = "";
1103referencedAssemblies = DefaultAssemblies;
1104StartReportEvent = "";
1105FinishReportEvent = "";
1106#if REFLECTION_EMIT_COMPILER
1107_cachedParsedExpressions.Clear();
1108#endif
1109needCompile = true;
1110}
1111
1112#endregion Private Methods
1113
1114#region Protected Methods
1115
1116/// <inheritdoc/>
1117protected override void Dispose(bool disposing)
1118{
1119if (disposing)
1120{
1121if (graphicCache != null)
1122graphicCache.Dispose();
1123graphicCache = null;
1124if (measureGraphics != null)
1125measureGraphics.Dispose();
1126measureGraphics = null;
1127if (measureBitmap != null)
1128measureBitmap.Dispose();
1129measureBitmap = null;
1130DisposeDesign();
1131if (PreparedPages != null)
1132PreparedPages.Dispose();
1133}
1134base.Dispose(disposing);
1135}
1136
1137/// <inheritdoc/>
1138protected override void DeserializeSubItems(FRReader reader)
1139{
1140if (String.Compare(reader.ItemName, "ScriptText", true) == 0)
1141ScriptText = reader.ReadPropertyValue();
1142else if (String.Compare(reader.ItemName, "Dictionary", true) == 0)
1143reader.Read(Dictionary);
1144else if (String.Compare(reader.ItemName, "Styles", true) == 0)
1145reader.Read(Styles);
1146else
1147base.DeserializeSubItems(reader);
1148}
1149
1150#endregion Protected Methods
1151
1152#region IParent
1153
1154/// <inheritdoc/>
1155public bool CanContain(Base child)
1156{
1157return child is PageBase || child is Dictionary;
1158}
1159
1160/// <inheritdoc/>
1161public void GetChildObjects(ObjectCollection list)
1162{
1163foreach (PageBase page in pages)
1164{
1165list.Add(page);
1166}
1167}
1168
1169/// <inheritdoc/>
1170public void AddChild(Base obj)
1171{
1172if (obj is PageBase)
1173pages.Add(obj as PageBase);
1174else if (obj is Dictionary)
1175Dictionary = obj as Dictionary;
1176}
1177
1178/// <inheritdoc/>
1179public void RemoveChild(Base obj)
1180{
1181if (obj is PageBase)
1182pages.Remove(obj as PageBase);
1183else if (obj is Dictionary && (obj as Dictionary) == dictionary)
1184Dictionary = null;
1185}
1186
1187/// <inheritdoc/>
1188public virtual int GetChildOrder(Base child)
1189{
1190if (child is PageBase)
1191return pages.IndexOf(child as PageBase);
1192return 0;
1193}
1194
1195/// <inheritdoc/>
1196public virtual void SetChildOrder(Base child, int order)
1197{
1198if (child is PageBase)
1199{
1200if (order > pages.Count)
1201order = pages.Count;
1202int oldOrder = child.ZOrder;
1203if (oldOrder != -1 && order != -1 && oldOrder != order)
1204{
1205if (oldOrder <= order)
1206order--;
1207pages.Remove(child as PageBase);
1208pages.Insert(order, child as PageBase);
1209}
1210}
1211}
1212
1213/// <inheritdoc/>
1214public virtual void UpdateLayout(float dx, float dy)
1215{
1216// do nothing
1217}
1218
1219#endregion IParent
1220
1221#region ISupportInitialize Members
1222
1223/// <inheritdoc/>
1224public void BeginInit()
1225{
1226initializing = true;
1227}
1228
1229/// <inheritdoc/>
1230public void EndInit()
1231{
1232initializing = false;
1233Dictionary.RegisterData(initializeData, initializeDataName, false);
1234}
1235
1236#endregion ISupportInitialize Members
1237
1238#region Script related
1239
1240private void FillDataSourceCache()
1241{
1242cachedDataItems.Clear();
1243ObjectCollection dictionaryObjects = Dictionary.AllObjects;
1244foreach (Parameter c in Dictionary.SystemVariables)
1245{
1246dictionaryObjects.Add(c);
1247}
1248foreach (Base c in dictionaryObjects)
1249{
1250if (c is DataSourceBase)
1251{
1252DataSourceBase data = c as DataSourceBase;
1253CachedDataItem cachedItem = new CachedDataItem();
1254cachedItem.dataSource = data;
1255cachedDataItems[data.FullName] = cachedItem;
1256
1257for (int i = 0; i < data.Columns.Count; i++)
1258{
1259cachedItem = new CachedDataItem();
1260cachedItem.dataSource = data;
1261cachedItem.column = data.Columns[i];
1262cachedDataItems[data.FullName + "." + data.Columns[i].Alias] = cachedItem;
1263}
1264}
1265else if (c is Parameter)
1266{
1267cachedDataItems[(c as Parameter).FullName] = c;
1268}
1269else if (c is Total)
1270{
1271cachedDataItems[(c as Total).Name] = c;
1272}
1273}
1274}
1275
1276internal void Compile()
1277{
1278FillDataSourceCache();
1279
1280#if REFLECTION_EMIT_COMPILER
1281if (Config.CompilerSettings.ReflectionEmitCompiler)
1282{
1283SetIsCompileNeeded();
1284if (!IsCompileNeeded)
1285return;
1286}
1287#endif
1288
1289if (needCompile)
1290{
1291Debug.WriteLine("Compile...");
1292
1293using (AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText))
1294{
1295assemblies.Clear();
1296assemblies.Add(descriptor);
1297descriptor.AddObjects();
1298descriptor.AddExpressions();
1299descriptor.AddFunctions();
1300descriptor.Compile();
1301}
1302}
1303else
1304{
1305InternalInit();
1306}
1307}
1308
1309#if ASYNC
1310internal async Task CompileAsync(CancellationToken token)
1311{
1312FillDataSourceCache();
1313
1314#if REFLECTION_EMIT_COMPILER
1315if (Config.CompilerSettings.ReflectionEmitCompiler)
1316{
1317SetIsCompileNeeded();
1318if (!IsCompileNeeded)
1319return;
1320}
1321#endif
1322
1323if (needCompile)
1324{
1325AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText);
1326assemblies.Clear();
1327assemblies.Add(descriptor);
1328descriptor.AddObjects();
1329descriptor.AddExpressions();
1330descriptor.AddFunctions();
1331await descriptor.CompileAsync(token);
1332}
1333else
1334{
1335InternalInit();
1336}
1337}
1338#endif
1339
1340/// <summary>
1341/// Initializes the report's fields.
1342/// </summary>
1343/// <remarks>
1344/// This method is for internal use only.
1345/// </remarks>
1346protected void InternalInit()
1347{
1348needCompile = false;
1349
1350AssemblyDescriptor descriptor = new AssemblyDescriptor(this, CodeHelper.EmptyScript());
1351assemblies.Clear();
1352assemblies.Add(descriptor);
1353descriptor.InitInstance(this);
1354}
1355
1356/// <summary>
1357/// Generates the file (.cs or .vb) that contains the report source code.
1358/// </summary>
1359/// <param name="fileName">Name of the file.</param>
1360/// <remarks>
1361/// Use this method to generate the report source code. This code can be attached to your project.
1362/// In this case, you will need to call the following code to run a report:
1363/// <code>
1364/// SimpleListReport report = new SimpleListReport();
1365/// report.RegisterData(your_dataset);
1366/// report.Show();
1367/// </code>
1368/// </remarks>
1369public void GenerateReportAssembly(string fileName)
1370{
1371// create the class name
1372string className = "";
1373const string punctuation = " ~`!@#$%^&*()-=+[]{},.<>/?;:'\"\\|";
1374foreach (char c in Path.GetFileNameWithoutExtension(fileName))
1375{
1376if (!punctuation.Contains(c.ToString()))
1377className += c;
1378}
1379
1380AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText);
1381descriptor.AddObjects();
1382descriptor.AddExpressions();
1383descriptor.AddFunctions();
1384
1385string reportClassText = descriptor.GenerateReportClass(className);
1386File.WriteAllText(fileName, reportClassText, Encoding.UTF8);
1387}
1388
1389/// <summary>
1390/// Calculates an expression and returns the result.
1391/// </summary>
1392/// <param name="expression">The expression to calculate.</param>
1393/// <returns>If report is running, returns the result of calculation.
1394/// Otherwise returns <b>null</b>.</returns>
1395/// <remarks>
1396/// <para>The expression may be any valid expression such as "1 + 2". The expression
1397/// is calculated in the report script's <b>ReportScript</b> class instance context,
1398/// so you may refer to any objects available in this context: private fields,
1399/// methods, report objects.</para>
1400/// </remarks>
1401public object Calc(string expression)
1402{
1403return Calc(expression, 0);
1404}
1405
1406/// <summary>
1407/// Calculates an expression and returns the result.
1408/// </summary>
1409/// <param name="expression">The expression to calculate.</param>
1410/// <param name="value">The value of currently printing object.</param>
1411/// <returns>If report is running, returns the result of calculation.
1412/// Otherwise returns <b>null</b>.</returns>
1413/// <remarks>
1414/// Do not call this method directly. Use the <b>Calc(string expression)</b> method instead.
1415/// </remarks>
1416public object Calc(string expression, Variant value)
1417{
1418if (!IsRunning)
1419return null;
1420if (String.IsNullOrEmpty(expression) || String.IsNullOrEmpty(expression.Trim()))
1421return null;
1422
1423string expr = expression;
1424if (expr.StartsWith("[") && expr.EndsWith("]"))
1425expr = expression.Substring(1, expression.Length - 2);
1426
1427// check cached items first
1428object cachedObject = cachedDataItems[expr];
1429
1430if (cachedObject is CachedDataItem)
1431{
1432CachedDataItem cachedItem = cachedObject as CachedDataItem;
1433DataSourceBase data = cachedItem.dataSource;
1434Column column = cachedItem.column;
1435
1436object val = ConvertToColumnDataType(column.Value, column.DataType, ConvertNulls);
1437
1438if (CustomCalc != null)
1439{
1440CustomCalcEventArgs e = new CustomCalcEventArgs(expr, val, this);
1441CustomCalc(this, e);
1442val = e.CalculatedObject;
1443}
1444
1445return val;
1446}
1447else if (cachedObject is Parameter)
1448{
1449return (cachedObject as Parameter).Value;
1450}
1451else if (cachedObject is Total)
1452{
1453object val = (cachedObject as Total).Value;
1454if (ConvertNulls && (val == null || val is DBNull))
1455val = 0;
1456
1457(cachedObject as Total).ExecuteTotal(val);
1458
1459return val;
1460}
1461
1462// calculate the expression
1463return CalcExpression(expression, value);
1464}
1465
1466private object ConvertToColumnDataType(object val, Type dataType, bool convertNulls)
1467{
1468if (val == null || val is DBNull)
1469{
1470if (convertNulls)
1471val = Converter.ConvertNull(dataType);
1472}
1473else
1474{
1475if (val is IConvertible)
1476{
1477Type t = Nullable.GetUnderlyingType(dataType);
1478try
1479{
1480val = Convert.ChangeType(val, t != null ? t : dataType);
1481}
1482catch (InvalidCastException)
1483{
1484// do nothing
1485}
1486catch (FormatException)
1487{
1488// do nothing
1489}
1490}
1491}
1492return val;
1493}
1494
1495/// <summary>
1496/// Returns an expression value.
1497/// </summary>
1498/// <param name="expression">The expression.</param>
1499/// <param name="value">The value of currently printing object.</param>
1500/// <returns>Returns the result of calculation.</returns>
1501/// <remarks>
1502/// This method is for internal use only, do not call it directly.
1503/// </remarks>
1504protected virtual object CalcExpression(string expression, Variant value)
1505{
1506if (expression.ToLower() == "true" || expression.ToLower() == "false")
1507{
1508expression = expression.ToLower();
1509}
1510
1511// try to calculate the expression
1512foreach (AssemblyDescriptor d in assemblies)
1513{
1514if (d.ContainsExpression(expression))
1515return d.CalcExpression(expression, value);
1516}
1517
1518#if REFLECTION_EMIT_COMPILER
1519if (Config.CompilerSettings.ReflectionEmitCompiler)
1520if (TryReflectionEmit(expression, value, out object returnValue))
1521return returnValue;
1522#endif
1523
1524// expression not found. Probably it was added after the start of the report.
1525// Compile new assembly containing this expression.
1526using (AssemblyDescriptor descriptor = new AssemblyDescriptor(this, CodeHelper.EmptyScript()))
1527{
1528assemblies.Add(descriptor);
1529descriptor.AddObjects();
1530descriptor.AddSingleExpression(expression);
1531descriptor.AddFunctions();
1532descriptor.Compile();
1533return descriptor.CalcExpression(expression, value);
1534}
1535}
1536
1537/// <summary>
1538/// Invokes the script method with given name.
1539/// </summary>
1540/// <param name="name">The name of the script method.</param>
1541/// <param name="parms">The method parameters.</param>
1542public object InvokeMethod(string name, object[] parms)
1543{
1544if (assemblies.Count > 0)
1545return assemblies[0].InvokeMethod(name, parms);
1546return null;
1547}
1548
1549private Column GetColumn(string complexName)
1550{
1551if (String.IsNullOrEmpty(complexName))
1552return null;
1553
1554CachedDataItem cachedItem = cachedDataItems[complexName] as CachedDataItem;
1555if (cachedItem != null)
1556return cachedItem.column;
1557
1558string[] names = complexName.Split('.');
1559cachedItem = cachedDataItems[names[0]] as CachedDataItem;
1560DataSourceBase data = cachedItem != null ? cachedItem.dataSource : GetDataSource(names[0]);
1561
1562return DataHelper.GetColumn(Dictionary, data, names, true);
1563}
1564
1565private object GetColumnValue(string complexName, bool convertNull)
1566{
1567Column column = GetColumn(complexName);
1568if (column == null)
1569return null;
1570
1571return ConvertToColumnDataType(column.Value, column.DataType, convertNull);
1572}
1573
1574private Variant GetTotalValue(string name, bool convertNull)
1575{
1576object value = Dictionary.Totals.GetValue(name);
1577if (convertNull && (value == null || value is DBNull))
1578value = 0;
1579
1580return new Variant(value);
1581}
1582
1583/// <summary>
1584/// Gets the data column's value. Automatically converts null value to 0, false or ""
1585/// depending on the column type.
1586/// </summary>
1587/// <param name="complexName">The name of the data column including the datasource name.</param>
1588/// <returns>If report is running, returns the column value. Otherwise returns <b>null</b>.</returns>
1589/// <remarks>
1590/// The return value of this method does not depend on the <see cref="ConvertNulls"/> property.
1591/// </remarks>
1592/// <example>
1593/// <code>
1594/// string employeeName = (string)report.GetColumnValue("Employees.FirstName");
1595/// </code>
1596/// </example>
1597public object GetColumnValue(string complexName)
1598{
1599return GetColumnValue(complexName, true);
1600}
1601
1602/// <summary>
1603/// Gets the data column's value. This method does not convert null values.
1604/// </summary>
1605/// <param name="complexName">The name of the data column including the datasource name.</param>
1606/// <returns>If report is running, returns the column value.
1607/// Otherwise returns <b>null</b>.</returns>
1608public object GetColumnValueNullable(string complexName)
1609{
1610return GetColumnValue(complexName, false);
1611}
1612
1613/// <summary>
1614/// Gets the report parameter with given name.
1615/// </summary>
1616/// <param name="complexName">The name of the parameter.</param>
1617/// <returns>The <see cref="Parameter"/> object if found, otherwise <b>null</b>.</returns>
1618/// <remarks>
1619/// To find nested parameter, use the "." separator: "MainParameter.NestedParameter"
1620/// </remarks>
1621public Parameter GetParameter(string complexName)
1622{
1623if (IsRunning)
1624return cachedDataItems[complexName] as Parameter;
1625return DataHelper.GetParameter(Dictionary, complexName);
1626}
1627
1628/// <summary>
1629/// Gets a value of the parameter with given name.
1630/// </summary>
1631/// <param name="complexName">The name of the parameter.</param>
1632/// <returns>The parameter's value if found, otherwise <b>null</b>.</returns>
1633/// <remarks>
1634/// To find nested parameter, use the "." separator: "MainParameter.NestedParameter"
1635/// </remarks>
1636public object GetParameterValue(string complexName)
1637{
1638Parameter par = GetParameter(complexName);
1639if (par != null)
1640{
1641// avoid InvalidCastException when casting object that is int to double
1642if (par.DataType.Name == "Double" && par.Value.GetType() == typeof(int))
1643{
1644return (double)(int)par.Value;
1645}
1646return par.Value;
1647}
1648return null;
1649}
1650
1651/// <summary>
1652/// Sets the parameter's value.
1653/// </summary>
1654/// <param name="complexName">The name of the parameter.</param>
1655/// <param name="value">Value to set.</param>
1656/// <remarks>
1657/// Use this method to pass a value to the parameter that you've created in the "Data" window.
1658/// Such parameter may be used everythere in a report; for example, you can print its value
1659/// or use it in expressions.
1660/// <para/>You should call this method <b>after</b> the report was loaded and <b>before</b> you run it.
1661/// <para/>To access a nested parameter, use the "." separator: "MainParameter.NestedParameter"
1662/// <note type="caution">
1663/// This method will create the parameter if it does not exist.
1664/// </note>
1665/// </remarks>
1666/// <example>This example shows how to pass a value to the parameter with "MyParam" name:
1667/// <code>
1668/// // load the report
1669/// report1.Load("report.frx");
1670/// // setup the parameter
1671/// report1.SetParameterValue("MyParam", 10);
1672/// // show the report
1673/// report1.Show();
1674/// </code>
1675/// </example>
1676public void SetParameterValue(string complexName, object value)
1677{
1678Parameter par = GetParameter(complexName);
1679if (par == null)
1680par = DataHelper.CreateParameter(Dictionary, complexName);
1681if (par != null)
1682{
1683par.Value = value;
1684par.Expression = "";
1685}
1686
1687isParameterChanged = true;
1688}
1689
1690/// <summary>
1691/// Sets the parameter's expression.
1692/// </summary>
1693/// <param name="complexName">The name of the parameter.</param>
1694/// <param name="expression">Epression to set. It must be a valid FR expression.</param>
1695/// <remarks>
1696/// This method is used to create an expression for a parameter.
1697/// If the specified parameter does not exist, it will be created with the specified expression.
1698/// <br>
1699/// <b>Expression must be a valid FR expression to avoid exceptions.</b>
1700/// </br>
1701/// </remarks>
1702public void SetParameterExpression(string complexName, string expression)
1703{
1704Parameter par = GetParameter(complexName) ?? DataHelper.CreateParameter(Dictionary, complexName);
1705
1706if (par != null)
1707{
1708par.Expression = expression;
1709}
1710
1711isParameterChanged = true;
1712}
1713
1714/// <summary>
1715/// Gets a value of the system variable with specified name.
1716/// </summary>
1717/// <param name="complexName">Name of a variable.</param>
1718/// <returns>The variable's value if found, otherwise <b>null</b>.</returns>
1719public object GetVariableValue(string complexName)
1720{
1721return GetParameterValue(complexName);
1722}
1723
1724/// <summary>
1725/// Gets a value of the total with specified name.
1726/// </summary>
1727/// <param name="name">Name of total.</param>
1728/// <returns>The total's value if found, otherwise <b>0</b>.</returns>
1729/// <remarks>This method converts null values to 0 if the <see cref="ConvertNulls"/> property is set to true.
1730/// Use the <see cref="GetTotalValueNullable"/> method if you don't want the null conversion.
1731/// </remarks>
1732public Variant GetTotalValue(string name)
1733{
1734return GetTotalValue(name, ConvertNulls);
1735}
1736
1737/// <summary>
1738/// Gets a value of the total with specified name.
1739/// </summary>
1740/// <param name="name">Name of total.</param>
1741/// <returns>The total's value if found, otherwise <b>null</b>.</returns>
1742public Variant GetTotalValueNullable(string name)
1743{
1744return GetTotalValue(name, false);
1745}
1746
1747/// <summary>
1748/// Gets the datasource with specified name.
1749/// </summary>
1750/// <param name="alias">Alias name of a datasource.</param>
1751/// <returns>The datasource object if found, otherwise <b>null</b>.</returns>
1752public DataSourceBase GetDataSource(string alias)
1753{
1754return Dictionary.FindByAlias(alias) as DataSourceBase;
1755}
1756
1757#endregion Script related
1758
1759#region Public Methods
1760
1761/// <inheritdoc/>
1762public override void Assign(Base source)
1763{
1764BaseAssign(source);
1765}
1766
1767/// <summary>
1768/// Aborts the report execution.
1769/// </summary>
1770public void Abort()
1771{
1772SetAborted(true);
1773}
1774
1775/// <inheritdoc/>
1776public override Base FindObject(string name)
1777{
1778foreach (Base c in AllNamedObjects)
1779{
1780if (String.Compare(name, c.Name, true) == 0)
1781return c;
1782}
1783return null;
1784}
1785
1786/// <inheritdoc/>
1787public override void Clear()
1788{
1789base.Clear();
1790ClearReportProperties();
1791}
1792
1793/// <summary>
1794/// Updates the report component's styles.
1795/// </summary>
1796/// <remarks>
1797/// Call this method if you change the <see cref="Styles"/> collection.
1798/// </remarks>
1799public void ApplyStyles()
1800{
1801foreach (Base c in AllObjects)
1802{
1803if (c is ReportComponentBase)
1804(c as ReportComponentBase).Style = (c as ReportComponentBase).Style;
1805}
1806}
1807
1808/// <summary>
1809/// Sets prepared pages.
1810/// </summary>
1811/// <param name="pages"></param>
1812public void SetPreparedPages(Preview.PreparedPages pages)
1813{
1814preparedPages = pages;
1815if (pages != null)
1816pages.SetReport(this);
1817}
1818
1819internal void SetAborted(bool value)
1820{
1821aborted = value;
1822}
1823
1824internal void SetOperation(ReportOperation operation)
1825{
1826this.operation = operation;
1827}
1828
1829/// <summary>
1830/// This method fires the <b>StartReport</b> event and the script code connected
1831/// to the <b>StartReportEvent</b>.
1832/// </summary>
1833public void OnStartReport(EventArgs e)
1834{
1835SetRunning(true);
1836if (StartReport != null)
1837StartReport(this, e);
1838InvokeMethod(StartReportEvent, new object[] { this, e });
1839}
1840
1841/// <summary>
1842/// This method fires the <b>FinishReport</b> event and the script code connected
1843/// to the <b>FinishReportEvent</b>.
1844/// </summary>
1845public void OnFinishReport(EventArgs e)
1846{
1847SetRunning(false);
1848if (FinishReport != null)
1849FinishReport(this, e);
1850InvokeMethod(FinishReportEvent, new object[] { this, e });
1851}
1852
1853/// <summary>
1854/// Runs the Export event.
1855/// </summary>
1856/// <param name="e">ExportReportEventArgs object.</param>
1857public void OnExportParameters(ExportParametersEventArgs e)
1858{
1859if (ExportParameters != null)
1860{
1861ExportParameters(this, e);
1862}
1863}
1864
1865/// <summary>
1866/// Add the name of the assembly (in addition to the default) that will be used to compile the report script
1867/// </summary>
1868/// <param name="assembly_name">Assembly name</param>
1869/// <remarks>
1870/// For example: <code>report.AddReferencedAssembly("Newtonsoft.Json.dll")</code>
1871/// </remarks>
1872public void AddReferencedAssembly(string assembly_name)
1873{
1874string[] assemblies = ReferencedAssemblies;
1875Array.Resize(ref assemblies, assemblies.Length + 1);
1876assemblies[assemblies.Length - 1] = assembly_name;
1877ReferencedAssemblies = assemblies;
1878}
1879
1880/// <summary>
1881/// Add the names of the assembly (in addition to the default) that will be used to compile the report script
1882/// </summary>
1883/// <param name="assembly_names">Assembly's names</param>
1884public void AddReferencedAssembly(IList<string> assembly_names)
1885{
1886string[] assemblies = ReferencedAssemblies;
1887int oldLength = assemblies.Length;
1888Array.Resize(ref assemblies, oldLength + assembly_names.Count);
1889for (int i = 0; i < assembly_names.Count; i++)
1890{
1891assemblies[oldLength + i] = assembly_names[i];
1892}
1893ReferencedAssemblies = assemblies;
1894}
1895
1896/// <inheritdoc/>
1897public override void Serialize(FRWriter writer)
1898{
1899Report c = writer.DiffObject as Report;
1900writer.ItemName = IsAncestor ? "inherited" : ClassName;
1901if (BaseReport != c.BaseReport)
1902{
1903// when save to the report file, convert absolute path to the base report to relative path
1904// (based on the main report path). Do not convert when saving to the clipboard.
1905string value = writer.SerializeTo != SerializeTo.Undo ? GetRelativePathToBaseReport() : BaseReport;
1906writer.WriteStr("BaseReport", value);
1907// Fix bug with moving child report to another folder without parent report.
1908if (writer.SerializeTo == SerializeTo.Report)
1909writer.WriteStr("BaseReportAbsolutePath", BaseReport);
1910}
1911// always serialize ScriptLanguage because its default value depends on Config.ReportSettings.DefaultLanguage
1912writer.WriteValue("ScriptLanguage", ScriptLanguage);
1913if (ScriptText != c.ScriptText)
1914writer.WritePropertyValue("ScriptText", ScriptText);
1915if (!writer.AreEqual(ReferencedAssemblies, c.ReferencedAssemblies))
1916writer.WriteValue("ReferencedAssemblies", ReferencedAssemblies);
1917if (ConvertNulls != c.ConvertNulls)
1918writer.WriteBool("ConvertNulls", ConvertNulls);
1919if (DoublePass != c.DoublePass)
1920writer.WriteBool("DoublePass", DoublePass);
1921if (Compressed != c.Compressed)
1922writer.WriteBool("Compressed", Compressed);
1923if (UseFileCache != c.UseFileCache)
1924writer.WriteBool("UseFileCache", UseFileCache);
1925if (TextQuality != c.TextQuality)
1926writer.WriteValue("TextQuality", TextQuality);
1927if (SmoothGraphics != c.SmoothGraphics)
1928writer.WriteBool("SmoothGraphics", SmoothGraphics);
1929if (Password != c.Password)
1930writer.WriteStr("Password", Password);
1931if (InitialPageNumber != c.InitialPageNumber)
1932writer.WriteInt("InitialPageNumber", InitialPageNumber);
1933if (MaxPages != c.MaxPages)
1934writer.WriteInt("MaxPages", MaxPages);
1935if (StartReportEvent != c.StartReportEvent)
1936writer.WriteStr("StartReportEvent", StartReportEvent);
1937if (FinishReportEvent != c.FinishReportEvent)
1938writer.WriteStr("FinishReportEvent", FinishReportEvent);
1939ReportInfo.Serialize(writer, c.ReportInfo);
1940SerializeDesign(writer, c);
1941if (Styles.Count > 0)
1942writer.Write(Styles);
1943writer.Write(Dictionary);
1944if (writer.SaveChildren)
1945{
1946foreach (Base child in ChildObjects)
1947{
1948writer.Write(child);
1949}
1950}
1951}
1952
1953/// <inheritdoc/>
1954public override void Deserialize(FRReader reader)
1955{
1956if (reader.HasProperty("BaseReportAbsolutePath"))
1957{
1958BaseReportAbsolutePath = reader.ReadStr("BaseReportAbsolutePath");
1959}
1960
1961base.Deserialize(reader);
1962
1963// call OnAfterLoad method of each report object
1964foreach (Base c in AllObjects)
1965{
1966c.OnAfterLoad();
1967}
1968}
1969
1970/// <summary>
1971/// Saves the report to a stream.
1972/// </summary>
1973/// <param name="stream">The stream to save to.</param>
1974public void Save(Stream stream)
1975{
1976using (FRWriter writer = new FRWriter())
1977{
1978if (IsAncestor)
1979writer.GetDiff += new DiffEventHandler(GetDiff);
1980writer.Write(this);
1981
1982List<Stream> disposeList = new List<Stream>();
1983
1984if (Compressed)
1985{
1986stream = Compressor.Compress(stream);
1987disposeList.Add(stream);
1988}
1989if (!String.IsNullOrEmpty(Password))
1990{
1991stream = Crypter.Encrypt(stream, Password);
1992disposeList.Insert(0, stream);
1993}
1994writer.Save(stream);
1995
1996foreach (Stream s in disposeList)
1997{
1998s.Dispose();
1999}
2000}
2001}
2002
2003/// <summary>
2004/// Saves the report to a file.
2005/// </summary>
2006/// <param name="fileName">The name of the file to save to.</param>
2007public void Save(string fileName)
2008{
2009FileName = fileName;
2010using (FileStream f = new FileStream(fileName, FileMode.Create))
2011{
2012Save(f);
2013}
2014}
2015
2016/// <summary>
2017/// Saves the report to a stream with randomized values in data sources.
2018/// </summary>
2019/// <param name="stream">The stream to save to.</param>
2020public void SaveWithRandomData(Stream stream)
2021{
2022FRRandom random = new FRRandom();
2023random.RandomizeDataSources(Dictionary.DataSources);
2024Save(stream);
2025}
2026
2027/// <summary>
2028/// Saves the report to a file with randomized values in data sources.
2029/// </summary>
2030/// <param name="fileName">The name of the file to save to.</param>
2031public void SaveWithRandomData(string fileName)
2032{
2033FRRandom random = new FRRandom();
2034random.RandomizeDataSources(Dictionary.DataSources);
2035Save(fileName);
2036}
2037
2038/// <summary>
2039/// Loads report from a stream.
2040/// </summary>
2041/// <param name="stream">The stream to load from.</param>
2042/// <remarks>
2043/// The stream must be seekable.
2044/// When you load a password-protected report, you should specify a password in the <see cref="Password"/> property,
2045/// otherwise you will get the <see cref="DecryptException"/>. In this case you should ask for a password and try again:
2046/// <code>
2047/// try
2048/// {
2049/// report.Load(stream);
2050/// }
2051/// catch (DecryptException)
2052/// {
2053/// report.Password = report.ShowPasswordForm(); // or use your own form to do this
2054/// report.Load(stream);
2055/// }
2056/// </code>
2057/// </remarks>
2058public void Load(Stream stream)
2059{
2060string password = Password;
2061Clear();
2062
2063var saveStream = stream;
2064var saveStreamPos = stream.Position;
2065
2066using (FRReader reader = new FRReader(this))
2067{
2068List<Stream> disposeList = new List<Stream>();
2069if (Compressor.IsStreamCompressed(stream))
2070{
2071stream = Compressor.Decompress(stream, true);
2072disposeList.Add(stream);
2073}
2074bool crypted = Crypter.IsStreamEncrypted(stream);
2075if (crypted)
2076{
2077stream = Crypter.Decrypt(stream, password);
2078disposeList.Add(stream);
2079}
2080
2081try
2082{
2083reader.Load(stream);
2084}
2085catch (Exception e)
2086{
2087if (crypted)
2088{
2089saveStream.Position = saveStreamPos;
2090throw new DecryptException();
2091}
2092throw e;
2093}
2094finally
2095{
2096foreach (Stream s in disposeList)
2097{
2098try
2099{
2100s.Dispose();
2101}
2102catch
2103{
2104}
2105}
2106}
2107
2108reader.Read(this);
2109}
2110}
2111
2112/// <summary>
2113/// Loads the report from a file.
2114/// </summary>
2115/// <param name="fileName">The name of the file to load from.</param>
2116/// <remarks>
2117/// When you try to load the password-protected report, you will be asked
2118/// for a password. You also may specify the password in the <see cref="Password"/>
2119/// property before loading the report. In this case the report will load silently.
2120/// </remarks>
2121public void Load(string fileName)
2122{
2123this.fileName = "";
2124using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
2125{
2126this.fileName = fileName;
2127Load(f);
2128}
2129}
2130
2131/// <summary>
2132/// Loads the report from a string.
2133/// </summary>
2134/// <param name="s">The string that contains a stream in UTF8 or Base64 encoding.</param>
2135public void LoadFromString(string s)
2136{
2137if (String.IsNullOrEmpty(s))
2138return;
2139
2140byte[] buffer;
2141int startIndex = s.IndexOf("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
2142if (startIndex != -1)
2143{
2144buffer = Encoding.UTF8.GetBytes(s.Substring(startIndex));
2145}
2146else
2147{
2148buffer = Convert.FromBase64String(s);
2149}
2150
2151using (MemoryStream stream = new MemoryStream(buffer))
2152{
2153Load(stream);
2154}
2155}
2156
2157/// <summary>
2158/// Saves the report to a string.
2159/// </summary>
2160/// <returns>The string that contains a stream.</returns>
2161public string SaveToString()
2162{
2163using (MemoryStream stream = new MemoryStream())
2164{
2165Save(stream);
2166
2167if (Compressed || !String.IsNullOrEmpty(Password))
2168{
2169return Convert.ToBase64String(stream.ToArray());
2170}
2171else
2172{
2173return Encoding.UTF8.GetString(stream.ToArray());
2174}
2175}
2176}
2177
2178/// <summary>
2179/// Saves the report to a string using the Base64 encoding.
2180/// </summary>
2181/// <returns>The string that contains a stream.</returns>
2182public string SaveToStringBase64()
2183{
2184using (MemoryStream stream = new MemoryStream())
2185{
2186Save(stream);
2187return Convert.ToBase64String(stream.ToArray());
2188}
2189}
2190
2191/// <summary>
2192/// Creates the report instance and loads the report from a stream.
2193/// </summary>
2194/// <param name="stream">The stream to load from.</param>
2195/// <returns>The new report instance.</returns>
2196public static Report FromStream(Stream stream)
2197{
2198Report result = new Report();
2199result.Load(stream);
2200return result;
2201}
2202
2203/// <summary>
2204/// Creates the report instance and loads the report from a file.
2205/// </summary>
2206/// <param name="fileName">The name of the file to load from.</param>
2207/// <returns>The new report instance.</returns>
2208public static Report FromFile(string fileName)
2209{
2210Report result = new Report();
2211result.Load(fileName);
2212return result;
2213}
2214
2215/// <summary>
2216/// Creates the report instance and loads the report from a string.
2217/// </summary>
2218/// <param name="utf8String">The string that contains a stream in UTF8 encoding.</param>
2219/// <returns>The new report instance.</returns>
2220public static Report FromString(string utf8String)
2221{
2222Report result = new Report();
2223result.LoadFromString(utf8String);
2224return result;
2225}
2226
2227/// <summary>
2228/// Registers the application dataset with all its tables and relations to use it in the report.
2229/// </summary>
2230/// <param name="data">The application data.</param>
2231/// <remarks>
2232/// If you register more than one dataset, use the <see cref="RegisterData(DataSet, string)"/> method.
2233/// </remarks>
2234/// <example>
2235/// <code>
2236/// report1.Load("report.frx");
2237/// report1.RegisterData(dataSet1);
2238/// </code>
2239/// </example>
2240public void RegisterData(DataSet data)
2241{
2242Dictionary.RegisterDataSet(data, "Data", false);
2243}
2244
2245/// <summary>
2246/// Registers the application dataset with all its tables and relations to use it in the report and enables all its tables.
2247/// </summary>
2248/// <param name="data">The application data.</param>
2249/// <param name="enableAllTables">The boolean value indicating whether all tables should be enabled.</param>
2250/// <remarks>
2251/// If you register more than one dataset, use the <see cref="RegisterData(DataSet, string)"/> method.
2252/// </remarks>
2253/// <example>
2254/// <code>
2255/// report1.Load("report.frx");
2256/// report1.RegisterData(dataSet1, true);
2257/// </code>
2258/// </example>
2259public void RegisterData(DataSet data, bool enableAllTables)
2260{
2261Dictionary.RegisterDataSet(data, "Data", false);
2262foreach (DataTable table in data.Tables)
2263{
2264DataSourceBase ds = Report.GetDataSource(table.TableName);
2265if (ds != null)
2266ds.Enabled = true;
2267}
2268}
2269
2270/// <summary>
2271/// Registers the application dataset with specified name.
2272/// </summary>
2273/// <param name="data">The application data.</param>
2274/// <param name="name">The name of the data.</param>
2275/// <remarks>
2276/// Use this method if you register more than one dataset. You may specify any value
2277/// for the <b>name</b> parameter: it is not displayed anywhere in the designer and used only
2278/// to load/save a report. The name must be persistent and unique for each registered dataset.
2279/// </remarks>
2280/// <example>
2281/// <code>
2282/// report1.Load("report.frx");
2283/// report1.RegisterData(dataSet1, "NorthWind");
2284/// </code>
2285/// </example>
2286public void RegisterData(DataSet data, string name)
2287{
2288if (initializing)
2289{
2290initializeData = data;
2291initializeDataName = name;
2292}
2293else
2294Dictionary.RegisterDataSet(data, name, false);
2295}
2296
2297/// <summary>
2298/// Registers the application dataset with specified name and enables all its tables.
2299/// </summary>
2300/// <param name="data">The application data.</param>
2301/// <param name="name">The name of the data.</param>
2302/// <param name="enableAllTables">The boolean value indicating whether all tables should be enabled.</param>
2303/// <remarks>
2304/// Use this method if you register more than one dataset. You may specify any value
2305/// for the <b>name</b> parameter: it is not displayed anywhere in the designer and used only
2306/// to load/save a report. The name must be persistent and unique for each registered dataset.
2307/// </remarks>
2308/// <example>
2309/// <code>
2310/// report1.Load("report.frx");
2311/// report1.RegisterData(dataSet1, "NorthWind", true);
2312/// </code>
2313/// </example>
2314public void RegisterData(DataSet data, string name, bool enableAllTables)
2315{
2316if (initializing)
2317{
2318initializeData = data;
2319initializeDataName = name;
2320}
2321else
2322{
2323Dictionary.RegisterDataSet(data, name, false);
2324foreach (DataTable table in data.Tables)
2325{
2326DataSourceBase ds = Report.GetDataSource(table.TableName);
2327if (ds != null)
2328ds.Enabled = true;
2329}
2330}
2331}
2332
2333/// <summary>
2334/// Registers the application data table to use it in the report.
2335/// </summary>
2336/// <param name="data">The application data.</param>
2337/// <param name="name">The name of the data.</param>
2338/// <example>
2339/// <code>
2340/// report1.Load("report.frx");
2341/// report1.RegisterData(dataSet1.Tables["Orders"], "Orders");
2342/// </code>
2343/// </example>
2344public void RegisterData(DataTable data, string name)
2345{
2346Dictionary.RegisterDataTable(data, name, false);
2347}
2348
2349/// <summary>
2350/// Registers the application data view to use it in the report.
2351/// </summary>
2352/// <param name="data">The application data.</param>
2353/// <param name="name">The name of the data.</param>
2354/// <example>
2355/// <code>
2356/// report1.Load("report.frx");
2357/// report1.RegisterData(myDataView, "OrdersView");
2358/// </code>
2359/// </example>
2360public void RegisterData(DataView data, string name)
2361{
2362Dictionary.RegisterDataView(data, name, false);
2363}
2364
2365/// <summary>
2366/// Registers the application data relation to use it in the report.
2367/// </summary>
2368/// <param name="data">The application data.</param>
2369/// <param name="name">The name of the data.</param>
2370/// <remarks>
2371/// You may specify any value for the <b>name</b> parameter: it is not displayed anywhere
2372/// in the designer and used only to load/save a report. The name must be persistent
2373/// and unique for each registered relation.
2374/// </remarks>
2375/// <example>
2376/// <code>
2377/// report1.Load("report.frx");
2378/// report1.RegisterData(myDataRelation, "myRelation");
2379/// </code>
2380/// </example>
2381public void RegisterData(DataRelation data, string name)
2382{
2383Dictionary.RegisterDataRelation(data, name, false);
2384}
2385
2386/// <summary>
2387/// <b>Obsolete</b>. Registers the application business object to use it in the report.
2388/// </summary>
2389/// <param name="data">Application data.</param>
2390/// <param name="name">Name of the data.</param>
2391/// <param name="flags">Not used.</param>
2392/// <param name="maxNestingLevel">Maximum nesting level of business objects.</param>
2393/// <remarks>
2394/// This method is obsolete. Use the <see cref="RegisterData(IEnumerable, string)"/> method instead.
2395/// </remarks>
2396public void RegisterData(IEnumerable data, string name, BOConverterFlags flags, int maxNestingLevel)
2397{
2398RegisterData(data, name, maxNestingLevel);
2399}
2400
2401/// <summary>
2402/// Registers the application business object to use it in the report.
2403/// </summary>
2404/// <param name="data">Application data.</param>
2405/// <param name="name">Name of the data.</param>
2406/// <example>
2407/// <code>
2408/// report1.Load("report.frx");
2409/// report1.RegisterData(myBusinessObject, "Customers");
2410/// </code>
2411/// </example>
2412public void RegisterData(IEnumerable data, string name)
2413{
2414if (initializing)
2415{
2416initializeData = data;
2417initializeDataName = name;
2418}
2419else
2420Dictionary.RegisterBusinessObject(data, name, 1, false);
2421}
2422
2423/// <summary>
2424/// Registers the application business object to use it in the report.
2425/// </summary>
2426/// <param name="data">Application data.</param>
2427/// <param name="name">Name of the data.</param>
2428/// <param name="maxNestingLevel">Maximum nesting level of business objects.</param>
2429/// <remarks>
2430/// This method creates initial datasource with specified nesting level. It is useful if
2431/// you create a report in code. In most cases, you don't need to specify the nesting level
2432/// because it may be selected in the designer's "Choose Report Data" dialog.
2433/// </remarks>
2434public void RegisterData(IEnumerable data, string name, int maxNestingLevel)
2435{
2436Dictionary.RegisterBusinessObject(data, name, maxNestingLevel, false);
2437}
2438
2439/// <summary>
2440/// Registers the application cube link to use it in the report.
2441/// </summary>
2442/// <param name="data">The application data.</param>
2443/// <param name="name">The name of the data.</param>
2444/// <example>
2445/// <code>
2446/// report1.Load("report.frx");
2447/// report1.RegisterData(myCubeLink, "Orders");
2448/// </code>
2449/// </example>
2450public void RegisterData(IBaseCubeLink data, string name)
2451{
2452Dictionary.RegisterCubeLink(data, name, false);
2453}
2454
2455/// <summary>
2456/// Prepares the report.
2457/// </summary>
2458/// <returns><b>true</b> if report was prepared succesfully.</returns>
2459public bool Prepare()
2460{
2461return Prepare(false);
2462}
2463
2464#if ASYNC
2465/// <summary>
2466/// Prepares the report asynchronously.
2467/// </summary>
2468/// <param name="token">Cancellation token</param>
2469/// <returns><b>true</b> if report was prepared succesfully.</returns>
2470[EditorBrowsable(EditorBrowsableState.Never)] // TODO
2471public Task<bool> PrepareAsync(CancellationToken token = default)
2472{
2473return PrepareAsync(false, token);
2474}
2475
2476private async Task<bool> PrepareAsync(bool append, CancellationToken token = default)
2477{
2478SetRunning(true);
2479try
2480{
2481if (PreparedPages == null || !append)
2482{
2483ClearPreparedPages();
2484
2485SetPreparedPages(new Preview.PreparedPages(this));
2486}
2487engine = new ReportEngine(this);
2488
2489if (!Config.WebMode)
2490StartPerformanceCounter();
2491
2492try
2493{
2494await CompileAsync(token).ConfigureAwait(false);
2495isParameterChanged = false;
2496return Engine.Run(true, append, true);
2497}
2498finally
2499{
2500if (!Config.WebMode)
2501StopPerformanceCounter();
2502}
2503}
2504finally
2505{
2506SetRunning(false);
2507}
2508}
2509
2510#endif
2511
2512/// <summary>
2513/// Prepares the report.
2514/// </summary>
2515/// <param name="append">Specifies whether the new report should be added to a
2516/// report that was prepared before.</param>
2517/// <returns><b>true</b> if report was prepared succesfully.</returns>
2518/// <remarks>
2519/// Use this method to merge prepared reports.
2520/// </remarks>
2521/// <example>This example shows how to merge two reports and preview the result:
2522/// <code>
2523/// Report report = new Report();
2524/// report.Load("report1.frx");
2525/// report.Prepare();
2526/// report.Load("report2.frx");
2527/// report.Prepare(true);
2528/// report.ShowPrepared();
2529/// </code>
2530/// </example>
2531public bool Prepare(bool append)
2532{
2533SetRunning(true);
2534try
2535{
2536if (PreparedPages == null || !append)
2537{
2538ClearPreparedPages();
2539
2540SetPreparedPages(new Preview.PreparedPages(this));
2541}
2542engine = new ReportEngine(this);
2543
2544if (!Config.WebMode)
2545StartPerformanceCounter();
2546
2547try
2548{
2549Compile();
2550isParameterChanged = false;
2551return Engine.Run(true, append, true);
2552}
2553finally
2554{
2555if (!Config.WebMode)
2556StopPerformanceCounter();
2557}
2558}
2559finally
2560{
2561SetRunning(false);
2562}
2563}
2564
2565/// <summary>
2566/// Prepares the report with pages limit.
2567/// </summary>
2568/// <param name="pagesLimit">Pages limit. The number of pages equal or less will be prepared.</param>
2569/// <returns><b>true</b> if report was prepared succesfully.</returns>
2570public bool Prepare(int pagesLimit)
2571{
2572SetRunning(true);
2573try
2574{
2575ClearPreparedPages();
2576SetPreparedPages(new Preview.PreparedPages(this));
2577engine = new ReportEngine(this);
2578
2579if (!Config.WebMode)
2580StartPerformanceCounter();
2581
2582try
2583{
2584Compile();
2585return Engine.Run(true, false, true, pagesLimit);
2586}
2587finally
2588{
2589if (!Config.WebMode)
2590StopPerformanceCounter();
2591}
2592}
2593finally
2594{
2595SetRunning(false);
2596}
2597}
2598
2599/// <summary>
2600/// For internal use only.
2601/// </summary>
2602[EditorBrowsable(EditorBrowsableState.Never)]
2603public void PreparePhase1()
2604{
2605bool webDialog = false;
2606SetRunning(true);
2607if (preparedPages != null)
2608{
2609// if prepared pages are set before => it's call method again => it's web dialog
2610webDialog = true;
2611preparedPages.Clear();
2612}
2613SetPreparedPages(new Preview.PreparedPages(this));
2614engine = new ReportEngine(this);
2615Compile();
2616Engine.RunPhase1(true, webDialog);
2617}
2618
2619/// <summary>
2620/// For internal use only.
2621/// </summary>
2622[EditorBrowsable(EditorBrowsableState.Never)]
2623public void PreparePhase2(int? pagesLimit = null)
2624{
2625Engine.RunPhase2(pagesLimit);
2626SetRunning(false);
2627}
2628
2629/// <summary>
2630/// Refresh the current report.
2631/// </summary>
2632/// <remarks>
2633/// Call this method in the Click or MouseUp event handler of a report object to refresh
2634/// the currently previewed report. Report will be generated again, but without dialog forms.
2635/// </remarks>
2636public void Refresh()
2637{
2638needRefresh = true;
2639}
2640
2641/// <summary>
2642/// Refresh prepared report after interactive actions.
2643/// </summary>
2644public void InteractiveRefresh()
2645{
2646PreparedPages.ClearPageCache();
2647InternalRefresh();
2648}
2649
2650/// <summary>
2651/// Serialize report object from string
2652/// </summary>
2653/// <returns>Serialized report object from string</returns>
2654[EditorBrowsable(EditorBrowsableState.Never)]
2655public ReportComponentBase Xml(string xml)
2656{
2657XmlDocument doc = new XmlDocument();
2658using (TextReader reader = new StringReader(xml))
2659{
2660doc.WriteHeader = false;
2661doc.ReadHeader = true;
2662doc.Load(reader);
2663
2664}
2665using (FRReader reader = new FRReader(this, doc.Root))
2666{
2667
2668reader.DeserializeFrom = SerializeTo.Clipboard;
2669return reader.Read() as ReportComponentBase;
2670}
2671}
2672
2673
2674internal void InternalRefresh()
2675{
2676SetRunning(true);
2677try
2678{
2679Engine.Run(false, false, false);
2680}
2681finally
2682{
2683SetRunning(false);
2684}
2685}
2686
2687
2688internal TextRenderingHint GetTextQuality()
2689{
2690switch (this.TextQuality)
2691{
2692case TextQuality.Regular:
2693return TextRenderingHint.AntiAliasGridFit;
2694
2695case TextQuality.ClearType:
2696return TextRenderingHint.ClearTypeGridFit;
2697
2698case TextQuality.AntiAlias:
2699return TextRenderingHint.AntiAlias;
2700
2701case TextQuality.SingleBPP:
2702return TextRenderingHint.SingleBitPerPixel;
2703
2704case TextQuality.SingleBPPGridFit:
2705return TextRenderingHint.SingleBitPerPixelGridFit;
2706}
2707
2708return TextRenderingHint.SystemDefault;
2709}
2710
2711
2712/// <summary>
2713/// Prepare page
2714/// </summary>
2715/// <param name="page"></param>
2716public void PreparePage(ReportPage page)
2717{
2718SetRunning(true);
2719try
2720{
2721Engine.Run(false, false, false, page);
2722}
2723finally
2724{
2725SetRunning(false);
2726}
2727}
2728
2729/// <summary>
2730/// Prepare page
2731/// </summary>
2732/// <param name="page"></param>
2733/// <param name="isDetailPage"> Flag indicating whether the page is a detail page. </param>
2734public void PreparePage(ReportPage page, bool isDetailPage)
2735{
2736bool pageVisible = page.Visible;
2737if (isDetailPage)
2738page.Visible = true;
2739PreparePage(page);
2740page.Visible = pageVisible;
2741}
2742
2743/// <summary>
2744/// Exports a report. Report should be prepared using the <see cref="Prepare()"/> method.
2745/// </summary>
2746/// <param name="export">The export filter.</param>
2747/// <param name="stream">Stream to save export result to.</param>
2748public void Export(ExportBase export, Stream stream)
2749{
2750export.Export(this, stream);
2751}
2752
2753/// <summary>
2754/// Exports a report. Report should be prepared using the <see cref="Prepare()"/> method.
2755/// </summary>
2756/// <param name="export">The export filter.</param>
2757/// <param name="fileName">File name to save export result to.</param>
2758public void Export(ExportBase export, string fileName)
2759{
2760export.Export(this, fileName);
2761}
2762
2763/// <summary>
2764/// Saves the prepared report. Report should be prepared using the <see cref="Prepare()"/> method.
2765/// </summary>
2766/// <param name="fileName">File name to save to.</param>
2767public void SavePrepared(string fileName)
2768{
2769if (PreparedPages != null)
2770PreparedPages.Save(fileName);
2771}
2772
2773/// <summary>
2774/// Saves the prepared report. Report should be prepared using the <see cref="Prepare()"/> method.
2775/// </summary>
2776/// <param name="stream">Stream to save to.</param>
2777public void SavePrepared(Stream stream)
2778{
2779if (PreparedPages != null)
2780PreparedPages.Save(stream);
2781}
2782
2783/// <summary>
2784/// Loads the prepared report from a .fpx file.
2785/// </summary>
2786/// <param name="fileName">File name to load form.</param>
2787public void LoadPrepared(string fileName)
2788{
2789isLoadPrepared = true;
2790if (PreparedPages == null)
2791SetPreparedPages(new FastReport.Preview.PreparedPages(this));
2792PreparedPages.Load(fileName);
2793}
2794
2795/// <summary>
2796/// Loads the prepared report from a .fpx file.
2797/// </summary>
2798/// <param name="stream">Stream to load from.</param>
2799public void LoadPrepared(Stream stream)
2800{
2801isLoadPrepared = true;
2802if (PreparedPages == null)
2803SetPreparedPages(new FastReport.Preview.PreparedPages(this));
2804PreparedPages.Load(stream);
2805}
2806
2807#endregion Public Methods
2808
2809/// <summary>
2810/// Initializes a new instance of the <see cref="Report"/> class with default settings.
2811/// </summary>
2812public Report()
2813{
2814pages = new PageCollection(this);
2815reportInfo = new ReportInfo();
2816InitDesign();
2817styles = new StyleCollection();
2818Dictionary = new Dictionary();
2819graphicCache = new GraphicCache();
2820assemblies = new AssemblyCollection();
2821cachedDataItems = new Hashtable(StringComparer.InvariantCultureIgnoreCase); // needed for case insensitivity
2822storeInResources = true;
2823fileName = "";
2824autoFillDataSet = true;
2825tag = null;
2826ClearReportProperties();
2827SetFlags(Flags.CanMove | Flags.CanResize | Flags.CanDelete | Flags.CanEdit | Flags.CanChangeOrder |
2828Flags.CanChangeParent | Flags.CanCopy, false);
2829//FInlineImageCache = new InlineImageCache();
2830}
2831
2832static Report()
2833{
2834Config.Init();
2835}
2836
2837/// <summary>
2838/// Ensure that static constructor is called.
2839/// </summary>
2840public static void EnsureInit()
2841{
2842// do nothing, just ensure that static constructor is called.
2843}
2844
2845/// <summary>
2846/// Create name for all unnamed elements with prefix and start with number
2847/// </summary>
2848/// <param name="prefix">Prefix for name</param>
2849/// <param name="number">Number from which to start</param>
2850public void PostNameProcess(string prefix, int number)
2851{
2852int i = number;
2853
2854foreach (Base obj in AllObjects)
2855{
2856if (String.IsNullOrEmpty(obj.Name))
2857{
2858obj.SetName(prefix + i.ToString());
2859i++;
2860}
2861}
2862}
2863
2864private class CachedDataItem
2865{
2866public DataSourceBase dataSource;
2867public Column column;
2868}
2869}
2870}