using System.ComponentModel; using FastReport.Utils; using FastReport.Data; using System.Drawing.Design; namespace FastReport { /// /// Specifies a sort order. /// /// /// This enumeration is used in the group header and in the "Matrix" object. /// public enum SortOrder { /// /// Specifies no sort (natural order). /// None, /// /// Specifies an ascending sort order. /// Ascending, /// /// Specifies a descending sort order. /// Descending } /// /// Represents a group header band. /// /// /// A simple group consists of one GroupHeaderBand and the DataBand that is set /// to the property. To create the nested groups, use the property. /// /// Only the last nested group can have data band. /// /// Use the property to set the group condition. The /// property can be used to set the sort order for group's data rows. You can also use the Sort /// property of the group's DataBand to specify additional sort. /// /// This example shows how to create nested groups. /// /// ReportPage page = report.Pages[0] as ReportPage; /// /// // create the main group /// GroupHeaderBand mainGroup = new GroupHeaderBand(); /// mainGroup.Height = Units.Millimeters * 10; /// mainGroup.Name = "MainGroup"; /// mainGroup.Condition = "[Orders.CustomerName]"; /// // add a group to the page /// page.Bands.Add(mainGroup); /// /// // create the nested group /// GroupHeaderBand nestedGroup = new GroupHeaderBand(); /// nestedGroup.Height = Units.Millimeters * 10; /// nestedGroup.Name = "NestedGroup"; /// nestedGroup.Condition = "[Orders.OrderDate]"; /// // add it to the main group /// mainGroup.NestedGroup = nestedGroup; /// /// // create a data band /// DataBand dataBand = new DataBand(); /// dataBand.Height = Units.Millimeters * 10; /// dataBand.Name = "GroupData"; /// dataBand.DataSource = report.GetDataSource("Orders"); /// // connect the databand to the nested group /// nestedGroup.Data = dataBand; /// /// public partial class GroupHeaderBand : HeaderFooterBandBase { #region Fields private GroupHeaderBand nestedGroup; private DataBand data; private GroupFooterBand groupFooter; private DataHeaderBand header; private DataFooterBand footer; private string condition; private SortOrder sortOrder; private bool keepTogether; private bool resetPageNumber; private object groupValue; #endregion #region Properties /// /// Gets or sets a nested group. /// /// /// Use this property to create nested groups. /// /// Only the last nested group can have data band. /// /// /// /// This example demonstrates how to create a group with nested group. /// /// ReportPage page; /// GroupHeaderBand group = new GroupHeaderBand(); /// group.NestedGroup = new GroupHeaderBand(); /// group.NestedGroup.Data = new DataBand(); /// page.Bands.Add(group); /// /// [Browsable(false)] public GroupHeaderBand NestedGroup { get { return nestedGroup; } set { SetProp(nestedGroup, value); nestedGroup = value; } } /// /// Gets or sets the group data band. /// /// /// Use this property to add a data band to a group. Note: only the last nested group can have Data band. /// /// /// This example demonstrates how to add a data band to a group. /// /// ReportPage page; /// GroupHeaderBand group = new GroupHeaderBand(); /// group.Data = new DataBand(); /// page.Bands.Add(group); /// /// [Browsable(false)] public DataBand Data { get { return data; } set { SetProp(data, value); data = value; } } /// /// Gets or sets a group footer. /// [Browsable(false)] public GroupFooterBand GroupFooter { get { return groupFooter; } set { SetProp(groupFooter, value); groupFooter = value; } } /// /// Gets or sets a header band. /// [Browsable(false)] public DataHeaderBand Header { get { return header; } set { SetProp(header, value); header = value; } } /// /// Gets or sets a footer band. /// /// /// To access a group footer band, use the property. /// [Browsable(false)] public DataFooterBand Footer { get { return footer; } set { SetProp(footer, value); footer = value; } } /// /// Gets or sets the group condition. /// /// /// This property can contain any valid expression. When running a report, this expression is calculated /// for each data row. When the value of this condition is changed, FastReport starts a new group. /// [Category("Data")] [Editor("FastReport.TypeEditors.ExpressionEditor, FastReport", typeof(UITypeEditor))] public string Condition { get { return condition; } set { condition = value; } } /// /// Gets or sets the sort order. /// /// /// FastReport can sort data rows automatically using the value. /// [DefaultValue(SortOrder.Ascending)] [Category("Behavior")] public SortOrder SortOrder { get { return sortOrder; } set { sortOrder = value; } } /// /// Gets or sets a value indicating that the group should be printed together on one page. /// [DefaultValue(false)] [Category("Behavior")] public bool KeepTogether { get { return keepTogether; } set { keepTogether = value; } } /// /// Gets or sets a value that determines whether to reset the page numbers when this group starts print. /// /// /// Typically you should set the property to true as well. /// [DefaultValue(false)] [Category("Behavior")] public bool ResetPageNumber { get { return resetPageNumber; } set { resetPageNumber = value; } } internal DataSourceBase DataSource { get { DataBand dataBand = GroupDataBand; return dataBand == null ? null : dataBand.DataSource; } } internal DataBand GroupDataBand { get { GroupHeaderBand group = this; while (group != null) { if (group.Data != null) return group.Data; group = group.NestedGroup; } return null; } } #endregion #region IParent /// public override void GetChildObjects(ObjectCollection list) { base.GetChildObjects(list); if (!IsRunning) { list.Add(header); list.Add(nestedGroup); list.Add(data); list.Add(groupFooter); list.Add(footer); } } /// public override bool CanContain(Base child) { return base.CanContain(child) || (child is DataBand && nestedGroup == null && data == null) || (child is GroupHeaderBand && (nestedGroup == null || nestedGroup is GroupHeaderBand) && data == null) || child is GroupFooterBand || child is DataHeaderBand || child is DataFooterBand; } /// public override void AddChild(Base child) { if (IsRunning) { base.AddChild(child); return; } if (child is GroupHeaderBand) NestedGroup = child as GroupHeaderBand; else if (child is DataBand) Data = child as DataBand; else if (child is GroupFooterBand) GroupFooter = child as GroupFooterBand; else if (child is DataHeaderBand) Header = child as DataHeaderBand; else if (child is DataFooterBand) Footer = child as DataFooterBand; else base.AddChild(child); } /// public override void RemoveChild(Base child) { base.RemoveChild(child); if (IsRunning) return; if (child is GroupHeaderBand && nestedGroup == child) NestedGroup = null; if (child is DataBand && data == child as DataBand) Data = null; if (child is GroupFooterBand && groupFooter == child) GroupFooter = null; if (child is DataHeaderBand && header == child) Header = null; if (child is DataFooterBand && footer == child) Footer = null; } #endregion #region Public Methods /// public override void Assign(Base source) { base.Assign(source); GroupHeaderBand src = source as GroupHeaderBand; Condition = src.Condition; SortOrder = src.SortOrder; KeepTogether = src.KeepTogether; ResetPageNumber = src.ResetPageNumber; } /// public override void Serialize(FRWriter writer) { GroupHeaderBand c = writer.DiffObject as GroupHeaderBand; base.Serialize(writer); if (writer.SerializeTo == SerializeTo.Preview) return; if (Condition != c.Condition) writer.WriteStr("Condition", Condition); if (SortOrder != c.SortOrder) writer.WriteValue("SortOrder", SortOrder); if (KeepTogether != c.KeepTogether) writer.WriteBool("KeepTogether", KeepTogether); if (ResetPageNumber != c.ResetPageNumber) writer.WriteBool("ResetPageNumber", ResetPageNumber); } /// public override string[] GetExpressions() { return new string[] { Condition }; } internal override bool IsEmpty() { if (NestedGroup != null) return NestedGroup.IsEmpty(); else if (Data != null) return Data.IsEmpty(); return base.IsEmpty(); } internal void InitDataSource() { DataBand dataBand = GroupDataBand; GroupHeaderBand group = this; int index = 0; // insert group sort to the databand while (group != null) { if (group.SortOrder != SortOrder.None) { dataBand.Sort.Insert(index, new Sort(group.Condition, group.SortOrder == SortOrder.Descending)); index++; } group = group.NestedGroup; } dataBand.InitDataSource(); } internal void FinalizeDataSource() { DataBand dataBand = GroupDataBand; GroupHeaderBand group = this; // remove group sort from the databand while (group != null) { if (group.SortOrder != SortOrder.None) dataBand.Sort.RemoveAt(0); group = group.NestedGroup; } } internal void ResetGroupValue() { if (!string.IsNullOrEmpty(Condition)) { groupValue = Report.Calc(Condition); } else { throw new GroupHeaderHasNoGroupCondition(Name); } } internal bool GroupValueChanged() { object value = null; if (!string.IsNullOrEmpty(Condition)) { value = Report.Calc(Condition); } else { throw new GroupHeaderHasNoGroupCondition(Name); } if (groupValue == null) { if (value == null) return false; return true; } return !groupValue.Equals(value); } #endregion /// /// Initializes a new instance of the class with default settings. /// public GroupHeaderBand() { condition = ""; sortOrder = SortOrder.Ascending; } } }