private void RunGroupsPage(Pages pgs, TableWorkClass wc, List <GroupEntry> groupEntries, int endRow, float groupHeight) { Report rpt = pgs.Report; foreach (GroupEntry ge in groupEntries) { // set the group entry value int index; if (ge.Group != null) // groups? { ge.Group.ResetHideDuplicates(rpt); // reset duplicate checking index = ge.Group.GetIndex(rpt); // yes } else // no; must be main dataset { index = 0; } wc.Data.CurrentGroups[index] = ge; if (ge.NestedGroup.Count > 0) { RunGroupsSetGroups(rpt, wc, ge.NestedGroup); } // Handle the group header if (ge.Group != null) { TableGroup tg = ge.Group.Parent as TableGroup; if (ge.Group.PageBreakAtStart && !pgs.CurrentPage.IsEmpty()) { RunPageNew(pgs, pgs.CurrentPage); RunPageHeader(pgs, wc.Data.Data[ge.StartRow], false, tg); } if (tg != null && tg.Header != null) { // Calculate the number of table rows below this group; header, footer, details count if (ge.NestedGroup.Count > 0) { wc.GroupNestCount = RunGroupsCount(ge.NestedGroup, 0); } else { wc.GroupNestCount = (ge.EndRow - ge.StartRow + 1) * DetailsCount; } tg.Header.RunPage(pgs, wc.Data.Data[ge.StartRow]); wc.GroupNestCount = 0; } } float footerHeight = RunGroupsFooterHeight(pgs, wc, ge); if (ge.EndRow == endRow) { footerHeight += groupHeight; } // Handle the nested groups if any if (ge.NestedGroup.Count > 0) { RunGroupsPage(pgs, wc, ge.NestedGroup, ge.EndRow, footerHeight); } // If no nested groups then handle the detail rows for the group else if (_Details != null) { if (ge.Group != null && ge.Group.Parent as TableGroup == null) { // Group defined on table; means that Detail rows only put out once per group _Details.RunPage(pgs, wc.Data, ge.StartRow, ge.StartRow, footerHeight); } else { _Details.RunPage(pgs, wc.Data, ge.StartRow, ge.EndRow, footerHeight); } } else // When no details we need to figure out whether any more fits on a page { Page p = pgs.CurrentPage; if (p.YOffset + footerHeight > pgs.BottomOfPage) // Do we need new page to fit footer? { p = RunPageNew(pgs, p); RunPageHeader(pgs, wc.Data.Data[ge.EndRow], false, null); } } // Do the group footer if (ge.Group != null && ge.Group.Parent != null) { TableGroup tg = ge.Group.Parent as TableGroup; // detail groups will result in null if (tg != null && tg.Footer != null) { tg.Footer.RunPage(pgs, wc.Data.Data[ge.EndRow]); } if (ge.Group.PageBreakAtEnd && !pgs.CurrentPage.IsEmpty()) { RunPageNew(pgs, pgs.CurrentPage); RunPageHeader(pgs, wc.Data.Data[ge.StartRow], false, tg); } } } }
private void PrepRecursiveGroup(Report rpt, TableWorkClass wc) { // Prepare for processing recursive group Grouping g = wc.RecursiveGroup; IExpr parentExpr = g.ParentGroup; GroupExpression gexpr = g.GroupExpressions.Items[0] as GroupExpression; IExpr groupExpr = gexpr.Expression; TypeCode tc = groupExpr.GetTypeCode(); List <Row> odata = new List <Row>(wc.Data.Data); // this is the old data that we'll recreate using the recursive hierarchy List <Row> newrows = new List <Row>(odata.Count); // For now we assume on a single top of tree (and it must sort first as null) // spec is incomplete: should have ability to specify starting value of tree // TODO: pull all of the rows that start with null newrows.Add(odata[0]); // add the starting row odata.RemoveAt(0); // remove olddata // we need to build the group entry stack // Build the initial one wc.Groups = new List <GroupEntry>(); GroupEntry ge = new GroupEntry(null, null, 0); ge.EndRow = odata.Count - 1; wc.Groups.Add(ge); // top group List <GroupEntry> ges = new List <GroupEntry>(); ges.Add(ge); // loop thru the rows and find their children // we place the children right after the parent // this reorders the rows in the form of the hierarchy Row r; RecursiveCompare rc = new RecursiveCompare(rpt, parentExpr, tc, groupExpr); for (int iRow = 0; iRow < newrows.Count; iRow++) // go thru the temp rows { r = newrows[iRow]; r.GroupEntry = ge = new GroupEntry(g, null, iRow); // TODO: sort for this group?? r.GroupEntry.EndRow = iRow; // pull out all the rows that match this value int iMainRow = odata.BinarySearch(r, rc); if (iMainRow < 0) { for (int i = 0; i <= r.Level + 1 && i < ges.Count; i++) { ge = ges[i] as GroupEntry; Row rr = newrows[ge.StartRow]; // start row has the base level of group if (rr.Level < r.Level) { ge.EndRow = iRow; } } continue; } // look backward for starting row; // in case of duplicates, BinarySearch can land on any of the rows object cmpvalue = groupExpr.Evaluate(rpt, r); int sRow = iMainRow - 1; while (sRow >= 0) { object v = parentExpr.Evaluate(rpt, odata[sRow]); if (Filter.ApplyCompare(tc, cmpvalue, v) != 0) { break; } sRow--; } sRow++; // adjust; since we went just prior it // look forward for ending row int eRow = iMainRow + 1; while (eRow < odata.Count) { object v = parentExpr.Evaluate(rpt, odata[eRow]); if (Filter.ApplyCompare(tc, cmpvalue, v) != 0) { break; } eRow++; } // Build a group entry for this GroupEntry ge2 = ges[r.Level] as GroupEntry; ge2.NestedGroup.Add(ge); if (r.Level + 1 >= ges.Count) // ensure we have room in the array (based on level) { ges.Add(ge); // add to the array } else { ges[r.Level + 1] = ge; // put this in the array } // add all of them in; want the same order for these rows. int offset = 1; for (int tRow = sRow; tRow < eRow; tRow++) { Row tr = odata[tRow]; tr.Level = r.Level + 1; newrows.Insert(iRow + offset, tr); offset++; } // remove from old data odata.RemoveRange(sRow, eRow - sRow); } // update the groupentries for the very last row int lastrow = newrows.Count - 1; r = newrows[lastrow]; for (int i = 0; i < r.Level + 1 && i < ges.Count; i++) { ge = ges[i] as GroupEntry; ge.EndRow = lastrow; } wc.Data.Data = newrows; // we've completely replaced the rows return; }
private void RunGroups(IPresent ip, List <GroupEntry> groupEntries, TableWorkClass wc) { Report rpt = ip.Report(); GroupEntry fge = (GroupEntry)(groupEntries[0]); if (fge.Group != null) { ip.GroupingStart(fge.Group); } foreach (GroupEntry ge in groupEntries) { // set the group entry value int index; if (ge.Group != null) // groups? { ip.GroupingInstanceStart(ge.Group); ge.Group.ResetHideDuplicates(rpt); // reset duplicate checking index = ge.Group.GetIndex(rpt); // yes } else // no; must be main dataset { index = 0; } wc.Data.CurrentGroups[index] = ge; if (ge.NestedGroup.Count > 0) { RunGroupsSetGroups(rpt, wc, ge.NestedGroup); } // Handle the group header if (ge.Group != null && ge.Group.Parent != null) { TableGroup tg = ge.Group.Parent as TableGroup; if (tg != null && tg.Header != null) { // Calculate the number of table rows below this group; header, footer, details count if (ge.NestedGroup.Count > 0) { wc.GroupNestCount = RunGroupsCount(ge.NestedGroup, 0); } else { wc.GroupNestCount = (ge.EndRow - ge.StartRow + 1) * DetailsCount; } tg.Header.Run(ip, wc.Data.Data[ge.StartRow]); wc.GroupNestCount = 0; } } // Handle the nested groups if any if (ge.NestedGroup.Count > 0) { RunGroups(ip, ge.NestedGroup, wc); } // If no nested groups then handle the detail rows for the group else if (_Details != null) { if (ge.Group != null && ge.Group.Parent as TableGroup == null) { // Group defined on table; means that Detail rows only put out once per group _Details.Run(ip, wc.Data, ge.StartRow, ge.StartRow); } else { _Details.Run(ip, wc.Data, ge.StartRow, ge.EndRow); } } // Do the group footer if (ge.Group != null) { if (ge.Group.Parent != null) { TableGroup tg = ge.Group.Parent as TableGroup; // detail groups will result in null if (tg != null && tg.Footer != null) { tg.Footer.Run(ip, wc.Data.Data[ge.EndRow]); } } ip.GroupingInstanceEnd(ge.Group); } } if (fge.Group != null) { ip.GroupingEnd(fge.Group); } }
void RunPrep(Report rpt, Row row, TableWorkClass wc) { GroupEntry[] currentGroups; // We have some data if (_TableGroups != null || (_Details != null && (_Details.Sorting != null || _Details.Grouping != null))) // fix up the data { List <Row> saveData = wc.Data.Data; Grouping gr; Sorting srt; if (_Details == null) { gr = null; srt = null; } else { gr = _Details.Grouping; srt = _Details.Sorting; } wc.Data = new Rows(rpt, _TableGroups, gr, srt); wc.Data.Data = saveData; wc.Data.Sort(); PrepGroups(rpt, wc); } // If we haven't formed any groups then form one with all rows if (wc.Groups == null) { wc.Groups = new List <GroupEntry>(); GroupEntry ge = new GroupEntry(null, null, 0); if (wc.Data.Data != null) // Do we have any data? { ge.EndRow = wc.Data.Data.Count - 1; // yes } else { ge.EndRow = -1; // no } wc.Groups.Add(ge); // top group currentGroups = new GroupEntry[1]; } else if (_TableGroups != null) { int count = _TableGroups.Items.Count; if (_Details != null && _Details.Grouping != null) { count++; } currentGroups = new GroupEntry[count]; } else { currentGroups = new GroupEntry[1]; } wc.Data.CurrentGroups = currentGroups; SortGroups(rpt, wc.Groups, wc); }
private void PrepGroups(Report rpt, TableWorkClass wc) { wc.RecursiveGroup = null; if (_TableGroups == null) { // no tablegroups; check to ensure details is grouped if (_Details == null || _Details.Grouping == null) { return; // no groups to prepare } } int i = 0; // 1) Build array of all GroupExpression objects List <GroupExpression> gea = new List <GroupExpression>(); // count the number of groups int countG = 0; if (_TableGroups != null) { countG = _TableGroups.Items.Count; } Grouping dg = null; Sorting ds = null; if (_Details != null && _Details.Grouping != null) { dg = _Details.Grouping; ds = _Details.Sorting; countG++; } GroupEntry[] currentGroups = new GroupEntry[countG++]; if (_TableGroups != null) { // add in the groups for the tablegroup foreach (TableGroup tg in _TableGroups.Items) { if (tg.Grouping.ParentGroup != null) { wc.RecursiveGroup = tg.Grouping; } tg.Grouping.SetIndex(rpt, i); // set the index of this group (so we can find the GroupEntry) currentGroups[i++] = new GroupEntry(tg.Grouping, tg.Sorting, 0); foreach (GroupExpression ge in tg.Grouping.GroupExpressions.Items) { gea.Add(ge); } } } if (dg != null) { // add in the groups for the details grouping if (dg.ParentGroup != null) { wc.RecursiveGroup = dg; } dg.SetIndex(rpt, i); // set the index of this group (so we can find the GroupEntry) currentGroups[i++] = new GroupEntry(dg, ds, 0); foreach (GroupExpression ge in dg.GroupExpressions.Items) { gea.Add(ge); } } if (wc.RecursiveGroup != null) { if (gea.Count != 1) // Limitiation of implementation { throw new Exception("Error: Recursive groups must be the only group definition."); } PrepRecursiveGroup(rpt, wc); // only one group and it's recursive: optimization return; } // Save the typecodes, and grouping by groupexpression; for later use TypeCode[] tcs = new TypeCode[gea.Count]; Grouping[] grp = new Grouping[gea.Count]; i = 0; foreach (GroupExpression ge in gea) { grp[i] = (Grouping)(ge.Parent.Parent); // remember the group tcs[i++] = ge.Expression.GetTypeCode(); // remember type of expression } // 2) Loop thru the data, then loop thru the GroupExpression list wc.Groups = new List <GroupEntry>(); object[] savValues = null; object[] grpValues = null; int rowCurrent = 0; foreach (Row row in wc.Data.Data) { // Get the values for all the group expressions if (grpValues == null) { grpValues = new object[gea.Count]; } i = 0; foreach (GroupExpression ge in gea) { if (((Grouping)(ge.Parent.Parent)).ParentGroup == null) { grpValues[i++] = ge.Expression.Evaluate(rpt, row); } else { grpValues[i++] = null; // Want all the parentGroup to evaluate equal } } // For first row we just primed the pump; action starts on next row if (rowCurrent == 0) // always start new group on first row { rowCurrent++; savValues = grpValues; grpValues = null; continue; } // compare the values; if change then we have a group break for (i = 0; i < savValues.Length; i++) { if (Filter.ApplyCompare(tcs[i], savValues[i], grpValues[i]) != 0) { // start a new group; and force a break on every subgroup GroupEntry saveGe = null; for (int j = grp[i].GetIndex(rpt); j < currentGroups.Length; j++) { currentGroups[j].EndRow = rowCurrent - 1; if (j == 0) { wc.Groups.Add(currentGroups[j]); // top group } else if (saveGe == null) { currentGroups[j - 1].NestedGroup.Add(currentGroups[j]); } else { saveGe.NestedGroup.Add(currentGroups[j]); } saveGe = currentGroups[j]; // retain this GroupEntry currentGroups[j] = new GroupEntry(currentGroups[j].Group, currentGroups[j].Sort, rowCurrent); } savValues = grpValues; grpValues = null; break; // break out of the value comparison loop } } rowCurrent++; } // End of all rows force break on end of rows for (i = 0; i < currentGroups.Length; i++) { currentGroups[i].EndRow = rowCurrent - 1; if (i == 0) { wc.Groups.Add(currentGroups[i]); // top group } else { currentGroups[i - 1].NestedGroup.Add(currentGroups[i]); } } return; }
override internal void RunPage(Pages pgs, Row row) { Report r = pgs.Report; if (IsHidden(r, row)) { return; } TableWorkClass wc = GetValue(r); if (_IsGrid) { wc.Data = Rows.CreateOneRow(r); } else { wc.Data = GetFilteredData(r, row); } SetPagePositionBegin(pgs); if (!AnyRowsPage(pgs, wc.Data)) // if no rows return { return; // nothing left to do } RunPrep(r, row, wc); RunPageRegionBegin(pgs); Page p = pgs.CurrentPage; p.YOffset += this.RelativeY(r); // Calculate the xpositions of the columns TableColumns.CalculateXPositions(r, GetOffsetCalc(r) + LeftCalc(r), row); RunPageHeader(pgs, wc.Data.Data[0], true, null); if (wc.RecursiveGroup != null) { RunRecursiveGroupsPage(pgs, wc); } else { RunGroupsPage(pgs, wc, wc.Groups, wc.Data.Data.Count - 1, 0); } // Footer if (_Footer != null) { Row lrow = wc.Data.Data.Count > 0? wc.Data.Data[wc.Data.Data.Count - 1]: null; p = pgs.CurrentPage; // make sure the footer fits on the page if (p.YOffset + _Footer.HeightOfRows(pgs, lrow) > pgs.BottomOfPage) { p = RunPageNew(pgs, p); RunPageHeader(pgs, row, false, null); } _Footer.RunPage(pgs, lrow); } RunPageRegionEnd(pgs); SetPagePositionEnd(pgs, pgs.CurrentPage.YOffset); RemoveValue(r); }
override internal void Run(IPresent ip, Row row) { Report r = ip.Report(); TableWorkClass wc = GetValue(r); if (_IsGrid) { wc.Data = Rows.CreateOneRow(r); } else { wc.Data = GetFilteredData(r, row); } if (!AnyRows(ip, wc.Data)) // if no rows return { return; // nothing left to do } RunPrep(r, row, wc); if (!ip.TableStart(this, row)) { return; // render doesn't want to continue } if (_TableColumns != null) { _TableColumns.Run(ip, row); } // Header if (_Header != null) { ip.TableHeaderStart(_Header, row); Row frow = wc.Data.Data.Count > 0? wc.Data.Data[0]: null; _Header.Run(ip, frow); ip.TableHeaderEnd(_Header, row); } // Body ip.TableBodyStart(this, row); if (wc.RecursiveGroup != null) { RunRecursiveGroups(ip, wc); } else { RunGroups(ip, wc.Groups, wc); } ip.TableBodyEnd(this, row); // Footer if (_Footer != null) { ip.TableFooterStart(_Footer, row); Row lrow = wc.Data.Data.Count > 0? wc.Data.Data[wc.Data.Data.Count - 1]: null; _Footer.Run(ip, lrow); ip.TableFooterEnd(_Footer, row); } ip.TableEnd(this, row); RemoveValue(r); }
internal GroupEntryCompare(Report r, TableWorkClass w) { rpt = r; wc = w; }
internal int GetGroupNestCount(Report rpt) { TableWorkClass wc = GetValue(rpt); return(wc.GroupNestCount); }
private void RunRecursiveGroupsPage(Pages pgs, TableWorkClass wc) { List <Row> rows = wc.Data.Data; Row r; // Get any header/footer information for use in loop Header header = null; Footer footer = null; TableGroup tg = wc.RecursiveGroup.Parent as TableGroup; if (tg != null) { header = tg.Header; footer = tg.Footer; } bool bHeader = true; for (int iRow = 0; iRow < rows.Count; iRow++) { r = rows[iRow]; wc.Data.CurrentGroups[0] = r.GroupEntry; wc.GroupNestCount = r.GroupEntry.EndRow - r.GroupEntry.StartRow; if (bHeader) { bHeader = false; if (header != null) { Page p = pgs.CurrentPage; // this can change after running a row float height = p.YOffset + header.HeightOfRows(pgs, r); if (height > pgs.BottomOfPage) { p = RunPageNew(pgs, p); RunPageHeader(pgs, r, false, null); if (!header.RepeatOnNewPage) { header.RunPage(pgs, r); } } else { header.RunPage(pgs, r); } } } // determine need for group headers and/or footers bool bFooter = false; float footerHeight = 0; if (iRow < rows.Count - 1) { Row r2 = rows[iRow + 1]; if (r.Level > r2.Level) { if (footer != null) { bFooter = true; footerHeight = footer.HeightOfRows(pgs, r); } } else if (r.Level < r2.Level) { bHeader = true; } } if (_Details != null) { _Details.RunPage(pgs, wc.Data, iRow, iRow, footerHeight); } // and output the footer if needed if (bFooter) { footer.RunPage(pgs, r); } } if (footer != null) { footer.RunPage(pgs, rows[rows.Count - 1] as Row); } }