diff --git a/ClosedXML.Report/Excel/Subtotal.cs b/ClosedXML.Report/Excel/Subtotal.cs index 6b35a1e..6fa9ed9 100644 --- a/ClosedXML.Report/Excel/Subtotal.cs +++ b/ClosedXML.Report/Excel/Subtotal.cs @@ -53,13 +53,13 @@ public SubtotalGroup AddGrandTotal(SummaryFuncTag[] summaries) { var rangeAddress = _range.ShiftRows(1).RangeAddress; _range.InsertRowsAbove(1, true); - gr = CreateGroup(Sheet.Range(rangeAddress), 1, 1, GrandLabel, summaries, false,true); + gr = CreateGroup(Sheet.Range(rangeAddress), 1, 1, GrandLabel, summaries, false, true); } else { var rangeAddress = _range.RangeAddress; _range.InsertRowsBelow(1, true); - gr = CreateGroup(Sheet.Range(rangeAddress), 1, 1, GrandLabel, summaries, false,true); + gr = CreateGroup(Sheet.Range(rangeAddress), 1, 1, GrandLabel, summaries, false, true); } gr.Column = 0; _groups.Add(gr); @@ -256,7 +256,7 @@ private void MoveRange(MoveData moveData) Sheet.Cell(moveData.TargetAddress.FirstAddress).Value = _tempSheet.Range(1, 1, srcRng.RowCount(), srcRng.ColumnCount()); } - private SubtotalGroup CreateGroup(IXLRange groupRng, int groupClmn, int level, string title, SummaryFuncTag[] summaries, bool pageBreaks,bool isGrandTotal=false) + private SubtotalGroup CreateGroup(IXLRange groupRng, int groupClmn, int level, string title, SummaryFuncTag[] summaries, bool pageBreaks, bool isGrandTotal = false) { var firstRow = groupRng.RangeAddress.FirstAddress.RowNumber; var lastRow = groupRng.RangeAddress.LastAddress.RowNumber; @@ -351,18 +351,37 @@ private MoveData[] ScanRange(int groupBy) var val = row.Cell(groupBy).GetString(); var isSummaryRow = row.IsSummary(); + var isLeftGroupEndLine = false; + if (false == isSummaryRow) + { + isLeftGroupEndLine = _groups.SingleOrDefault(gr => gr.Column == groupBy - 1 && + gr.SummaryRow == null && + gr.Range.RangeAddress.LastAddress.RowNumber == row.RowNumber()) != null; + } - if (string.IsNullOrEmpty(val) && !isSummaryRow) + if (string.IsNullOrEmpty(val) && !isSummaryRow) + { + if (groupStart > 0) { - if (groupStart > 0) - { - groups.Add(CreateMoveTask(groupBy, prevVal, _range.Cell(groupStart, 1), row.RowAbove().LastCell(), RangeType.DataRange)); - } - groups.Add(CreateMoveTask(groupBy, "", row.FirstCell(), row.LastCell(), RangeType.HeaderRow)); - prevVal = null; - groupStart = 0; - continue; + groups.Add(CreateMoveTask(groupBy, prevVal, _range.Cell(groupStart, 1), row.RowAbove().LastCell(), RangeType.DataRange)); } + groups.Add(CreateMoveTask(groupBy, "", row.FirstCell(), row.LastCell(), RangeType.HeaderRow)); + prevVal = null; + groupStart = 0; + continue; + } + + if (isLeftGroupEndLine) + { + var localGroupStart = groupStart == 0 + ? row.RangeAddress.Relative(_range.RangeAddress).FirstAddress.RowNumber + : groupStart; + + groups.Add(CreateMoveTask(groupBy, prevVal, _range.Cell(localGroupStart, 1), row.LastCell(), RangeType.DataRange)); + prevVal = null; + groupStart = 0; + continue; + } if (val != prevVal) { @@ -392,7 +411,7 @@ private MoveData CreateMoveTask(int groupColumn, string title, IXLCell firstCell { var groupRng = _range.Range(firstCell, lastCell); var level = firstCell.WorksheetRow().OutlineLevel; - var group = new MoveData(groupRng.RangeAddress, rangeType, title, level) {GroupColumn = groupColumn}; + var group = new MoveData(groupRng.RangeAddress, rangeType, title, level) { GroupColumn = groupColumn }; return group; } diff --git a/ClosedXML.Report/Options/GroupTag.cs b/ClosedXML.Report/Options/GroupTag.cs index f3d1660..5d565be 100644 --- a/ClosedXML.Report/Options/GroupTag.cs +++ b/ClosedXML.Report/Options/GroupTag.cs @@ -12,6 +12,7 @@ OPTION PARAMS OBJECTS RNG Priority "\PageBreaks" "\TotalLabel" "\GrandLabel" + "\DisableSubtotalLine" "SummaryAbove" Range rD Normal @@ -40,6 +41,7 @@ public class GroupTag : SortTag public bool PageBreaks => Parameters.ContainsKey("pagebreaks"); public bool DisableSubtotals => Parameters.ContainsKey("disablesubtotals"); + public bool DisableSubtotalLine => Parameters.ContainsKey("disablesubtotalline"); public bool Collapse => Parameters.ContainsKey("collapse"); public bool DisableOutLine => Parameters.ContainsKey("disableoutline"); public bool OutLine => !Parameters.ContainsKey("disableoutline"); @@ -63,7 +65,7 @@ public MergeMode MergeLabels return _mergeLabels.Value; } } - + private bool? _isWithHeader; public bool IsWithHeader => (bool)(_isWithHeader ?? (_isWithHeader = Parameters.ContainsKey("withheader"))); @@ -114,7 +116,7 @@ private void Process(ProcessingContext context, GroupTag[] groups, bool summaryA return; var r = root.Offset(0, 0, rows, columns); - + using (var subtotal = new Subtotal(r, summaryAbove, groups, context.Evaluator)) { if (TotalLabel != null) subtotal.TotalLabel = TotalLabel; @@ -129,15 +131,24 @@ private void Process(ProcessingContext context, GroupTag[] groups, bool summaryA foreach (var g in groups.OrderBy(x => x.Column)) { + // Todo: New Feature Group Without Subtotal. Only Merge. + if (g.DisableSubtotalLine) + { + subtotal.ScanForGroups(g.Column); + g.Level = ++level; + + continue; + } + Func labFormat = null; if (!string.IsNullOrEmpty(g.LabelFormat)) - labFormat = title => string.Format(LabelFormat, title); - + labFormat = title => string.Format(g.LabelFormat, title); + if (g.MergeLabels == MergeMode.Merge2 && summaries.Length == 0) subtotal.ScanForGroups(g.Column); else subtotal.GroupBy(g.Column, g.DisableSubtotals ? new SummaryFuncTag[0] : summaries, g.PageBreaks, labFormat); - + g.Level = ++level; } @@ -177,7 +188,7 @@ private static void FormatHeaderFooter(SubtotalGroup subGroup, IXLRangeRow group subGroup.HeaderRow.CopyConditionalFormatsFrom(groupRow); } - + if (subGroup.SummaryRow != null) { foreach (var cell in groupRow.Cells(c => c.HasFormula && !(c.GetCellText()?.Contains("<>")??false))) @@ -216,7 +227,11 @@ protected virtual void GroupRender(SubtotalGroup subGroup, GroupTag grData) var rng = subGroup.Range.Column(subGroup.Column); if (subGroup.Range.RowCount() > 1) { - int cellIdx = _maxLevel - subGroup.Level + 1; + // TODO: Wrong Style apply for merged cells if on right has grouped total + // But in first cell i expect already cell with value and style + // Plus with DisableSubtotalLine feature this became totally wrong + int cellIdx = 1; + //int cellIdx = _maxLevel - subGroup.Level + 1; // TODO: Comment for future investigation var style = rng.Cell(cellIdx).Style; rng.Merge(); rng.Style = style; diff --git a/tests/ClosedXML.Report.Tests/GroupTagTests.cs b/tests/ClosedXML.Report.Tests/GroupTagTests.cs index 185bf71..0cfa46b 100644 --- a/tests/ClosedXML.Report.Tests/GroupTagTests.cs +++ b/tests/ClosedXML.Report.Tests/GroupTagTests.cs @@ -37,7 +37,7 @@ public void Simple(string templateFile) { using (var db = new DbDemos()) { - var cust = db.customers.LoadWith(x=>x.Orders.First().Items).OrderBy(c => c.CustNo).First(x=>x.CustNo == 1356); + var cust = db.customers.LoadWith(x=>x.Orders.First().Items).OrderBy(c => c.CustNo).First(x => x.CustNo == 1356); cust.Logo = Resource.toms_diving_center; tpl.AddVariable("MoreOrders", cust.Orders.Take(5)); tpl.AddVariable(cust); @@ -78,6 +78,7 @@ public void EmptyDataSource(string templateFile) InlineData("GroupTagTests_MultiRanges.xlsx"), InlineData("GroupTagTests_FormulasWithTagsInGroupRow.xlsx"), InlineData("GroupTagTests_TotalLabel.xlsx"), + InlineData("GroupTagTests_DisableSubTotals_MergeLabels.xlsx") ] public void Customers(string templateFile) { diff --git a/tests/Gauges/GroupTagTests_DisableSubTotals_MergeLabels.xlsx b/tests/Gauges/GroupTagTests_DisableSubTotals_MergeLabels.xlsx new file mode 100644 index 0000000..7b7b1da Binary files /dev/null and b/tests/Gauges/GroupTagTests_DisableSubTotals_MergeLabels.xlsx differ diff --git a/tests/Templates/GroupTagTests_DisableSubTotals_MergeLabels.xlsx b/tests/Templates/GroupTagTests_DisableSubTotals_MergeLabels.xlsx new file mode 100644 index 0000000..a315789 Binary files /dev/null and b/tests/Templates/GroupTagTests_DisableSubTotals_MergeLabels.xlsx differ