diff --git a/ClosedXML/Excel/AutoFilters/XLAutoFilter.cs b/ClosedXML/Excel/AutoFilters/XLAutoFilter.cs index 3e33697..ec79a5c 100644 --- a/ClosedXML/Excel/AutoFilters/XLAutoFilter.cs +++ b/ClosedXML/Excel/AutoFilters/XLAutoFilter.cs @@ -116,62 +116,59 @@ SortColumn = columnToSortBy; // Recalculate shown / hidden rows - if (Enabled) + using (var rows = Range.Rows(2, Range.RowCount())) { - using (var rows = Range.Rows(2, Range.RowCount())) - { - foreach (IXLRangeRow row in rows) - row.WorksheetRow().Unhide(); - } + foreach (IXLRangeRow row in rows) + row.WorksheetRow().Unhide(); + } - foreach (var kp in Filters) + foreach (var kp in Filters) + { + Boolean firstFilter = true; + foreach (XLFilter filter in kp.Value) { - Boolean firstFilter = true; - foreach (XLFilter filter in kp.Value) + var condition = filter.Condition; + var isText = filter.Value is String; + var isDateTime = filter.Value is DateTime; + + using (var rows = Range.Rows(2, Range.RowCount())) { - var condition = filter.Condition; - var isText = filter.Value is String; - var isDateTime = filter.Value is DateTime; - - using (var rows = Range.Rows(2, Range.RowCount())) + foreach (IXLRangeRow row in rows) { - foreach (IXLRangeRow row in rows) + //TODO : clean up filter matching - it's done in different place + Boolean match; + + if (isText) + match = condition(row.Cell(kp.Key).GetFormattedString()); + else if (isDateTime) + match = row.Cell(kp.Key).DataType == XLDataType.DateTime && condition(row.Cell(kp.Key).GetDateTime()); + else + match = row.Cell(kp.Key).DataType == XLDataType.Number && condition(row.Cell(kp.Key).GetDouble()); + + if (firstFilter) { - //TODO : clean up filter matching - it's done in different place - Boolean match; - - if (isText) - match = condition(row.Cell(kp.Key).GetFormattedString()); - else if (isDateTime) - match = row.Cell(kp.Key).DataType == XLDataType.DateTime && condition(row.Cell(kp.Key).GetDateTime()); + if (match) + row.WorksheetRow().Unhide(); else - match = row.Cell(kp.Key).DataType == XLDataType.Number && condition(row.Cell(kp.Key).GetDouble()); - - if (firstFilter) - { - if (match) - row.WorksheetRow().Unhide(); - else - row.WorksheetRow().Hide(); - } - else - { - if (filter.Connector == XLConnector.And) - { - if (!row.WorksheetRow().IsHidden) - { - if (match) - row.WorksheetRow().Unhide(); - else - row.WorksheetRow().Hide(); - } - } - else if (match) - row.WorksheetRow().Unhide(); - } + row.WorksheetRow().Hide(); } - firstFilter = false; + else + { + if (filter.Connector == XLConnector.And) + { + if (!row.WorksheetRow().IsHidden) + { + if (match) + row.WorksheetRow().Unhide(); + else + row.WorksheetRow().Hide(); + } + } + else if (match) + row.WorksheetRow().Unhide(); + } } + firstFilter = false; } } } diff --git a/ClosedXML/Excel/CalcEngine/Functions/Tally.cs b/ClosedXML/Excel/CalcEngine/Functions/Tally.cs index 93abf67..cd6b4d5 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/Tally.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/Tally.cs @@ -89,7 +89,7 @@ { double tmp; var vEnumerable = value as IEnumerable; - if (vEnumerable == null) + if (vEnumerable == null || vEnumerable is string) { if (TryParseToDouble(value, out tmp)) yield return tmp; @@ -100,7 +100,6 @@ { if (TryParseToDouble(v, out tmp)) yield return tmp; - break; } } } diff --git a/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs b/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs index 4354e04..081df15 100644 --- a/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs +++ b/ClosedXML/Excel/CalcEngine/Functions/XLMath.cs @@ -91,11 +91,11 @@ public static Boolean IsEven(Int32 value) { - return Math.Abs(value % 2) < XLHelper.Epsilon; + return Math.Abs(value % 2) == 0; } public static Boolean IsOdd(Int32 value) { - return Math.Abs(value % 2) > XLHelper.Epsilon; + return Math.Abs(value % 2) != 0; } public static string ToRoman(int number) diff --git a/ClosedXML/Excel/Cells/XLCell.cs b/ClosedXML/Excel/Cells/XLCell.cs index e11eaee..30fca92 100644 --- a/ClosedXML/Excel/Cells/XLCell.cs +++ b/ClosedXML/Excel/Cells/XLCell.cs @@ -933,7 +933,7 @@ _richText = null; } - if (_cellValue.Length > 0) + if (!string.IsNullOrEmpty(_cellValue)) { if (value == XLDataType.Boolean) { @@ -1628,8 +1628,8 @@ var cell = cells.First(); var field = table.Fields.First(f => f.Column.ColumnNumber() == cell.WorksheetColumn().ColumnNumber()); field.TotalsRowFunction = XLTotalsRowFunction.None; - field.TotalsRowLabel = value.ToString(); - this._cellValue = value.ToString(); + _cellValue = value.ToString(); + field.TotalsRowLabel = _cellValue; this.DataType = XLDataType.Text; return true; } diff --git a/ClosedXML/Excel/ConditionalFormats/Save/XLCFCellIsConverter.cs b/ClosedXML/Excel/ConditionalFormats/Save/XLCFCellIsConverter.cs index d846ce3..dfad5bc 100644 --- a/ClosedXML/Excel/ConditionalFormats/Save/XLCFCellIsConverter.cs +++ b/ClosedXML/Excel/ConditionalFormats/Save/XLCFCellIsConverter.cs @@ -16,11 +16,7 @@ conditionalFormattingRule.Operator = cf.Operator.ToOpenXml(); - var formula = new Formula(); - if (cf.Operator == XLCFOperator.Equal || cf.Operator == XLCFOperator.NotEqual) - formula.Text = val; - else - formula.Text = val; + var formula = new Formula(val); conditionalFormattingRule.Append(formula); if (cf.Operator == XLCFOperator.Between || cf.Operator == XLCFOperator.NotBetween) diff --git a/ClosedXML/Excel/DataValidation/IXLDataValidation.cs b/ClosedXML/Excel/DataValidation/IXLDataValidation.cs index 1c7b9fd..0d87c3c 100644 --- a/ClosedXML/Excel/DataValidation/IXLDataValidation.cs +++ b/ClosedXML/Excel/DataValidation/IXLDataValidation.cs @@ -5,7 +5,7 @@ public enum XLErrorStyle { Stop, Warning, Information } public enum XLAllowedValues { AnyValue, WholeNumber, Decimal, Date, Time, TextLength, List, Custom } public enum XLOperator { EqualTo, NotEqualTo, GreaterThan, LessThan, EqualOrGreaterThan, EqualOrLessThan, Between, NotBetween } - public interface IXLDataValidation + public interface IXLDataValidation : IDisposable { IXLRanges Ranges { get; set; } //void Delete(); diff --git a/ClosedXML/Excel/DataValidation/IXLDataValidations.cs b/ClosedXML/Excel/DataValidation/IXLDataValidations.cs index 9dfca5f..dccd8d1 100644 --- a/ClosedXML/Excel/DataValidation/IXLDataValidations.cs +++ b/ClosedXML/Excel/DataValidation/IXLDataValidations.cs @@ -3,7 +3,7 @@ namespace ClosedXML.Excel { - public interface IXLDataValidations: IEnumerable + public interface IXLDataValidations: IEnumerable, IDisposable { void Add(IXLDataValidation dataValidation); Boolean ContainsSingle(IXLRange range); diff --git a/ClosedXML/Excel/DataValidation/XLDataValidation.cs b/ClosedXML/Excel/DataValidation/XLDataValidation.cs index 3ee5896..9d5ec8b 100644 --- a/ClosedXML/Excel/DataValidation/XLDataValidation.cs +++ b/ClosedXML/Excel/DataValidation/XLDataValidation.cs @@ -197,5 +197,10 @@ { Initialize(); } + + public void Dispose() + { + Ranges?.Dispose(); + } } } diff --git a/ClosedXML/Excel/DataValidation/XLDataValidations.cs b/ClosedXML/Excel/DataValidation/XLDataValidations.cs index fa339f6..3387588 100644 --- a/ClosedXML/Excel/DataValidation/XLDataValidations.cs +++ b/ClosedXML/Excel/DataValidation/XLDataValidations.cs @@ -50,5 +50,10 @@ { _dataValidations.RemoveAll(dv => dv.Ranges.Contains(range)); } + + public void Dispose() + { + _dataValidations.ForEach(dv => dv.Dispose()); + } } } diff --git a/ClosedXML/Excel/Drawings/XLPicture.cs b/ClosedXML/Excel/Drawings/XLPicture.cs index b1e44e8..d0732db 100644 --- a/ClosedXML/Excel/Drawings/XLPicture.cs +++ b/ClosedXML/Excel/Drawings/XLPicture.cs @@ -333,12 +333,12 @@ internal void SetName(string value) { - if (value.IndexOfAny(InvalidNameChars.ToCharArray()) != -1) - throw new ArgumentException($"Picture names cannot contain any of the following characters: {InvalidNameChars}"); - if (String.IsNullOrWhiteSpace(value)) throw new ArgumentException("Picture names cannot be empty"); + if (value.IndexOfAny(InvalidNameChars.ToCharArray()) != -1) + throw new ArgumentException($"Picture names cannot contain any of the following characters: {InvalidNameChars}"); + if (value.Length > 31) throw new ArgumentException("Picture names cannot be more than 31 characters"); diff --git a/ClosedXML/Excel/Ranges/XLRange.cs b/ClosedXML/Excel/Ranges/XLRange.cs index a133105..4f5f4d2 100644 --- a/ClosedXML/Excel/Ranges/XLRange.cs +++ b/ClosedXML/Excel/Ranges/XLRange.cs @@ -804,7 +804,9 @@ public override bool Equals(object obj) { - var other = (XLRange)obj; + var other = obj as XLRange; + if (other == null) + return false; return RangeAddress.Equals(other.RangeAddress) && Worksheet.Equals(other.Worksheet); } diff --git a/ClosedXML/Excel/Ranges/XLRangeAddress.cs b/ClosedXML/Excel/Ranges/XLRangeAddress.cs index d900347..2594558 100644 --- a/ClosedXML/Excel/Ranges/XLRangeAddress.cs +++ b/ClosedXML/Excel/Ranges/XLRangeAddress.cs @@ -191,7 +191,9 @@ public override bool Equals(object obj) { - var other = (XLRangeAddress)obj; + var other = obj as XLRangeAddress; + if (other == null) + return false; return Worksheet.Equals(other.Worksheet) && FirstAddress.Equals(other.FirstAddress) && LastAddress.Equals(other.LastAddress); diff --git a/ClosedXML/Excel/Ranges/XLRanges.cs b/ClosedXML/Excel/Ranges/XLRanges.cs index 3b0650e..63c5458 100644 --- a/ClosedXML/Excel/Ranges/XLRanges.cs +++ b/ClosedXML/Excel/Ranges/XLRanges.cs @@ -220,8 +220,9 @@ public override bool Equals(object obj) { - var other = (XLRanges)obj; - + var other = obj as XLRanges; + if (other == null) + return false; return _ranges.Count == other._ranges.Count && _ranges.Select(thisRange => Enumerable.Contains(other._ranges, thisRange)).All(foundOne => foundOne); } diff --git a/ClosedXML/Excel/Rows/XLRow.cs b/ClosedXML/Excel/Rows/XLRow.cs index 697801e..2e660e0 100644 --- a/ClosedXML/Excel/Rows/XLRow.cs +++ b/ClosedXML/Excel/Rows/XLRow.cs @@ -336,7 +336,7 @@ else { Double rotation; - if (textRotation == 90 || textRotation == 180 || textRotation == 255) + if (textRotation == 90 || textRotation == 180) rotation = 90; else rotation = textRotation % 90; diff --git a/ClosedXML/Excel/Tables/IXLTableField.cs b/ClosedXML/Excel/Tables/IXLTableField.cs index 4c2fb00..9fb10ec 100644 --- a/ClosedXML/Excel/Tables/IXLTableField.cs +++ b/ClosedXML/Excel/Tables/IXLTableField.cs @@ -16,7 +16,7 @@ Custom } - public interface IXLTableField + public interface IXLTableField : IDisposable { /// /// Gets the corresponding column for this table field. diff --git a/ClosedXML/Excel/Tables/XLTable.cs b/ClosedXML/Excel/Tables/XLTable.cs index 4c70fc1..6eb0a9e 100644 --- a/ClosedXML/Excel/Tables/XLTable.cs +++ b/ClosedXML/Excel/Tables/XLTable.cs @@ -564,6 +564,8 @@ if (AutoFilter != null) AutoFilter.Dispose(); + Fields?.ForEach(field => field.Dispose()); + base.Dispose(); } diff --git a/ClosedXML/Excel/Tables/XLTableField.cs b/ClosedXML/Excel/Tables/XLTableField.cs index 0a975dd..c7b2bbf 100644 --- a/ClosedXML/Excel/Tables/XLTableField.cs +++ b/ClosedXML/Excel/Tables/XLTableField.cs @@ -213,5 +213,10 @@ } } } + + public void Dispose() + { + _column.Dispose(); + } } } diff --git a/ClosedXML/Excel/XLWorkbook_Load.cs b/ClosedXML/Excel/XLWorkbook_Load.cs index 7aa868f..fa2079c 100644 --- a/ClosedXML/Excel/XLWorkbook_Load.cs +++ b/ClosedXML/Excel/XLWorkbook_Load.cs @@ -278,7 +278,7 @@ var dTable = tableDefinitionPart.Table; String reference = dTable.Reference.Value; - String tableName = dTable?.Name ?? dTable.DisplayName ?? string.Empty; + String tableName = dTable.Name ?? dTable.DisplayName ?? string.Empty; if (String.IsNullOrWhiteSpace(tableName)) throw new InvalidDataException("The table name is missing."); @@ -324,7 +324,7 @@ if (dTable.AutoFilter != null) { xlTable.ShowAutoFilter = true; - LoadAutoFilterColumns(dTable.AutoFilter, (xlTable as XLTable).AutoFilter); + LoadAutoFilterColumns(dTable.AutoFilter, xlTable.AutoFilter); } else xlTable.ShowAutoFilter = false; @@ -374,7 +374,7 @@ // find cell by reference var cell = ws.Cell(c.Reference); - XLComment xlComment = cell.Comment as XLComment; + var xlComment = cell.Comment; xlComment.Author = authors[(int)c.AuthorId.Value].InnerText; //xlComment.ShapeId = (Int32)c.ShapeId.Value; //ShapeIdManager.Add(xlComment.ShapeId); @@ -384,7 +384,7 @@ { var runProperties = run.RunProperties; String text = run.Text.InnerText.FixNewLines(); - var rt = cell.Comment.AddText(text); + var rt = xlComment.AddText(text); LoadFont(runProperties, rt); } @@ -908,7 +908,7 @@ xdoc = XDocumentExtensions.Load(vmlPart.GetStream(FileMode.Open)); //Probe for comments - if (xdoc.Root == null) continue; + if (xdoc?.Root == null) continue; var shape = GetCommentShape(xdoc); if (shape != null) break; } @@ -1361,12 +1361,9 @@ else formula = cell.CellFormula.Text; - if (cell.CellFormula.Reference != null) - { - // Parent cell of shared formulas - // Child cells will use this shared index to set its R1C1 style formula - xlCell.FormulaReference = ws.Range(cell.CellFormula.Reference.Value).RangeAddress; - } + // Parent cell of shared formulas + // Child cells will use this shared index to set its R1C1 style formula + xlCell.FormulaReference = ws.Range(cell.CellFormula.Reference.Value).RangeAddress; xlCell.FormulaA1 = formula; sharedFormulasR1C1.Add(cell.CellFormula.SharedIndex.Value, xlCell.FormulaR1C1); @@ -2144,7 +2141,7 @@ if (conditionalFormat.ConditionalFormatType == XLConditionalFormatType.CellIs && fr.Operator != null) conditionalFormat.Operator = fr.Operator.Value.ToClosedXml(); - if (fr.Text != null && !String.IsNullOrWhiteSpace(fr.Text)) + if (!String.IsNullOrWhiteSpace(fr.Text)) conditionalFormat.Values.Add(GetFormula(fr.Text.Value)); if (conditionalFormat.ConditionalFormatType == XLConditionalFormatType.Top10) diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs index 6bc0f59..66221b7 100644 --- a/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/Excel/XLWorkbook_Save.cs @@ -1069,6 +1069,9 @@ { if (c.HasArrayFormula) { + if (c.FormulaReference == null) + c.FormulaReference = c.AsRange().RangeAddress; + if (c.FormulaReference.FirstAddress.Equals(c.Address)) { var cc = new CalculationCell @@ -1077,9 +1080,6 @@ SheetId = worksheet.SheetId }; - if (c.FormulaReference == null) - c.FormulaReference = c.AsRange().RangeAddress; - cc.Array = true; calculationChain.AppendChild(cc); @@ -2498,8 +2498,9 @@ if (labelOrFilterField != null && labelOrFilterField.Collapsed) item.HideDetails = BooleanValue.FromBoolean(false); - if (labelOrFilterField.SelectedValues.Count > 1 - && !labelOrFilterField.SelectedValues.Contains(value)) + if (labelOrFilterField != null && + labelOrFilterField.SelectedValues.Count > 1 && + !labelOrFilterField.SelectedValues.Contains(value)) item.Hidden = BooleanValue.FromBoolean(true); fieldItems.AppendChild(item); diff --git a/ClosedXML/Excel/XLWorksheet.cs b/ClosedXML/Excel/XLWorksheet.cs index 839b5d8..cdd2d65 100644 --- a/ClosedXML/Excel/XLWorksheet.cs +++ b/ClosedXML/Excel/XLWorksheet.cs @@ -170,13 +170,13 @@ get { return _name; } set { + if (String.IsNullOrWhiteSpace(value)) + throw new ArgumentException("Worksheet names cannot be empty"); + if (value.IndexOfAny(InvalidNameChars.ToCharArray()) != -1) throw new ArgumentException("Worksheet names cannot contain any of the following characters: " + InvalidNameChars); - if (String.IsNullOrWhiteSpace(value)) - throw new ArgumentException("Worksheet names cannot be empty"); - if (value.Length > 31) throw new ArgumentException("Worksheet names cannot be more than 31 characters"); @@ -484,7 +484,7 @@ public IXLWorksheet ExpandColumns() { - Enumerable.Range(1, 8).ForEach(i => ExpandRows(i)); + Enumerable.Range(1, 8).ForEach(i => ExpandColumns(i)); return this; } @@ -989,6 +989,8 @@ Internals.Dispose(); + SelectedRanges?.Dispose(); + DataValidations?.Dispose(); this.Pictures.ForEach(p => p.Dispose()); base.Dispose(); diff --git a/ClosedXML/XLHelper.cs b/ClosedXML/XLHelper.cs index 0796264..76d2b7b 100644 --- a/ClosedXML/XLHelper.cs +++ b/ClosedXML/XLHelper.cs @@ -116,8 +116,10 @@ public static bool IsValidColumn(string column) { + if (String.IsNullOrWhiteSpace(column)) + return false; var length = column.Length; - if (String.IsNullOrWhiteSpace(column) || length > 3) + if (length > 3) return false; var theColumn = column.ToUpper();