diff --git a/ClosedXML/Excel/ConditionalFormats/IXLConditionalFormats.cs b/ClosedXML/Excel/ConditionalFormats/IXLConditionalFormats.cs index 541b12f..8ccfbdd 100644 --- a/ClosedXML/Excel/ConditionalFormats/IXLConditionalFormats.cs +++ b/ClosedXML/Excel/ConditionalFormats/IXLConditionalFormats.cs @@ -10,6 +10,5 @@ void Add(IXLConditionalFormat conditionalFormat); void RemoveAll(); void Remove(Predicate predicate); - void Compress(); } } diff --git a/ClosedXML/Excel/ConditionalFormats/XLConditionalFormat.cs b/ClosedXML/Excel/ConditionalFormats/XLConditionalFormat.cs index 5e665f8..5023880 100644 --- a/ClosedXML/Excel/ConditionalFormats/XLConditionalFormat.cs +++ b/ClosedXML/Excel/ConditionalFormats/XLConditionalFormat.cs @@ -47,6 +47,7 @@ && xx.Bottom == yy.Bottom && xx.Percent == yy.Percent && xx.ReverseIconOrder == yy.ReverseIconOrder + && xx.StopIfTrueInternal == yy.StopIfTrueInternal && xx.ShowIconOnly == yy.ShowIconOnly && xx.ShowBarOnly == yy.ShowBarOnly && _listComparer.Equals(xxValues, yyValues) @@ -59,7 +60,34 @@ public int GetHashCode(IXLConditionalFormat obj) { - throw new NotImplementedException(); + var xx = (XLConditionalFormat)obj; + var xStyle = xx._style ?? xx.Range.Worksheet.Workbook.GetStyleById(xx._styleCacheId); + var xValues = xx.Values.Values.Where(v => !v.IsFormula).Select(v => v.Value) + .Union(xx.Values.Values.Where(v => v.IsFormula).Select(f => ((XLCell)obj.Range.FirstCell()).GetFormulaR1C1(f.Value))); + + unchecked + { + var hashCode = xStyle.GetHashCode(); + hashCode = (hashCode * 397) ^ xx._styleCacheId; + hashCode = (hashCode * 397) ^ xx.CopyDefaultModify.GetHashCode(); + hashCode = (hashCode * 397) ^ xx.UpdatingStyle.GetHashCode(); + hashCode = (hashCode * 397) ^ xValues.GetHashCode(); + hashCode = (hashCode * 397) ^ (xx.Colors != null ? xx.Colors.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (xx.ContentTypes != null ? xx.ContentTypes.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (xx.IconSetOperators != null ? xx.IconSetOperators.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (_compareRange && xx.Range != null ? xx.Range.GetHashCode() : 0); + hashCode = (hashCode * 397) ^ (int)xx.ConditionalFormatType; + hashCode = (hashCode * 397) ^ (int)xx.TimePeriod; + hashCode = (hashCode * 397) ^ (int)xx.IconSetStyle; + hashCode = (hashCode * 397) ^ (int)xx.Operator; + hashCode = (hashCode * 397) ^ xx.Bottom.GetHashCode(); + hashCode = (hashCode * 397) ^ xx.Percent.GetHashCode(); + hashCode = (hashCode * 397) ^ xx.ReverseIconOrder.GetHashCode(); + hashCode = (hashCode * 397) ^ xx.ShowIconOnly.GetHashCode(); + hashCode = (hashCode * 397) ^ xx.ShowBarOnly.GetHashCode(); + hashCode = (hashCode * 397) ^ xx.StopIfTrueInternal.GetHashCode(); + return hashCode; + } } } diff --git a/ClosedXML/Excel/ConditionalFormats/XLConditionalFormats.cs b/ClosedXML/Excel/ConditionalFormats/XLConditionalFormats.cs index 847e388..940bd22 100644 --- a/ClosedXML/Excel/ConditionalFormats/XLConditionalFormats.cs +++ b/ClosedXML/Excel/ConditionalFormats/XLConditionalFormats.cs @@ -13,7 +13,7 @@ _conditionalFormats.Add(conditionalFormat); } - private bool RangeAbove(IXLRangeAddress newAddr, IXLRangeAddress addr) + private bool IsRangeAbove(IXLRangeAddress newAddr, IXLRangeAddress addr) { return newAddr.FirstAddress.ColumnNumber == addr.FirstAddress.ColumnNumber && newAddr.LastAddress.ColumnNumber == addr.LastAddress.ColumnNumber @@ -21,7 +21,7 @@ && (newAddr.LastAddress.RowNumber+1).Between(addr.FirstAddress.RowNumber, addr.LastAddress.RowNumber); } - private bool RangeBefore(IXLRangeAddress newAddr, IXLRangeAddress addr) + private bool IsRangeToLeft(IXLRangeAddress newAddr, IXLRangeAddress addr) { return newAddr.FirstAddress.RowNumber == addr.FirstAddress.RowNumber && newAddr.LastAddress.RowNumber == addr.LastAddress.RowNumber @@ -45,12 +45,14 @@ _conditionalFormats.RemoveAll(predicate); } - public void Compress() + /// + /// The method consolidate the same conditional formats, which are located in adjacent ranges. + /// + internal void Consolidate() { var formats = _conditionalFormats .OrderByDescending(x => x.Range.RangeAddress.FirstAddress.RowNumber) - .ThenByDescending(x => x.Range.RangeAddress.FirstAddress.ColumnNumber) - .ToList(); + .ThenByDescending(x => x.Range.RangeAddress.FirstAddress.ColumnNumber); var orderedFormats = formats.ToList(); @@ -62,9 +64,10 @@ Func IsSameFormat = f => f != item && f.Range.Worksheet.Position == item.Range.Worksheet.Position && XLConditionalFormat.NoRangeComparer.Equals(f, item); + // search for an adjacent range var format = orderedFormats .TakeWhile(f => f.Range.RangeAddress.FirstAddress.RowNumber >= itemRowNum) - .FirstOrDefault(f => (RangeAbove(itemAddr, f.Range.RangeAddress) || RangeBefore(itemAddr, f.Range.RangeAddress)) && IsSameFormat(f)); + .FirstOrDefault(f => (IsRangeAbove(itemAddr, f.Range.RangeAddress) || IsRangeToLeft(itemAddr, f.Range.RangeAddress)) && IsSameFormat(f)); if (format != null) { Merge(format, item); @@ -75,7 +78,7 @@ var newRowNum = newaddr.FirstAddress.RowNumber; var bottom = orderedFormats .TakeWhile(f => f.Range.RangeAddress.FirstAddress.RowNumber >= newRowNum) - .FirstOrDefault(f => RangeAbove(newaddr, f.Range.RangeAddress) && IsSameFormat(f)); + .FirstOrDefault(f => IsRangeAbove(newaddr, f.Range.RangeAddress) && IsSameFormat(f)); if (bottom != null) { Merge(bottom, format); @@ -85,6 +88,7 @@ continue; } + // search for an encompassable range format = _conditionalFormats.FirstOrDefault(f => f.Range.Contains(item.Range) && IsSameFormat(f)); if (format != null) { diff --git a/ClosedXML/Excel/XLWorkbook.cs b/ClosedXML/Excel/XLWorkbook.cs index 0f1c2ea..663249b 100644 --- a/ClosedXML/Excel/XLWorkbook.cs +++ b/ClosedXML/Excel/XLWorkbook.cs @@ -458,11 +458,6 @@ if (_loadSource == XLLoadSource.New) throw new InvalidOperationException("This is a new file. Please use one of the 'SaveAs' methods."); - foreach (var worksheet in Worksheets) - { - worksheet.ConditionalFormats.Compress(); - } - if (_loadSource == XLLoadSource.Stream) { CreatePackage(_originalStream, false, _spreadsheetDocumentType, options); @@ -500,11 +495,6 @@ { checkForWorksheetsPresent(); - foreach (var worksheet in Worksheets) - { - worksheet.ConditionalFormats.Compress(); - } - PathHelper.CreateDirectory(Path.GetDirectoryName(file)); if (_loadSource == XLLoadSource.New) { @@ -593,11 +583,6 @@ { checkForWorksheetsPresent(); - foreach (var worksheet in Worksheets) - { - worksheet.ConditionalFormats.Compress(); - } - if (_loadSource == XLLoadSource.New) { // dm 20130422, this method or better the method SpreadsheetDocument.Create which is called diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs index d80ed6f..fbb6162 100644 --- a/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/Excel/XLWorkbook_Save.cs @@ -3788,6 +3788,8 @@ private static void GenerateWorksheetPartContent( WorksheetPart worksheetPart, XLWorksheet xlWorksheet, bool evaluateFormulae, SaveContext context) { + ((XLConditionalFormats)xlWorksheet.ConditionalFormats).Consolidate(); + #region Worksheet if (worksheetPart.Worksheet == null) diff --git a/ClosedXML/Excel/XLWorksheet.cs b/ClosedXML/Excel/XLWorksheet.cs index 9b48ed2..ab7e3c3 100644 --- a/ClosedXML/Excel/XLWorksheet.cs +++ b/ClosedXML/Excel/XLWorksheet.cs @@ -1350,7 +1350,7 @@ conditionalFormat.Range.Dispose(); } ResumeEvents(); - newConditionalFormats.Compress(); + newConditionalFormats.Consolidate(); ConditionalFormats = newConditionalFormats; } diff --git a/ClosedXML_Tests/Excel/ConditionalFormats/ConditionalFormatesCompressTests.cs b/ClosedXML_Tests/Excel/ConditionalFormats/ConditionalFormatesCompressTests.cs index fc0748a..9bfd39e 100644 --- a/ClosedXML_Tests/Excel/ConditionalFormats/ConditionalFormatesCompressTests.cs +++ b/ClosedXML_Tests/Excel/ConditionalFormats/ConditionalFormatesCompressTests.cs @@ -5,7 +5,7 @@ namespace ClosedXML_Tests.Excel.ConditionalFormats { [TestFixture] - public class ConditionalFormatesCompressTests + public class ConditionalFormatsCompressTests { [Test] public void ConsecutivelyRowsCompressTest() @@ -17,7 +17,7 @@ SetFormat1(ws.Range("B4:C4").AddConditionalFormat()); SetFormat1(ws.Range("B3:C3").AddConditionalFormat()); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); Assert.AreEqual(1, ws.ConditionalFormats.Count()); var format = ws.ConditionalFormats.First(); @@ -35,7 +35,7 @@ SetFormat1(ws.Range("B2:B3").AddConditionalFormat()); SetFormat1(ws.Range("C2:C3").AddConditionalFormat()); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); Assert.AreEqual(1, ws.ConditionalFormats.Count()); var format = ws.ConditionalFormats.First(); @@ -52,7 +52,7 @@ SetFormat1(ws.Range("B11:D12").AddConditionalFormat()); SetFormat1(ws.Range("C12:D12").AddConditionalFormat()); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); Assert.AreEqual(1, ws.ConditionalFormats.Count()); var format = ws.ConditionalFormats.First(); @@ -69,7 +69,7 @@ SetFormat1(ws.Range("B14:C14").AddConditionalFormat()); SetFormat1(ws.Range("B14:B14").AddConditionalFormat()); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); Assert.AreEqual(1, ws.ConditionalFormats.Count()); var format = ws.ConditionalFormats.First(); @@ -86,7 +86,7 @@ SetFormat1(ws.Range("B16:D18").AddConditionalFormat()); SetFormat1(ws.Range("B18:D19").AddConditionalFormat()); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); Assert.AreEqual(1, ws.ConditionalFormats.Count()); var format = ws.ConditionalFormats.First(); @@ -104,7 +104,7 @@ SetFormat1(ws.Range("B8:B8").AddConditionalFormat()); SetFormat1(ws.Range("B9:C9").AddConditionalFormat()); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); Assert.AreEqual(3, ws.ConditionalFormats.Count()); } @@ -118,7 +118,7 @@ SetFormat1(ws.Range("B11:D12").AddConditionalFormat()); SetFormat2(ws.Range("C12:D12").AddConditionalFormat()); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); Assert.AreEqual(2, ws.ConditionalFormats.Count()); } @@ -133,4 +133,4 @@ format.WhenEquals(5).Fill.SetBackgroundColor(XLColor.AliceBlue); } } -} \ No newline at end of file +} diff --git a/ClosedXML_Tests/Excel/Ranges/CopyingRangesTests.cs b/ClosedXML_Tests/Excel/Ranges/CopyingRangesTests.cs index 1f1a29f..f2b8058 100644 --- a/ClosedXML_Tests/Excel/Ranges/CopyingRangesTests.cs +++ b/ClosedXML_Tests/Excel/Ranges/CopyingRangesTests.cs @@ -93,7 +93,7 @@ FillRow(ws.Row(2)); FillRow(ws.Row(3)); - ws.ConditionalFormats.Compress(); + ((XLConditionalFormats)ws.ConditionalFormats).Consolidate(); ws.Cell(5, 2).Value = ws.Row(2).Row(1, 7); @@ -115,4 +115,4 @@ row1.Cell(2).AddConditionalFormat().WhenEquals("=" + row1.FirstCell().CellRight(6).Address.ToStringRelative()).Fill.SetBackgroundColor(XLColor.Blue); } } -} \ No newline at end of file +}