List <GroupEntry> _NestedGroup; // group one hierarchy below internal GroupEntry(Grouping g, Sorting s, int start) { _Group = g; _Sort = s; _StartRow = start; _EndRow = -1; _NestedGroup = new List <GroupEntry>(); // Check to see if grouping and sorting are the same if (g == null || s == null) { return; // nothing to check if either is null } if (s.Items.Count != g.GroupExpressions.Items.Count) { return; } for (int i = 0; i < s.Items.Count; i++) { SortBy sb = s.Items[i] as SortBy; if (sb.Direction == SortDirectionEnum.Descending) { return; // TODO we could optimize this } FunctionField ff = sb.SortExpression.Expr as FunctionField; if (ff == null || ff.GetTypeCode() != TypeCode.String) { return; } GroupExpression ge = g.GroupExpressions.Items[i] as GroupExpression; FunctionField ff2 = ge.Expression.Expr as FunctionField; if (ff2 == null || ff.Fld != ff2.Fld) { return; } } _Sort = null; // we won't need to sort since the groupby will handle it correctly }
List <GroupExpression> _Items; // list of GroupExpression internal GroupExpressions(ReportDefn r, ReportLink p, XmlNode xNode) : base(r, p) { GroupExpression g; _Items = new List <GroupExpression>(); // Loop thru all the child nodes foreach (XmlNode xNodeLoop in xNode.ChildNodes) { if (xNodeLoop.NodeType != XmlNodeType.Element) { continue; } switch (xNodeLoop.Name) { case "GroupExpression": g = new GroupExpression(r, this, xNodeLoop); break; default: g = null; // don't know what this is // don't know this element - log it OwnerReport.rl.LogError(4, "Unknown GroupExpressions element '" + xNodeLoop.Name + "' ignored."); break; } if (g != null) { _Items.Add(g); } } if (_Items.Count == 0) { OwnerReport.rl.LogError(8, "GroupExpressions require at least one GroupExpression be defined."); } else { _Items.TrimExcess(); } }
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; }