[NWD] Format EPPlus with CSharpier. Also: - Add dotnet-csharpier and .editorconfig files - Clean up identifier naming - Misc cleanup Change-Id: I73e05e4ff47dd857323ec5da8aec4b3bf021f496 Reviewed-on: https://gnocchi-internal-review.git.corp.google.com/c/third_party/epplus/+/207429 Reviewed-by: Hughes Hilton <hugheshilton@google.com>
diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a054d7d --- /dev/null +++ b/.editorconfig
@@ -0,0 +1,257 @@ +root = true + +[*] + +indent_style = space +indent_size = 2 +tab_width = 2 +insert_final_newline = true +end_of_line = lf +trim_trailing_whitespace = true +charset = utf-8 +resharper_enforce_line_ending_style = true +resharper_apply_auto_detected_rules = false +resharper_use_indent_from_vs = false + + +[*.{cs, csx, cake, vb, vbx}] + +# Enforce go/csstyle +# Naming rules +# IDE1006 must be treated as an error for any of the following naming rules to affect builds +dotnet_diagnostic.IDE1006.severity = error + +# this. preferences +dotnet_style_qualification_for_field = false:error +dotnet_style_qualification_for_property = false:error +dotnet_style_qualification_for_method = false:error +dotnet_style_qualification_for_event = false:error + +# Pascal case style +dotnet_naming_style.pascal.capitalization = pascal_case +# Interface style +dotnet_naming_style.interface.capitalization = pascal_case +dotnet_naming_style.interface.required_prefix = I +# Camel-case style +dotnet_naming_style.camel.capitalization = camel_case +# Camel-case beginning with underscore style +dotnet_naming_style.underscore_camel.capitalization = camel_case +dotnet_naming_style.underscore_camel.required_prefix = _ + +# Symbols for namespaces +dotnet_naming_symbols.namespaces.applicable_kinds = namespace +dotnet_naming_symbols.namespaces.applicable_accessibilities = * +# Symbols for types +dotnet_naming_symbols.types.applicable_kinds = class, struct, delegate, type_parameter +dotnet_naming_symbols.types.applicable_accessibilities = * +# Symbols for interfaces +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_symbols.interfaces.applicable_accessibilities = * +# Symbols for enums +dotnet_naming_symbols.enums.applicable_kinds = enum +dotnet_naming_symbols.enums.applicable_accessibilities = * +# Symbols for public fields and properties +dotnet_naming_symbols.public_fields_properties.applicable_kinds = field, property +dotnet_naming_symbols.public_fields_properties.applicable_accessibilities = public +# Symbols for non-public fields and properties - Unenforced +dotnet_naming_symbols.non_public_fields_properties.applicable_kinds = field, property +dotnet_naming_symbols.non_public_fields_properties.applicable_accessibilities = internal, private, protected, protected_internal +# Symbols for non-public constants +dotnet_naming_symbols.private_constants.applicable_kinds = field +dotnet_naming_symbols.private_constants.applicable_accessibilities = private, protected, internal, protected_internal +dotnet_naming_symbols.private_constants.required_modifiers = const +# Symbols for public constants +dotnet_naming_symbols.public_constants.applicable_kinds = field +dotnet_naming_symbols.public_constants.applicable_accessibilities = public +dotnet_naming_symbols.public_constants.required_modifiers = const +# Symbols for non-public static readonly fields and properties +dotnet_naming_symbols.private_static_readonly.applicable_kinds = field, property +dotnet_naming_symbols.private_static_readonly.applicable_accessibilities = private, protected, internal, protected_internal +dotnet_naming_symbols.private_static_readonly.required_modifiers = static, readonly +# Symbols for public static readonly fields and properties +dotnet_naming_symbols.public_static_readonly.applicable_kinds = field, property +dotnet_naming_symbols.public_static_readonly.applicable_accessibilities = public +dotnet_naming_symbols.public_static_readonly.required_modifiers = static, readonly +# Symbols for methods and events +dotnet_naming_symbols.methods.applicable_kinds = method, event, local_function +dotnet_naming_symbols.methods.applicable_accessibilities = * +# Symbols for local variables and parameters +dotnet_naming_symbols.local_variables.applicable_kinds = local, parameter +dotnet_naming_symbols.local_variables.applicable_accessibilities = * + +# Rule for namespaces +dotnet_naming_rule.namespace_rule.symbols = namespaces +dotnet_naming_rule.namespace_rule.style = pascal +dotnet_naming_rule.namespace_rule.severity = error +# Rule for types +dotnet_naming_rule.type_rule.symbols = types +dotnet_naming_rule.type_rule.style = pascal +dotnet_naming_rule.type_rule.severity = error +# Rule for interfaces +dotnet_naming_rule.interface_rule.symbols = interfaces +dotnet_naming_rule.interface_rule.style = interface +dotnet_naming_rule.interface_rule.severity = error +# Rule for enums - For now, do not enforce due to serialization +dotnet_naming_rule.enum_rule.symbols = enums +dotnet_naming_rule.enum_rule.style = pascal +dotnet_naming_rule.enum_rule.severity = none +# Rule for public fields and properties - For now, do not enforce due to serialization +dotnet_naming_rule.public_field_property_rule.symbols = public_fields_properties +dotnet_naming_rule.public_field_property_rule.style = pascal +dotnet_naming_rule.public_field_property_rule.severity = none +# Rule for non-public fields and properties - Not enforced +dotnet_naming_rule.non_public_field_property_rule.symbols = non_public_fields_properties +dotnet_naming_rule.non_public_field_property_rule.style = underscore_camel +dotnet_naming_rule.non_public_field_property_rule.severity = none +# Rule for non-public constants +dotnet_naming_rule.private_constant_rule.symbols = private_constants +dotnet_naming_rule.private_constant_rule.style = underscore_camel +dotnet_naming_rule.private_constant_rule.severity = error +# Rule for public constants +dotnet_naming_rule.public_constant_rule.symbols = public_constants +dotnet_naming_rule.public_constant_rule.style = pascal +dotnet_naming_rule.public_constant_rule.severity = error +# Rule for non-public static readonly fields and properties +dotnet_naming_rule.private_static_readonly_rule.symbols = private_static_readonly +dotnet_naming_rule.private_static_readonly_rule.style = underscore_camel +dotnet_naming_rule.private_static_readonly_rule.severity = error +# Rule for public static readonly fields and properties +dotnet_naming_rule.private_static_readonly_rule.symbols = public_static_readonly +dotnet_naming_rule.private_static_readonly_rule.style = pascal +dotnet_naming_rule.private_static_readonly_rule.severity = error +# Rule for methods and events +dotnet_naming_rule.method_rule.symbols = methods +dotnet_naming_rule.method_rule.style = pascal +dotnet_naming_rule.method_rule.severity = error +# Rule for local variables and parameters +dotnet_naming_rule.variable_rule.symbols = local_variables +dotnet_naming_rule.variable_rule.style = camel +dotnet_naming_rule.variable_rule.severity = error + +# Organization + +dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion +dotnet_sort_system_directives_first = true +resharper_sort_usings_with_system_first = true +csharp_preserve_single_line_statements = false +# Single-line blocks can be things like auto properties +csharp_preserve_single_line_blocks = true +csharp_using_directive_placement = outside_namespace +csharp_trailing_comma_in_multiline_lists = true +csharp_trailing_comma_in_singleline_lists = false +resharper_arrange_trailing_comma_in_multiline_lists_highlighting = warning +resharper_arrange_trailing_comma_in_singleline_lists_highlighting = warning +dotnet_style_predefined_type_for_member_access = true:warning +dotnet_style_predefined_type_for_locals_parameters_members = true:warning +resharper_arrange_static_member_qualifier_highlighting = warning + +# Whitespace + +max_line_length = 100 +csharp_max_line_length = 100 +resharper_csharp_max_line_length = 100 +resharper_wrap_lines = true +resharper_continuous_indent_multiplier = 2 +resharper_align_multiline_binary_expressions_chain = false +resharper_align_multiline_statement_conditions = false +csharp_new_line_before_open_brace = none +csharp_new_line_before_else = false +csharp_new_line_before_catch = false +csharp_new_line_before_finally = false +csharp_new_line_before_members_in_object_initializers = false +csharp_new_line_before_members_in_anonymous_types = false +csharp_new_line_between_query_expression_clauses = true +resharper_blank_lines_after_block_statements = 0 +resharper_blank_lines_around_single_line_auto_property = 1 +resharper_blank_lines_around_single_line_property = 1 +resharper_csharp_blank_lines_around_field = 0 +resharper_csharp_blank_lines_around_single_line_invocable = 1 +resharper_csharp_blank_lines_inside_region = 0 +resharper_csharp_keep_blank_lines_in_code = 1 +resharper_csharp_keep_blank_lines_in_declarations = 1 +resharper_csharp_wrap_after_declaration_lpar = true +resharper_csharp_wrap_after_invocation_lpar = true +resharper_csharp_wrap_arguments_style = chop_if_long +resharper_csharp_wrap_extends_list_style = chop_if_long +resharper_csharp_wrap_parameters_style = chop_if_long +resharper_keep_existing_declaration_parens_arrangement = false +resharper_keep_existing_embedded_arrangement = false +resharper_keep_existing_invocation_parens_arrangement = false +resharper_keep_existing_property_patterns_arrangement = false +resharper_keep_existing_switch_expression_arrangement = false +resharper_max_array_initializer_elements_on_line = 3 +resharper_max_initializer_elements_on_line = 3 +resharper_place_accessorholder_attribute_on_same_line = false +resharper_place_field_attribute_on_same_line = false +resharper_place_simple_embedded_statement_on_same_line = false +resharper_wrap_array_initializer_style = chop_if_long +resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_verbatim_interpolated_strings = wrap_if_long +# Braces +csharp_prefer_braces = true:silent +resharper_braces_redundant = true +resharper_csharp_empty_block_style = together_same_line +resharper_enforce_do_while_statement_braces_highlighting = warning +resharper_enforce_fixed_statement_braces_highlighting = warning +resharper_enforce_foreach_statement_braces_highlighting = warning +resharper_enforce_for_statement_braces_highlighting = warning +resharper_enforce_if_statement_braces_highlighting = warning +resharper_enforce_lock_statement_braces_highlighting = warning +resharper_enforce_using_statement_braces_highlighting = warning +resharper_enforce_while_statement_braces_highlighting = warning +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents_when_block = false +csharp_space_after_cast = false +resharper_space_after_cast = false +resharper_space_within_single_line_array_initializer_braces = true +resharper_space_within_empty_braces = false +csharp_space_before_comma = false +csharp_space_after_comma = true +csharp_space_after_dot = false +csharp_space_after_keywords_in_control_flow_statements = true +csharp_space_between_method_call_parameter_list_parentheses = false +csharp_space_between_method_declaration_parameter_list_parentheses = false +csharp_space_between_method_declaration_empty_parameter_list_parentheses = false +csharp_space_before_colon_in_inheritance_clause = true +csharp_space_after_colon_in_inheritance_clause = true +csharp_space_around_binary_operators = before_and_after +csharp_space_between_method_call_name_and_opening_parenthesis = false +csharp_space_between_method_call_empty_parameter_list_parentheses = false +csharp_space_after_semicolon_in_for_statement = true +csharp_space_before_semicolon_in_for_statement = false +csharp_space_around_declaration_statements = false +csharp_space_before_open_square_brackets = false +csharp_space_between_empty_square_brackets = false +csharp_space_between_square_brackets = false +csharp_place_attribute_on_same_line = false +resharper_place_attribute_on_same_line = false +resharper_arrange_attributes_highlighting = warning +csharp_force_attribute_style = Separate +# Braces required even when optional +csharp_braces_for_ifelse = required +csharp_braces_for_for = required +csharp_braces_for_foreach = required +csharp_braces_for_while = required +csharp_braces_for_dowhile = required +csharp_braces_for_lock = required +csharp_braces_for_fixed = required +resharper_braces_for_for = required +resharper_braces_for_foreach = required +resharper_braces_for_ifelse = required +resharper_braces_for_while = required +resharper_braces_redundant = false +resharper_keep_existing_declaration_block_arrangement = true +resharper_keep_existing_embedded_block_arrangement = true +# Async/await rules. These don't seem to fail the build in Rider even though they show up as errors +# in the "Problems" box and in the code, but at least they are visually marked as errors. +resharper_async_void_lambda_highlighting = error +resharper_async_void_method_highlighting = error +dotnet_diagnostic.AsyncFixer01.severity = none +dotnet_diagnostic.AsyncFixer02.severity = error +dotnet_diagnostic.AsyncFixer03.severity = error +dotnet_diagnostic.AsyncFixer04.severity = error +dotnet_diagnostic.AsyncFixer05.severity = error +resharper_keep_existing_enum_arrangement = true
diff --git a/EPPlus/CellStore.cs b/EPPlus/CellStore.cs index 9e05a06..c767a82 100644 --- a/EPPlus/CellStore.cs +++ b/EPPlus/CellStore.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,1939 +13,1714 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 2012-11-25 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Collections; +using System.Collections.Generic; using OfficeOpenXml; -using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; -internal class IndexBase : IComparable<IndexBase> - { - internal short Index; - public int CompareTo(IndexBase other) - { - return Index < other.Index ? -1 : Index > other.Index ? 1 : 0; - } +internal class IndexBase : IComparable<IndexBase> { + internal short Index; + + public int CompareTo(IndexBase other) { + return Index < other.Index + ? -1 + : Index > other.Index + ? 1 + : 0; + } +} + +internal class IndexItem : IndexBase { + internal int IndexPointer { get; set; } +} + +internal class ColumnIndex : IndexBase { + internal IndexBase _searchIx = new(); + + public ColumnIndex() { + _pages = new PageIndex[CellStore<int>._pagesPerColumnMin]; + PageCount = 0; + } + + ~ColumnIndex() { + _pages = null; + } + + internal int GetPosition(int row) { + var page = (short)(row >> CellStore<int>._pageBits); + _searchIx.Index = page; + var res = + (_pages != null + && page >= 0 + && page < PageCount + && page < _pages.Length + && _pages[page] != null + && _pages[page].Index == page) + ? page + : Array.BinarySearch(_pages, 0, PageCount, _searchIx); + if (res >= 0) { + GetPage(row, ref res); + return res; } - internal class IndexItem : IndexBase - { - internal int IndexPointer - { - get; - set; - } - } - internal class ColumnIndex : IndexBase - { - internal IndexBase _searchIx=new IndexBase(); - public ColumnIndex () - { - _pages=new PageIndex[CellStore<int>.PagesPerColumnMin]; - PageCount=0; - } - ~ColumnIndex() - { - _pages=null; - } - internal int GetPosition(int Row) - { - var page = (short)(Row >> CellStore<int>.pageBits); - _searchIx.Index = page; - var res = (_pages != null && page >= 0 && page < PageCount && page < _pages.Length && _pages[page] != null && _pages[page].Index == page) ? page : Array.BinarySearch(_pages, 0, PageCount, _searchIx); - if (res >= 0) - { - GetPage(Row, ref res); - return res; - } - else - { - var p = ~res; - - if (GetPage(Row, ref p)) - { - return p; - } - else - { - return res; - } - } - } + var p = ~res; - private bool GetPage(int Row, ref int res) - { - if (res < PageCount && _pages[res].MinIndex <= Row && _pages[res].MaxIndex >= Row) - { - return true; - } - else - { - if (res + 1 < PageCount && (_pages[res + 1].MinIndex <= Row)) - { - do - { - res++; - } - while (res + 1 < PageCount && _pages[res + 1].MinIndex <= Row); - //if (res + 1 < PageCount && _pages[res + 1].MaxIndex >= Row) - //{ - return true; - //} - //else - //{ - // return false; - //} - } - else if (res - 1 >= 0 && _pages[res - 1].MaxIndex >= Row) - { - do - { - res--; - } - while (res-1 > 0 && _pages[res-1].MaxIndex >= Row); - //if (res > 0) - //{ - return true; - //} - //else - //{ - // return false; - //} - } - return false; - } - } - internal int GetNextRow(int row) - { - //var page = (int)((ulong)row >> CellStore<int>.pageBits); - var p = GetPosition(row); - if (p < 0) - { - p = ~p; - if (p >= PageCount) - { - return -1; - } - else - { - - if (_pages[p].IndexOffset + _pages[p].Rows[0].Index < row) - { - if (p + 1 >= PageCount) - { - return -1; - } - else - { - return _pages[p + 1].IndexOffset + _pages[p].Rows[0].Index; - } - } - else - { - return _pages[p].IndexOffset + _pages[p].Rows[0].Index; - } - } - } - else - { - if (p < PageCount) - { - var r = _pages[p].GetNextRow(row); - if (r >= 0) - { - return _pages[p].IndexOffset + _pages[p].Rows[r].Index; - } - else - { - if (++p < PageCount) - { - return _pages[p].IndexOffset + _pages[p].Rows[0].Index; - } - else - { - return -1; - } - } - } - else - { - return -1; - } - } - } - internal int FindNext(int Page) - { - var p = GetPosition(Page); - if (p < 0) - { - return ~p; - } - return p; - } - internal PageIndex[] _pages; - internal int PageCount; + if (GetPage(row, ref p)) { + return p; } + return res; + } - internal class PageIndex : IndexBase - { - internal IndexBase _searchIx = new IndexBase(); - public PageIndex() - { - Rows = new IndexItem[CellStore<int>.PageSizeMin]; - RowCount = 0; - } - public PageIndex(IndexItem[] rows, int count) - { - Rows = rows; - RowCount = count; - } - public PageIndex(PageIndex pageItem, int start, int size) - :this(pageItem, start, size, pageItem.Index, pageItem.Offset) - { - - } - public PageIndex(PageIndex pageItem, int start, int size, short index, int offset) - { - Rows = new IndexItem[CellStore<int>.GetSize(size)]; - Array.Copy(pageItem.Rows, start, Rows,0,size); - RowCount = size; - Index = index; - Offset = offset; - } - ~PageIndex() - { - Rows=null; - } - internal int Offset = 0; - internal int IndexOffset - { - get - { - return IndexExpanded + (int)Offset; - } - } - internal int IndexExpanded - { - get - { - return (Index << CellStore<int>.pageBits); - } - } - internal IndexItem[] Rows { get; set; } - internal int RowCount; - - internal int GetPosition(int offset) - { - _searchIx.Index = (short)offset; - return (Rows != null && offset > 0 && offset - 1 < RowCount && offset - 1 < Rows.Length && Rows[offset - 1] != null && Rows[offset - 1].Index == offset) ? offset - 1 : Array.BinarySearch(Rows, 0, RowCount, _searchIx); - } - internal int GetNextRow(int row) - { - int offset = row - IndexOffset; - var o= GetPosition(offset); - if (o < 0) - { - o = ~o; - if (o < RowCount) - { - return o; - } - else - { - return -1; - } - } - return o; - } - - public int MinIndex - { - get - { - if (Rows.Length > 0) - { - return IndexOffset + Rows[0].Index; - } - else - { - return -1; - } - } - } - public int MaxIndex - { - get - { - if (RowCount > 0) - { - return IndexOffset + Rows[RowCount-1].Index; - } - else - { - return -1; - } - } - } - public int GetIndex(int pos) - { - return IndexOffset + Rows[pos].Index; - } + private bool GetPage(int row, ref int res) { + if (res < PageCount && _pages[res].MinIndex <= row && _pages[res].MaxIndex >= row) { + return true; } - /// <summary> - /// This is the store for all Rows, Columns and Cells. - /// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID ) - /// </summary> - internal class CellStore<T> - { - /**** Size constants ****/ - internal const int pageBits = 10; //13bits=8192 Note: Maximum is 13 bits since short is used (PageMax=16K) - internal const int PageSize = 1 << pageBits; - internal const int PageSizeMin = 1<<10; - internal const int PageSizeMax = PageSize << 1; //Double page size - internal const int ColSizeMin = 32; - internal const int PagesPerColumnMin = 32; + if (res + 1 < PageCount && (_pages[res + 1].MinIndex <= row)) { + do { + res++; + } while (res + 1 < PageCount && _pages[res + 1].MinIndex <= row); + //if (res + 1 < PageCount && _pages[res + 1].MaxIndex >= Row) + //{ + return true; + //} + //else + //{ + // return false; + //} + } + if (res - 1 >= 0 && _pages[res - 1].MaxIndex >= row) { + do { + res--; + } while (res - 1 > 0 && _pages[res - 1].MaxIndex >= row); + //if (res > 0) + //{ + return true; + //} + //else + //{ + // return false; + //} + } + return false; + } - List<T> _values = new List<T>(); - internal ColumnIndex[] _columnIndex; - internal IndexBase _searchIx = new IndexBase(); - internal int ColumnCount; - public CellStore () - { - _columnIndex = new ColumnIndex[ColSizeMin]; - } - ~CellStore() - { - if (_values != null) - { - _values.Clear(); - _values = null; - } - _columnIndex=null; - } - internal int GetPosition(int Column) - { - _searchIx.Index = (short)Column; - return (_columnIndex != null && Column > 0 && Column - 1 < ColumnCount && Column - 1 < _columnIndex.Length && _columnIndex[Column - 1] != null && _columnIndex[Column - 1].Index == Column) ? Column - 1 : Array.BinarySearch(_columnIndex, 0, ColumnCount, _searchIx); + internal int GetNextRow(int row) { + //var page = (int)((ulong)row >> CellStore<int>.pageBits); + var p = GetPosition(row); + if (p < 0) { + p = ~p; + if (p >= PageCount) { + return -1; + } + if (_pages[p].IndexOffset + _pages[p].Rows[0].Index < row) { + if (p + 1 >= PageCount) { + return -1; } - internal CellStore<T> Clone() - { - int row,col; - var ret=new CellStore<T>(); - for (int c = 0; c < ColumnCount; c++) - { - col = _columnIndex[c].Index; - for (int p = 0;p < _columnIndex[c].PageCount; p++) - { - for (int r = 0; r < _columnIndex[c]._pages[p].RowCount; r++) - { - row = _columnIndex[c]._pages[p].IndexOffset + _columnIndex[c]._pages[p].Rows[r].Index; - ret.SetValue(row, col, _values[_columnIndex[c]._pages[p].Rows[r].IndexPointer]); - } - } - } - return ret; + return _pages[p + 1].IndexOffset + _pages[p].Rows[0].Index; + } + return _pages[p].IndexOffset + _pages[p].Rows[0].Index; + } + if (p < PageCount) { + var r = _pages[p].GetNextRow(row); + if (r >= 0) { + return _pages[p].IndexOffset + _pages[p].Rows[r].Index; + } else { + if (++p < PageCount) { + return _pages[p].IndexOffset + _pages[p].Rows[0].Index; + } else { + return -1; } - internal int Count - { - get - { - int count=0; - for (int c = 0; c < ColumnCount; c++) - { - for (int p = 0; p < _columnIndex[c].PageCount; p++) - { - count += _columnIndex[c]._pages[p].RowCount; - } - } - return count; - } - } - internal bool GetDimension(out int fromRow, out int fromCol, out int toRow, out int toCol) - { - if (ColumnCount == 0) - { - fromRow = fromCol = toRow = toCol = 0; - return false; - } - else - { - fromCol=_columnIndex[0].Index; - var fromIndex = 0; - if (fromCol <= 0 && ColumnCount > 1) - { - fromCol = _columnIndex[1].Index; - fromIndex = 1; - } - else if(ColumnCount == 1 && fromCol <= 0) - { - fromRow = fromCol = toRow = toCol = 0; - return false; - } - var col = ColumnCount - 1; - while (col > 0) - { - if (_columnIndex[col].PageCount == 0 || _columnIndex[col]._pages[0].RowCount > 1 || _columnIndex[col]._pages[0].Rows[0].Index > 0) - { - break; - } - col--; - } - toCol=_columnIndex[col].Index; - if (toCol == 0) - { - fromRow = fromCol = toRow = toCol = 0; - return false; - } - fromRow = toRow= 0; + } + } + return -1; + } - for (int c = fromIndex; c < ColumnCount; c++) - { - int first, last; - if (_columnIndex[c].PageCount == 0) continue; - if (_columnIndex[c]._pages[0].RowCount > 0 && _columnIndex[c]._pages[0].Rows[0].Index > 0) - { - first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[0].Index; - } - else - { - if(_columnIndex[c]._pages[0].RowCount>1) - { - first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[1].Index; - } - else if (_columnIndex[c].PageCount > 1) - { - first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[1].Rows[0].Index; - } - else - { - first = 0; - } - } - var lp = _columnIndex[c].PageCount - 1; - while(_columnIndex[c]._pages[lp].RowCount==0 && lp!=0) - { - lp--; - } - var p = _columnIndex[c]._pages[lp]; - if (p.RowCount > 0) - { - last = p.IndexOffset + p.Rows[p.RowCount - 1].Index; - } - else - { - last = first; - } - if (first > 0 && (first < fromRow || fromRow == 0)) - { - fromRow=first; - } - if (first>0 && (last > toRow || toRow == 0)) - { - toRow=last; - } - } - if (fromRow <= 0 || toRow <= 0) - { - fromRow = fromCol = toRow = toCol = 0; - return false; - } - else - { - return true; - } - } - } - internal int FindNext(int Column) - { - var c = GetPosition(Column); - if (c < 0) - { - return ~c; - } - return c; - } - internal T GetValue(int Row, int Column) - { - int i = GetPointer(Row, Column); - if (i >= 0) - { - return _values[i]; - } - else - { - return default(T); - } - //var col = GetPosition(Column); - //if (col >= 0) - //{ - // var pos = _columnIndex[col].GetPosition(Row); - // if (pos >= 0) - // { - // var pageItem = _columnIndex[col].Pages[pos]; - // if (pageItem.MinIndex > Row) - // { - // pos--; - // if (pos < 0) - // { - // return default(T); - // } - // else - // { - // pageItem = _columnIndex[col].Pages[pos]; - // } - // } - // short ix = (short)(Row - pageItem.IndexOffset); - // var cellPos = Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, new IndexBase() { Index = ix }); - // if (cellPos >= 0) - // { - // return _values[pageItem.Rows[cellPos].IndexPointer]; - // } - // else //Cell does not exist - // { - // return default(T); - // } - // } - // else //Page does not exist - // { - // return default(T); - // } - //} - //else //Column does not exist - //{ - // return default(T); - //} - } - int GetPointer(int Row, int Column) - { - var col = GetPosition(Column); - if (col >= 0) - { - var pos = _columnIndex[col].GetPosition(Row); - if (pos >= 0 && pos < _columnIndex[col].PageCount) - { - var pageItem = _columnIndex[col]._pages[pos]; - if (pageItem.MinIndex > Row) - { - pos--; - if (pos < 0) - { - return -1; - } - else - { - pageItem = _columnIndex[col]._pages[pos]; - } - } - short ix = (short)(Row - pageItem.IndexOffset); - _searchIx.Index = ix; - var cellPos = (pageItem.Rows != null && ix > 0 && ix - 1 < pageItem.RowCount && ix - 1 < pageItem.Rows.Length && pageItem.Rows[ix - 1] != null && pageItem.Rows[ix - 1].Index == ix) ? ix - 1 : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx); - if (cellPos >= 0) - { - return pageItem.Rows[cellPos].IndexPointer; - } - else //Cell does not exist - { - return -1; - } - } - else //Page does not exist - { - return -1; - } - } - else //Column does not exist - { - return -1; - } - } - internal bool Exists(int Row,int Column) - { - return GetPointer(Row, Column)>=0; - } - internal bool Exists(int Row, int Column, ref T value) - { - var p=GetPointer(Row, Column); - if (p >= 0) - { - value = _values[p]; - return true; - } - else - { - return false; - } - } - internal void SetValue(int Row, int Column, T Value) - { - lock (_columnIndex) - { - var col = (_columnIndex != null && Column > 0 && Column - 1 < ColumnCount && Column - 1 < _columnIndex.Length && _columnIndex[Column - 1] != null && _columnIndex[Column - 1].Index == Column) ? Column - 1 : Array.BinarySearch(_columnIndex, 0, ColumnCount, new IndexBase() { Index = (short)(Column) }); - var page = (short)(Row >> pageBits); - if (col >= 0) - { - //var pos = Array.BinarySearch(_columnIndex[col].Pages, 0, _columnIndex[col].Count, new IndexBase() { Index = page }); - var pos = _columnIndex[col].GetPosition(Row); - if (pos < 0) - { - pos = ~pos; - if (pos - 1 < 0 || _columnIndex[col]._pages[pos - 1].IndexOffset + PageSize - 1 < Row) - { - AddPage(_columnIndex[col], pos, page); - } - else - { - pos--; - } - } - if (pos >= _columnIndex[col].PageCount) - { - AddPage(_columnIndex[col], pos, page); - } - var pageItem = _columnIndex[col]._pages[pos]; - if (pageItem.IndexOffset > Row) - { - pos--; - page--; - if (pos < 0) - { - throw (new Exception("Unexpected error when setting value")); - } - pageItem = _columnIndex[col]._pages[pos]; - } + internal int FindNext(int page) { + var p = GetPosition(page); + if (p < 0) { + return ~p; + } + return p; + } - short ix = (short)(Row - ((pageItem.Index << pageBits) + pageItem.Offset)); - _searchIx.Index = ix; - var cellPos = (pageItem.Rows != null && ix >= 0 && ix < pageItem.RowCount && ix < pageItem.Rows.Length && pageItem.Rows[ix] != null && pageItem.Rows[ix].Index == ix) ? ix : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx); - if (cellPos < 0) - { - cellPos = ~cellPos; - AddCell(_columnIndex[col], pos, cellPos, ix, Value); - } - else - { - _values[pageItem.Rows[cellPos].IndexPointer] = Value; - } - } - else //Column does not exist - { - col = ~col; - AddColumn(col, Column); - AddPage(_columnIndex[col], 0, page); - short ix = (short)(Row - (page << pageBits)); - AddCell(_columnIndex[col], 0, 0, ix, Value); - } - } + internal PageIndex[] _pages; + internal int PageCount; +} + +internal class PageIndex : IndexBase { + internal IndexBase _searchIx = new(); + + public PageIndex() { + Rows = new IndexItem[CellStore<int>._pageSizeMin]; + RowCount = 0; + } + + public PageIndex(IndexItem[] rows, int count) { + Rows = rows; + RowCount = count; + } + + public PageIndex(PageIndex pageItem, int start, int size) + : this(pageItem, start, size, pageItem.Index, pageItem.Offset) {} + + public PageIndex(PageIndex pageItem, int start, int size, short index, int offset) { + Rows = new IndexItem[CellStore<int>.GetSize(size)]; + Array.Copy(pageItem.Rows, start, Rows, 0, size); + RowCount = size; + Index = index; + Offset = offset; + } + + ~PageIndex() { + Rows = null; + } + + internal int Offset; + + internal int IndexOffset => IndexExpanded + Offset; + + internal int IndexExpanded => (Index << CellStore<int>._pageBits); + + internal IndexItem[] Rows { get; set; } + + internal int RowCount; + + internal int GetPosition(int offset) { + _searchIx.Index = (short)offset; + return (Rows != null + && offset > 0 + && offset - 1 < RowCount + && offset - 1 < Rows.Length + && Rows[offset - 1] != null + && Rows[offset - 1].Index == offset) + ? offset - 1 + : Array.BinarySearch(Rows, 0, RowCount, _searchIx); + } + + internal int GetNextRow(int row) { + int offset = row - IndexOffset; + var o = GetPosition(offset); + if (o < 0) { + o = ~o; + if (o < RowCount) { + return o; + } + return -1; + } + return o; + } + + public int MinIndex { + get { + if (Rows.Length > 0) { + return IndexOffset + Rows[0].Index; + } + return -1; + } + } + + public int MaxIndex { + get { + if (RowCount > 0) { + return IndexOffset + Rows[RowCount - 1].Index; + } + return -1; + } + } + + public int GetIndex(int pos) { + return IndexOffset + Rows[pos].Index; + } +} + +/// <summary> +/// This is the store for all Rows, Columns and Cells. +/// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID ) +/// </summary> +internal class CellStore<T> { + /**** Size constants ****/ + internal const int _pageBits = 10; //13bits=8192 Note: Maximum is 13 bits since short is used (PageMax=16K) + internal const int _pageSize = 1 << _pageBits; + internal const int _pageSizeMin = 1 << 10; + internal const int _pageSizeMax = _pageSize << 1; //Double page size + internal const int _colSizeMin = 32; + internal const int _pagesPerColumnMin = 32; + + private List<T> _values = new(); + internal ColumnIndex[] _columnIndex; + internal IndexBase _searchIx = new(); + internal int ColumnCount; + + public CellStore() { + _columnIndex = new ColumnIndex[_colSizeMin]; + } + + ~CellStore() { + if (_values != null) { + _values.Clear(); + _values = null; + } + _columnIndex = null; + } + + internal int GetPosition(int column) { + _searchIx.Index = (short)column; + return (_columnIndex != null + && column > 0 + && column - 1 < ColumnCount + && column - 1 < _columnIndex.Length + && _columnIndex[column - 1] != null + && _columnIndex[column - 1].Index == column) + ? column - 1 + : Array.BinarySearch(_columnIndex, 0, ColumnCount, _searchIx); + } + + internal CellStore<T> Clone() { + int row, + col; + var ret = new CellStore<T>(); + for (int c = 0; c < ColumnCount; c++) { + col = _columnIndex[c].Index; + for (int p = 0; p < _columnIndex[c].PageCount; p++) { + for (int r = 0; r < _columnIndex[c]._pages[p].RowCount; r++) { + row = _columnIndex[c]._pages[p].IndexOffset + _columnIndex[c]._pages[p].Rows[r].Index; + ret.SetValue(row, col, _values[_columnIndex[c]._pages[p].Rows[r].IndexPointer]); + } + } + } + return ret; + } + + internal int Count { + get { + int count = 0; + for (int c = 0; c < ColumnCount; c++) { + for (int p = 0; p < _columnIndex[c].PageCount; p++) { + count += _columnIndex[c]._pages[p].RowCount; + } + } + return count; + } + } + + internal bool GetDimension(out int fromRow, out int fromCol, out int toRow, out int toCol) { + if (ColumnCount == 0) { + fromRow = fromCol = toRow = toCol = 0; + return false; + } + fromCol = _columnIndex[0].Index; + var fromIndex = 0; + if (fromCol <= 0 && ColumnCount > 1) { + fromCol = _columnIndex[1].Index; + fromIndex = 1; + } else if (ColumnCount == 1 && fromCol <= 0) { + fromRow = fromCol = toRow = toCol = 0; + return false; + } + var col = ColumnCount - 1; + while (col > 0) { + if (_columnIndex[col].PageCount == 0 + || _columnIndex[col]._pages[0].RowCount > 1 + || _columnIndex[col]._pages[0].Rows[0].Index > 0) { + break; + } + col--; + } + toCol = _columnIndex[col].Index; + if (toCol == 0) { + fromRow = fromCol = toRow = toCol = 0; + return false; + } + fromRow = toRow = 0; + + for (int c = fromIndex; c < ColumnCount; c++) { + int first, + last; + if (_columnIndex[c].PageCount == 0) { + continue; + } + if (_columnIndex[c]._pages[0].RowCount > 0 && _columnIndex[c]._pages[0].Rows[0].Index > 0) { + first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[0].Index; + } else { + if (_columnIndex[c]._pages[0].RowCount > 1) { + first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[0].Rows[1].Index; + } else if (_columnIndex[c].PageCount > 1) { + first = _columnIndex[c]._pages[0].IndexOffset + _columnIndex[c]._pages[1].Rows[0].Index; + } else { + first = 0; + } + } + var lp = _columnIndex[c].PageCount - 1; + while (_columnIndex[c]._pages[lp].RowCount == 0 && lp != 0) { + lp--; + } + var p = _columnIndex[c]._pages[lp]; + if (p.RowCount > 0) { + last = p.IndexOffset + p.Rows[p.RowCount - 1].Index; + } else { + last = first; + } + if (first > 0 && (first < fromRow || fromRow == 0)) { + fromRow = first; + } + if (first > 0 && (last > toRow || toRow == 0)) { + toRow = last; + } + } + if (fromRow <= 0 || toRow <= 0) { + fromRow = fromCol = toRow = toCol = 0; + return false; + } + return true; + } + + internal int FindNext(int column) { + var c = GetPosition(column); + if (c < 0) { + return ~c; + } + return c; + } + + internal T GetValue(int row, int column) { + int i = GetPointer(row, column); + if (i >= 0) { + return _values[i]; + } + return default(T); + //var col = GetPosition(Column); + //if (col >= 0) + //{ + // var pos = _columnIndex[col].GetPosition(Row); + // if (pos >= 0) + // { + // var pageItem = _columnIndex[col].Pages[pos]; + // if (pageItem.MinIndex > Row) + // { + // pos--; + // if (pos < 0) + // { + // return default(T); + // } + // else + // { + // pageItem = _columnIndex[col].Pages[pos]; + // } + // } + // short ix = (short)(Row - pageItem.IndexOffset); + // var cellPos = Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, new IndexBase() { Index = ix }); + // if (cellPos >= 0) + // { + // return _values[pageItem.Rows[cellPos].IndexPointer]; + // } + // else //Cell does not exist + // { + // return default(T); + // } + // } + // else //Page does not exist + // { + // return default(T); + // } + //} + //else //Column does not exist + //{ + // return default(T); + //} + } + + private int GetPointer(int row, int column) { + var col = GetPosition(column); + if (col >= 0) { + var pos = _columnIndex[col].GetPosition(row); + if (pos >= 0 && pos < _columnIndex[col].PageCount) { + var pageItem = _columnIndex[col]._pages[pos]; + if (pageItem.MinIndex > row) { + pos--; + if (pos < 0) { + return -1; + } + pageItem = _columnIndex[col]._pages[pos]; + } + short ix = (short)(row - pageItem.IndexOffset); + _searchIx.Index = ix; + var cellPos = + (pageItem.Rows != null + && ix > 0 + && ix - 1 < pageItem.RowCount + && ix - 1 < pageItem.Rows.Length + && pageItem.Rows[ix - 1] != null + && pageItem.Rows[ix - 1].Index == ix) + ? ix - 1 + : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx); + if (cellPos >= 0) { + return pageItem.Rows[cellPos].IndexPointer; + } //Cell does not exist + return -1; + } //Page does not exist + return -1; + } //Column does not exist + return -1; + } + + internal bool Exists(int row, int column) { + return GetPointer(row, column) >= 0; + } + + internal bool Exists(int row, int column, ref T value) { + var p = GetPointer(row, column); + if (p >= 0) { + value = _values[p]; + return true; + } + return false; + } + + internal void SetValue(int row, int column, T value) { + lock (_columnIndex) { + var col = + (_columnIndex != null + && column > 0 + && column - 1 < ColumnCount + && column - 1 < _columnIndex.Length + && _columnIndex[column - 1] != null + && _columnIndex[column - 1].Index == column) + ? column - 1 + : Array.BinarySearch( + _columnIndex, + 0, + ColumnCount, + new IndexBase { + Index = (short)(column), + }); + var page = (short)(row >> _pageBits); + if (col >= 0) { + //var pos = Array.BinarySearch(_columnIndex[col].Pages, 0, _columnIndex[col].Count, new IndexBase() { Index = page }); + var pos = _columnIndex[col].GetPosition(row); + if (pos < 0) { + pos = ~pos; + if (pos - 1 < 0 || _columnIndex[col]._pages[pos - 1].IndexOffset + _pageSize - 1 < row) { + AddPage(_columnIndex[col], pos, page); + } else { + pos--; + } + } + if (pos >= _columnIndex[col].PageCount) { + AddPage(_columnIndex[col], pos, page); + } + var pageItem = _columnIndex[col]._pages[pos]; + if (pageItem.IndexOffset > row) { + pos--; + page--; + if (pos < 0) { + throw (new("Unexpected error when setting value")); + } + pageItem = _columnIndex[col]._pages[pos]; } - internal void Insert(int fromRow, int fromCol, int rows, int columns) - { - lock (_columnIndex) - { + short ix = (short)(row - ((pageItem.Index << _pageBits) + pageItem.Offset)); + _searchIx.Index = ix; + var cellPos = + (pageItem.Rows != null + && ix >= 0 + && ix < pageItem.RowCount + && ix < pageItem.Rows.Length + && pageItem.Rows[ix] != null + && pageItem.Rows[ix].Index == ix) + ? ix + : Array.BinarySearch(pageItem.Rows, 0, pageItem.RowCount, _searchIx); + if (cellPos < 0) { + cellPos = ~cellPos; + AddCell(_columnIndex[col], pos, cellPos, ix, value); + } else { + _values[pageItem.Rows[cellPos].IndexPointer] = value; + } + } else //Column does not exist + { + col = ~col; + AddColumn(col, column); + AddPage(_columnIndex[col], 0, page); + short ix = (short)(row - (page << _pageBits)); + AddCell(_columnIndex[col], 0, 0, ix, value); + } + } + } - if (columns > 0) - { - var col = GetPosition(fromCol); - if (col < 0) - { - col = ~col; + internal void Insert(int fromRow, int fromCol, int rows, int columns) { + lock (_columnIndex) { + if (columns > 0) { + var col = GetPosition(fromCol); + if (col < 0) { + col = ~col; + } + for (var c = col; c < ColumnCount; c++) { + _columnIndex[c].Index += (short)columns; + } + } else { + var page = fromRow >> _pageBits; + for (int c = 0; c < ColumnCount; c++) { + var column = _columnIndex[c]; + var pagePos = column.GetPosition(fromRow); + if (pagePos >= 0) { + if (fromRow >= column._pages[pagePos].MinIndex + && fromRow + <= column._pages[pagePos].MaxIndex) //The row is inside the page + { + int offset = fromRow - column._pages[pagePos].IndexOffset; + var rowPos = column._pages[pagePos].GetPosition(offset); + if (rowPos < 0) { + rowPos = ~rowPos; + } + UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows); + } else if (column._pages[pagePos].MinIndex > fromRow - 1 + && pagePos + > 0) //The row is on the page before. + { + int offset = fromRow - ((page - 1) << _pageBits); + var rowPos = column._pages[pagePos - 1].GetPosition(offset); + if (rowPos > 0 && pagePos > 0) { + UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow, rows); + } + } else if (column.PageCount >= pagePos + 1) { + int offset = fromRow - column._pages[pagePos].IndexOffset; + var rowPos = column._pages[pagePos].GetPosition(offset); + if (rowPos < 0) { + rowPos = ~rowPos; + } + if (column._pages[pagePos].RowCount > rowPos) { + UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows); + } else { + UpdateIndexOffset(column, pagePos + 1, 0, fromRow, rows); + } + } + } else { + UpdateIndexOffset(column, ~pagePos, 0, fromRow, rows); + } + } + } + } + } + + internal void Clear(int fromRow, int fromCol, int rows, int columns) { + Delete(fromRow, fromCol, rows, columns, false); + } + + internal void Delete(int fromRow, int fromCol, int rows, int columns) { + Delete(fromRow, fromCol, rows, columns, true); + } + + internal void Delete(int fromRow, int fromCol, int rows, int columns, bool shift) { + lock (_columnIndex) { + if (columns > 0 && fromRow == 1 && rows >= ExcelPackage.MaxRows) { + DeleteColumns(fromCol, columns, shift); + } else { + var toCol = fromCol + columns - 1; + var pageFromRow = fromRow >> _pageBits; + for (int c = 0; c < ColumnCount; c++) { + var column = _columnIndex[c]; + if (column.Index >= fromCol) { + if (column.Index > toCol) { + break; + } + var pagePos = column.GetPosition(fromRow); + if (pagePos < 0) { + pagePos = ~pagePos; + } + if (pagePos < column.PageCount) { + var page = column._pages[pagePos]; + if (shift + && page.RowCount > 0 + && page.MinIndex > fromRow + && page.MaxIndex >= fromRow + rows) { + var o = page.MinIndex - fromRow; + if (o < rows) { + rows -= o; + page.Offset -= o; + UpdatePageOffset(column, pagePos, o); + } else { + page.Offset -= rows; + UpdatePageOffset(column, pagePos, rows); + continue; + } + } + if (page.RowCount > 0 + && page.MinIndex <= fromRow + rows - 1 + && page.MaxIndex + >= fromRow) //The row is inside the page + { + var endRow = fromRow + rows; + var delEndRow = DeleteCells(column._pages[pagePos], fromRow, endRow, shift); + if (shift && delEndRow != fromRow) { + UpdatePageOffset(column, pagePos, delEndRow - fromRow); + } + if (endRow > delEndRow + && pagePos < column.PageCount + && column._pages[pagePos].MinIndex < endRow) { + pagePos = (delEndRow == fromRow ? pagePos : pagePos + 1); + var rowsLeft = DeletePage( + shift ? fromRow : delEndRow, + endRow - delEndRow, + column, + pagePos, + shift); + //if (shift) UpdatePageOffset(column, pagePos, endRow - fromRow - rowsLeft); + if (rowsLeft > 0) { + var fr = shift ? fromRow : endRow - rowsLeft; + pagePos = column.GetPosition(fr); + delEndRow = DeleteCells( + column._pages[pagePos], + fr, + shift ? fr + rowsLeft : endRow, + shift); + if (shift) { + UpdatePageOffset(column, pagePos, rowsLeft); } - for (var c = col; c < ColumnCount; c++) - { - _columnIndex[c].Index += (short)columns; - } + } } - else - { - var page = fromRow >> pageBits; - for (int c = 0; c < ColumnCount; c++) - { - var column = _columnIndex[c]; - var pagePos = column.GetPosition(fromRow); - if (pagePos >= 0) - { - if (fromRow >= column._pages[pagePos].MinIndex && fromRow <= column._pages[pagePos].MaxIndex) //The row is inside the page - { - int offset = fromRow - column._pages[pagePos].IndexOffset; - var rowPos = column._pages[pagePos].GetPosition(offset); - if (rowPos < 0) - { - rowPos = ~rowPos; - } - UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows); - } - else if (column._pages[pagePos].MinIndex > fromRow - 1 && pagePos > 0) //The row is on the page before. - { - int offset = fromRow - ((page - 1) << pageBits); - var rowPos = column._pages[pagePos - 1].GetPosition(offset); - if (rowPos > 0 && pagePos > 0) - { - UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow, rows); - } - } - else if (column.PageCount >= pagePos + 1) - { - int offset = fromRow - column._pages[pagePos].IndexOffset; - var rowPos = column._pages[pagePos].GetPosition(offset); - if (rowPos < 0) - { - rowPos = ~rowPos; - } - if (column._pages[pagePos].RowCount > rowPos) - { - UpdateIndexOffset(column, pagePos, rowPos, fromRow, rows); - } - else - { - UpdateIndexOffset(column, pagePos + 1, 0, fromRow, rows); - } - } - } - else - { - UpdateIndexOffset(column, ~pagePos, 0, fromRow, rows); - } - } + } else if (pagePos > 0 + && column._pages[pagePos].IndexOffset + > fromRow) //The row is on the page before. + { + int offset = fromRow + rows - 1 - ((pageFromRow - 1) << _pageBits); + var rowPos = column._pages[pagePos - 1].GetPosition(offset); + if (rowPos > 0 && pagePos > 0) { + if (shift) { + UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow + rows - 1, -rows); + } } + } else { + if (shift && pagePos + 1 < column.PageCount) { + UpdateIndexOffset( + column, + pagePos + 1, + 0, + column._pages[pagePos + 1].MinIndex, + -rows); + } + } } + } } - internal void Clear(int fromRow, int fromCol, int rows, int columns) - { - Delete(fromRow, fromCol, rows, columns, false); + } + } + } + + private void UpdatePageOffset(ColumnIndex column, int pagePos, int rows) { + //Update Pageoffset + + if (++pagePos < column.PageCount) { + for (int p = pagePos; p < column.PageCount; p++) { + if (column._pages[p].Offset - rows <= -_pageSize) { + column._pages[p].Index--; + column._pages[p].Offset -= rows - _pageSize; + } else { + column._pages[p].Offset -= rows; } - internal void Delete(int fromRow, int fromCol, int rows, int columns) - { - Delete(fromRow, fromCol, rows, columns, true); - } - internal void Delete(int fromRow, int fromCol, int rows, int columns, bool shift) - { - lock (_columnIndex) - { - if (columns > 0 && fromRow == 1 && rows >= ExcelPackage.MaxRows) - { - DeleteColumns(fromCol, columns, shift); - } - else - { - var toCol = fromCol + columns - 1; - var pageFromRow = fromRow >> pageBits; - for (int c = 0; c < ColumnCount; c++) - { - var column = _columnIndex[c]; - if (column.Index >= fromCol) - { - if (column.Index > toCol) break; - var pagePos = column.GetPosition(fromRow); - if (pagePos < 0) pagePos = ~pagePos; - if (pagePos < column.PageCount) - { - var page = column._pages[pagePos]; - if (shift && page.RowCount > 0 && page.MinIndex > fromRow && page.MaxIndex >= fromRow + rows) - { - var o=page.MinIndex - fromRow; - if (o < rows) - { - rows -= o; - page.Offset -= o; - UpdatePageOffset(column, pagePos, o); - } - else - { - page.Offset -= rows; - UpdatePageOffset(column, pagePos, rows); - continue; - } - } - if (page.RowCount > 0 && page.MinIndex <= fromRow+rows-1 && page.MaxIndex >= fromRow) //The row is inside the page - { - var endRow = fromRow + rows; - var delEndRow = DeleteCells(column._pages[pagePos], fromRow, endRow, shift); - if (shift && delEndRow != fromRow) UpdatePageOffset(column, pagePos, delEndRow - fromRow); - if (endRow > delEndRow && pagePos < column.PageCount && column._pages[pagePos].MinIndex < endRow) - { - pagePos = (delEndRow == fromRow ? pagePos : pagePos + 1); - var rowsLeft = DeletePage(shift ? fromRow : delEndRow, endRow - delEndRow, column, pagePos, shift); - //if (shift) UpdatePageOffset(column, pagePos, endRow - fromRow - rowsLeft); - if (rowsLeft > 0) - { - var fr = shift ? fromRow : endRow - rowsLeft; - pagePos = column.GetPosition(fr); - delEndRow = DeleteCells(column._pages[pagePos], fr, shift ? fr + rowsLeft : endRow, shift); - if (shift) UpdatePageOffset(column, pagePos, rowsLeft); - } - } - } - else if (pagePos > 0 && column._pages[pagePos].IndexOffset > fromRow) //The row is on the page before. - { - int offset = fromRow + rows - 1 - ((pageFromRow - 1) << pageBits); - var rowPos = column._pages[pagePos - 1].GetPosition(offset); - if (rowPos > 0 && pagePos > 0) - { - if (shift) UpdateIndexOffset(column, pagePos - 1, rowPos, fromRow + rows - 1, -rows); - } - } - else - { - if (shift && pagePos + 1 < column.PageCount) UpdateIndexOffset(column, pagePos + 1, 0, column._pages[pagePos + 1].MinIndex, -rows); - } - } - } - } - } - } - } - private void UpdatePageOffset(ColumnIndex column, int pagePos, int rows) - { - //Update Pageoffset - - if (++pagePos < column.PageCount) - { - for (int p = pagePos; p < column.PageCount; p++) - { - if (column._pages[p].Offset - rows <= -PageSize) - { - column._pages[p].Index--; - column._pages[p].Offset -= rows-PageSize; - } - else - { - column._pages[p].Offset -= rows; - } - } + } - if (Math.Abs(column._pages[pagePos].Offset) > PageSize || - Math.Abs(column._pages[pagePos].Rows[column._pages[pagePos].RowCount-1].Index) > PageSizeMax) //Split or Merge??? - { - rows=ResetPageOffset(column, pagePos, rows); - ////MergePages - //if (column.Pages[pagePos - 1].Index + 1 == column.Pages[pagePos].Index) - //{ - // if (column.Pages[pagePos].IndexOffset + column.Pages[pagePos].Rows[column.Pages[pagePos].RowCount - 1].Index + rows - - // column.Pages[pagePos - 1].IndexOffset + column.Pages[pagePos - 1].Rows[0].Index <= PageSize) - // { - // //Merge - // MergePage(column, pagePos - 1, -rows); - // } - // else - // { - // //Split - // } - //} - //rows -= PageSize; - //for (int p = pagePos; p < column.PageCount; p++) - //{ - // column.Pages[p].Index -= 1; - //} - return; - } - } - } - - private int ResetPageOffset(ColumnIndex column, int pagePos, int rows) - { - PageIndex fromPage=column._pages[pagePos]; - PageIndex toPage; - short pageAdd = 0; - if (fromPage.Offset < -PageSize) - { - toPage=column._pages[pagePos-1]; - pageAdd = -1; - if (fromPage.Index - 1 == toPage.Index) - { - if (fromPage.IndexOffset + fromPage.Rows[fromPage.RowCount - 1].Index - - toPage.IndexOffset + toPage.Rows[0].Index <= PageSizeMax) - { - MergePage(column, pagePos - 1); - //var newPage = new PageIndex(toPage, 0, GetSize(fromPage.RowCount + toPage.RowCount)); - //newPage.RowCount = fromPage.RowCount + fromPage.RowCount; - //Array.Copy(toPage.Rows, 0, newPage.Rows, 0, toPage.RowCount); - //Array.Copy(fromPage.Rows, 0, newPage.Rows, toPage.RowCount, fromPage.RowCount); - //for (int r = toPage.RowCount; r < newPage.RowCount; r++) - //{ - // newPage.Rows[r].Index += (short)(fromPage.IndexOffset - toPage.IndexOffset); - //} - - } - } - else //No page after - { - fromPage.Index -= pageAdd; - fromPage.Offset += PageSize; - } - } - else if (fromPage.Offset > PageSize) - { - toPage = column._pages[pagePos + 1]; - pageAdd = 1; - if (fromPage.Index + 1 == toPage.Index) - { - - } - else - { - fromPage.Index += pageAdd; - fromPage.Offset += PageSize; - } - } - return rows; - } - - private int DeletePage(int fromRow, int rows, ColumnIndex column, int pagePos, bool shift) - { - PageIndex page = column._pages[pagePos]; - var startRows = rows; - while (page != null && page.MinIndex >= fromRow && ((shift && page.MaxIndex < fromRow + rows) || (!shift && page.MaxIndex < fromRow + startRows))) - { - //Delete entire page. - var delSize=page.MaxIndex - page.MinIndex+1; - rows -= delSize; - var prevOffset = page.Offset; - Array.Copy(column._pages, pagePos + 1, column._pages, pagePos, column.PageCount - pagePos + 1); - column.PageCount--; - if (column.PageCount == 0) - { - return 0; - } - if(shift) - { - for (int i = pagePos; i < column.PageCount; i++) - { - column._pages[i].Offset -= delSize; - if (column._pages[i].Offset <= -PageSize) - { - column._pages[i].Index--; - column._pages[i].Offset += PageSize; - } - } - } - if (column.PageCount > pagePos) - { - page = column._pages[pagePos]; - //page.Offset = pagePos == 0 ? 1 : prevOffset; //First page can only reference to rows starting from Index == 1 - } - else - { - //No more pages, return 0 - return 0; - } - } - return rows; - } - /// - private int DeleteCells(PageIndex page, int fromRow, int toRow, bool shift) - { - var fromPos = page.GetPosition(fromRow - (page.IndexOffset)); - if (fromPos < 0) - { - fromPos = ~fromPos; - } - var maxRow = page.MaxIndex; - var offset = toRow - page.IndexOffset; - if (offset > PageSizeMax) offset = PageSizeMax; - var toPos = page.GetPosition(offset); - if (toPos < 0) - { - toPos = ~toPos; - } - - if (fromPos <= toPos && fromPos < page.RowCount && page.GetIndex(fromPos) < toRow) - { - if (toRow > page.MaxIndex) - { - if (fromRow == page.MinIndex) //Delete entire page, late in the page delete method - { - return fromRow; - } - var r = page.MaxIndex; - var deletedRow = page.RowCount - fromPos; - page.RowCount -= deletedRow; - return r+1; - } - else - { - var rows = toRow - fromRow; - if(shift) UpdateRowIndex(page, toPos, rows); - Array.Copy(page.Rows, toPos, page.Rows, fromPos, page.RowCount - toPos); - page.RowCount -= toPos-fromPos; - - return toRow; - } - } - else if(shift) - { - UpdateRowIndex(page, toPos, toRow - fromRow); - } - return toRow < maxRow ? toRow : maxRow; - } - - private static void UpdateRowIndex(PageIndex page, int toPos, int rows) - { - for (int r = toPos; r < page.RowCount; r++) - { - page.Rows[r].Index -= (short) rows; - } - } - - private void DeleteColumns(int fromCol, int columns, bool shift) - { - var fPos = GetPosition(fromCol); - if (fPos < 0) - { - fPos = ~fPos; - } - int tPos = fPos; - for (var c = fPos; c <= ColumnCount; c++) - { - tPos = c; - if (tPos==ColumnCount || _columnIndex[c].Index >= fromCol + columns) - { - break; - } - } - - if (ColumnCount <= fPos) - { - return; - } - - if (_columnIndex[fPos].Index >= fromCol && _columnIndex[fPos].Index <= fromCol + columns) - { - //if (_columnIndex[fPos].Index < ColumnCount) - //{ - if (tPos < ColumnCount) - { - Array.Copy(_columnIndex, tPos, _columnIndex, fPos, ColumnCount - tPos); - } - ColumnCount -= (tPos - fPos); - //} - } - if (shift) - { - for (var c = fPos; c < ColumnCount; c++) - { - _columnIndex[c].Index -= (short)columns; - } - } - } - - private void UpdateIndexOffset(ColumnIndex column, int pagePos, int rowPos, int row, int rows) - { - if (pagePos >= column.PageCount) return; //A page after last cell. - var page = column._pages[pagePos]; - if (rows > PageSize) - { - short addPages = (short)(rows >> pageBits); - int offset = +(int)(rows - (PageSize*addPages)); - for (int p = pagePos + 1; p < column.PageCount; p++) - { - if (column._pages[p].Offset + offset > PageSize) - { - column._pages[p].Index += (short)(addPages + 1); - column._pages[p].Offset += offset - PageSize; - } - else - { - column._pages[p].Index += addPages; - column._pages[p].Offset += offset; - } - - } - - var size = page.RowCount - rowPos; - if (page.RowCount > rowPos) - { - if (column.PageCount-1 == pagePos) //No page after, create a new one. - { - //Copy rows to next page. - var newPage = CopyNew(page, rowPos, size); - newPage.Index = (short)((row + rows) >> pageBits); - newPage.Offset = row + rows - (newPage.Index * PageSize) - newPage.Rows[0].Index; - if (newPage.Offset > PageSize) - { - newPage.Index++; - newPage.Offset -= PageSize; - } - AddPage(column, pagePos + 1, newPage); - page.RowCount = rowPos; - } - else - { - if (column._pages[pagePos + 1].RowCount + size > PageSizeMax) //Split Page - { - SplitPageInsert(column,pagePos, rowPos, rows, size, addPages); - } - else //Copy Page. - { - CopyMergePage(page, rowPos, rows, size, column._pages[pagePos + 1]); - } - } - } - } - else - { - //Add to Pages. - for (int r = rowPos; r < page.RowCount; r++) - { - page.Rows[r].Index += (short)rows; - } - if (page.Offset + page.Rows[page.RowCount-1].Index >= PageSizeMax) //Can not be larger than the max size of the page. - { - AdjustIndex(column, pagePos); - if (page.Offset + page.Rows[page.RowCount - 1].Index >= PageSizeMax) - { - pagePos=SplitPage(column, pagePos); - } - //IndexItem[] newRows = new IndexItem[GetSize(page.RowCount - page.Rows[r].Index)]; - //var newPage = new PageIndex(newRows, r); - //newPage.Index = (short)(pagePos + 1); - //TODO: MoveRows to next page. - } - - for (int p = pagePos + 1; p < column.PageCount; p++) - { - if (column._pages[p].Offset + rows < PageSize) - { - column._pages[p].Offset += rows; - } - else - { - column._pages[p].Index++; - column._pages[p].Offset = (column._pages[p].Offset+rows) % PageSize; - } - } - } - } - - private void SplitPageInsert(ColumnIndex column,int pagePos, int rowPos, int rows, int size, int addPages) - { - var newRows = new IndexItem[GetSize(size)]; - var page=column._pages[pagePos]; - - var rStart=-1; - for (int r = rowPos; r < page.RowCount; r++) - { - if (page.IndexExpanded - (page.Rows[r].Index + rows) > PageSize) - { - rStart = r; - break; - } - else - { - page.Rows[r].Index += (short)rows; - } - } - var rc = page.RowCount - rStart; - page.RowCount=rStart; - if(rc>0) - { - //Copy to a new page - var row = page.IndexOffset; - var newPage=CopyNew(page,rStart,rc); - var ix = (short)(page.Index + addPages); - var offset = page.IndexOffset + rows - (ix * PageSize); - if (offset > PageSize) - { - ix += (short)(offset / PageSize); - offset %= PageSize; - } - newPage.Index = ix; - newPage.Offset = offset; - AddPage(column, pagePos + 1, newPage); - } - - //Copy from next Row - } - - private void CopyMergePage(PageIndex page, int rowPos, int rows, int size, PageIndex ToPage) - { - var startRow = page.IndexOffset + page.Rows[rowPos].Index + rows; - var newRows = new IndexItem[GetSize(ToPage.RowCount + size)]; - page.RowCount -= size; - Array.Copy(page.Rows, rowPos, newRows, 0, size); - for (int r = 0; r < size; r++) - { - newRows[r].Index += (short)(page.IndexOffset + rows - ToPage.IndexOffset); - } - - Array.Copy(ToPage.Rows, 0, newRows, size, ToPage.RowCount); - ToPage.Rows = newRows; - ToPage.RowCount += size; - } - private void MergePage(ColumnIndex column, int pagePos) - { - PageIndex Page1=column._pages[pagePos]; - PageIndex Page2 = column._pages[pagePos + 1]; - - var newPage = new PageIndex(Page1, 0, Page1.RowCount + Page2.RowCount); - newPage.RowCount = Page1.RowCount + Page2.RowCount; - Array.Copy(Page1.Rows, 0, newPage.Rows, 0, Page1.RowCount); - Array.Copy(Page2.Rows, 0, newPage.Rows, Page1.RowCount, Page2.RowCount); - for (int r = Page1.RowCount; r < newPage.RowCount; r++) - { - newPage.Rows[r].Index += (short)(Page2.IndexOffset - Page1.IndexOffset); - } - - column._pages[pagePos] = newPage; - column.PageCount--; - - if (column.PageCount > (pagePos + 1)) - { - Array.Copy(column._pages, pagePos+2, column._pages,pagePos+1,column.PageCount-(pagePos+1)); - for (int p = pagePos + 1; p < column.PageCount; p++) - { - column._pages[p].Index--; - column._pages[p].Offset += PageSize; - } - } - } - - private PageIndex CopyNew(PageIndex pageFrom, int rowPos, int size) - { - IndexItem[] newRows = new IndexItem[GetSize(size)]; - Array.Copy(pageFrom.Rows, rowPos, newRows, 0, size); - return new PageIndex(newRows, size); - } - - internal static int GetSize(int size) - { - var newSize=256; - while (newSize < size) - { - newSize <<= 1; - } - return newSize; - } - private void AddCell(ColumnIndex columnIndex, int pagePos, int pos, short ix, T value) - { - PageIndex pageItem = columnIndex._pages[pagePos]; - if (pageItem.RowCount == pageItem.Rows.Length) - { - if (pageItem.RowCount == PageSizeMax) //Max size-->Split - { - pagePos=SplitPage(columnIndex, pagePos); - if (columnIndex._pages[pagePos - 1].RowCount > pos) - { - pagePos--; - } - else - { - pos -= columnIndex._pages[pagePos - 1].RowCount; - } - pageItem = columnIndex._pages[pagePos]; - } - else //Expand to double size. - { - var rowsTmp = new IndexItem[pageItem.Rows.Length << 1]; - Array.Copy(pageItem.Rows, 0, rowsTmp, 0, pageItem.RowCount); - pageItem.Rows = rowsTmp; - } - } - if (pos < pageItem.RowCount) - { - Array.Copy(pageItem.Rows, pos, pageItem.Rows, pos + 1, pageItem.RowCount - pos); - } - pageItem.Rows[pos] = new IndexItem() { Index = ix,IndexPointer=_values.Count }; - _values.Add(value); - pageItem.RowCount++; - } - - private int SplitPage(ColumnIndex columnIndex, int pagePos) - { - var page = columnIndex._pages[pagePos]; - if (page.Offset != 0) - { - var offset = page.Offset; - page.Offset = 0; - for (int r = 0; r < page.RowCount; r++) - { - page.Rows[r].Index -= (short)offset; - } - } - //Find Split pos - int splitPos=0; - for (int r = 0; r < page.RowCount; r++) - { - if (page.Rows[r].Index > PageSize) - { - splitPos=r; - break; - } - } - var newPage = new PageIndex(page, 0, splitPos); - var nextPage = new PageIndex(page, splitPos, page.RowCount - splitPos, (short)(page.Index + 1), page.Offset); - - for (int r = 0; r < nextPage.RowCount; r++) - { - nextPage.Rows[r].Index = (short)(nextPage.Rows[r].Index - PageSize); - } - - columnIndex._pages[pagePos] = newPage; - if (columnIndex.PageCount + 1 > columnIndex._pages.Length) - { - var pageTmp = new PageIndex[columnIndex._pages.Length << 1]; - Array.Copy(columnIndex._pages, 0, pageTmp, 0, columnIndex.PageCount); - columnIndex._pages = pageTmp; - } - Array.Copy(columnIndex._pages, pagePos + 1, columnIndex._pages, pagePos + 2, columnIndex.PageCount - pagePos - 1); - columnIndex._pages[pagePos + 1] = nextPage; - page = nextPage; - //pos -= PageSize; - columnIndex.PageCount++; - return pagePos+1; - } - - private PageIndex AdjustIndex(ColumnIndex columnIndex, int pagePos) - { - PageIndex page = columnIndex._pages[pagePos]; - //First Adjust indexes - if (page.Offset + page.Rows[0].Index >= PageSize || - page.Offset >= PageSize || - page.Rows[0].Index >= PageSize) - { - page.Index++; - page.Offset -= PageSize; - } - else if (page.Offset + page.Rows[0].Index <= -PageSize || - page.Offset <= -PageSize || - page.Rows[0].Index <= -PageSize) - { - page.Index--; - page.Offset += PageSize; - } - //else if (page.Rows[0].Index >= PageSize) //Delete - //{ - // page.Index++; - // AddPageRowOffset(page, -PageSize); - //} - //else if (page.Rows[0].Index <= -PageSize) //Delete - //{ - // page.Index--; - // AddPageRowOffset(page, PageSize); - //} - return page; - } - - private void AddPageRowOffset(PageIndex page, short offset) - { - for (int r = 0; r < page.RowCount; r++) - { - page.Rows[r].Index += offset; - } - } - private void AddPage(ColumnIndex column, int pos, short index) - { - AddPage(column, pos); - column._pages[pos] = new PageIndex() { Index = index }; - if (pos > 0) - { - var pp=column._pages[pos-1]; - if(pp.RowCount>0 && pp.Rows[pp.RowCount-1].Index > PageSize) - { - column._pages[pos].Offset = pp.Rows[pp.RowCount-1].Index-PageSize; - } - } - } - /// <summary> - /// Add a new page to the collection - /// </summary> - /// <param name="column">The column</param> - /// <param name="pos">Position</param> - /// <param name="page">The new page object to add</param> - private void AddPage(ColumnIndex column, int pos, PageIndex page) - { - AddPage(column, pos); - column._pages[pos] = page ; - } - /// <summary> - /// Add a new page to the collection - /// </summary> - /// <param name="column">The column</param> - /// <param name="pos">Position</param> - private void AddPage(ColumnIndex column, int pos) - { - if (column.PageCount ==column._pages.Length) - { - var pageTmp = new PageIndex[column._pages.Length * 2]; - Array.Copy(column._pages, 0, pageTmp, 0, column.PageCount); - column._pages = pageTmp; - } - if (pos < column.PageCount) - { - Array.Copy(column._pages, pos, column._pages, pos + 1, column.PageCount - pos); - } - column.PageCount++; - } - private void AddColumn(int pos, int Column) - { - if (ColumnCount == _columnIndex.Length) - { - var colTmp = new ColumnIndex[_columnIndex.Length*2]; - Array.Copy(_columnIndex, 0, colTmp, 0, ColumnCount); - _columnIndex = colTmp; - } - if (pos < ColumnCount) - { - Array.Copy(_columnIndex, pos, _columnIndex, pos + 1, ColumnCount - pos); - } - _columnIndex[pos] = new ColumnIndex() { Index = (short)(Column) }; - ColumnCount++; - } - int _colPos = -1, _row; - public ulong Current - { - get - { - return ((ulong)_row << 32) | (uint)(_columnIndex[_colPos].Index); - } - } - - //object IEnumerator.Current + if (Math.Abs(column._pages[pagePos].Offset) > _pageSize + || Math.Abs(column._pages[pagePos].Rows[column._pages[pagePos].RowCount - 1].Index) + > _pageSizeMax) //Split or Merge??? + { + rows = ResetPageOffset(column, pagePos, rows); + ////MergePages + //if (column.Pages[pagePos - 1].Index + 1 == column.Pages[pagePos].Index) //{ - // get + // if (column.Pages[pagePos].IndexOffset + column.Pages[pagePos].Rows[column.Pages[pagePos].RowCount - 1].Index + rows - + // column.Pages[pagePos - 1].IndexOffset + column.Pages[pagePos - 1].Rows[0].Index <= PageSize) // { - // return GetValue(_row+1, _columnIndex[_colPos].Index); + // //Merge + // MergePage(column, pagePos - 1, -rows); + // } + // else + // { + // //Split // } //} - public bool MoveNext() - { - return GetNextCell(ref _row, ref _colPos, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - } - internal bool NextCell(ref int row, ref int col) - { - - return NextCell(ref row, ref col, 0,0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - } - internal bool NextCell(ref int row, ref int col, int minRow, int minColPos,int maxRow, int maxColPos) - { - if (minColPos >= ColumnCount) - { - return false; - } - if (maxColPos >= ColumnCount) - { - maxColPos = ColumnCount-1; - } - var c=GetPosition(col); - if(c>=0) - { - if (c > maxColPos) - { - if (col <= minColPos) - { - return false; - } - col = minColPos; - return NextCell(ref row, ref col); - } - else - { - var r=GetNextCell(ref row, ref c, minColPos, maxRow, maxColPos); - col = _columnIndex[c].Index; - return r; - } - } - else - { - c=~c; - if (c > _columnIndex[c].Index) - { - if (col <= minColPos) - { - return false; - } - col = minColPos; - return NextCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); - } - else - { - var r=GetNextCell(ref c, ref row, minColPos, maxRow, maxColPos); - col = _columnIndex[c].Index; - return r; - } - } - } - internal bool GetNextCell(ref int row, ref int colPos, int startColPos, int endRow, int endColPos) - { - if (ColumnCount == 0) - { - return false; - } - else - { - if (++colPos < ColumnCount && colPos <=endColPos) - { - var r = _columnIndex[colPos].GetNextRow(row); - if (r == row) //Exists next Row - { - return true; - } - else - { - int minRow, minCol; - if (r > row) - { - minRow = r; - minCol = colPos; - } - else - { - minRow = int.MaxValue; - minCol = 0; - } + //rows -= PageSize; + //for (int p = pagePos; p < column.PageCount; p++) + //{ + // column.Pages[p].Index -= 1; + //} + } + } + } - var c = colPos + 1; - while (c < ColumnCount && c <= endColPos) - { - r = _columnIndex[c].GetNextRow(row); - if (r == row) //Exists next Row - { - colPos = c; - return true; - } - if (r > row && r < minRow) - { - minRow = r; - minCol = c; - } - c++; - } - c = startColPos; - if (row < endRow) - { - row++; - while (c < colPos) - { - r = _columnIndex[c].GetNextRow(row); - if (r == row) //Exists next Row - { - colPos = c; - return true; - } - if (r > row && (r < minRow || (r==minRow && c<minCol)) && r <= endRow) - { - minRow = r; - minCol = c; - } - c++; - } - } - - if (minRow == int.MaxValue || minRow > endRow) - { - return false; - } - else - { - row = minRow; - colPos = minCol; - return true; - } - } - } - else - { - if (colPos <= startColPos || row>=endRow) - { - return false; - } - colPos = startColPos - 1; - row++; - return GetNextCell(ref row, ref colPos, startColPos, endRow, endColPos); - } - } + private int ResetPageOffset(ColumnIndex column, int pagePos, int rows) { + PageIndex fromPage = column._pages[pagePos]; + PageIndex toPage; + short pageAdd = 0; + if (fromPage.Offset < -_pageSize) { + toPage = column._pages[pagePos - 1]; + pageAdd = -1; + if (fromPage.Index - 1 == toPage.Index) { + if (fromPage.IndexOffset + + fromPage.Rows[fromPage.RowCount - 1].Index + - toPage.IndexOffset + + toPage.Rows[0].Index + <= _pageSizeMax) { + MergePage(column, pagePos - 1); + //var newPage = new PageIndex(toPage, 0, GetSize(fromPage.RowCount + toPage.RowCount)); + //newPage.RowCount = fromPage.RowCount + fromPage.RowCount; + //Array.Copy(toPage.Rows, 0, newPage.Rows, 0, toPage.RowCount); + //Array.Copy(fromPage.Rows, 0, newPage.Rows, toPage.RowCount, fromPage.RowCount); + //for (int r = toPage.RowCount; r < newPage.RowCount; r++) + //{ + // newPage.Rows[r].Index += (short)(fromPage.IndexOffset - toPage.IndexOffset); + //} } - internal bool GetNextCell(ref int row, ref int colPos, int startColPos, int endRow, int endColPos, ref int[] pagePos, ref int[] cellPos) - { - if (colPos == endColPos) - { - colPos = startColPos; - row++; - } - else - { - colPos++; - } + } else //No page after + { + fromPage.Index -= pageAdd; + fromPage.Offset += _pageSize; + } + } else if (fromPage.Offset > _pageSize) { + toPage = column._pages[pagePos + 1]; + pageAdd = 1; + if (fromPage.Index + 1 == toPage.Index) {} else { + fromPage.Index += pageAdd; + fromPage.Offset += _pageSize; + } + } + return rows; + } - if (pagePos[colPos] < 0) - { - if(pagePos[colPos]==-1) - { - pagePos[colPos] = _columnIndex[colPos].GetPosition(row); - } - } - else if (_columnIndex[colPos]._pages[pagePos[colPos]].RowCount <= row) - { - if (_columnIndex[colPos].PageCount > pagePos[colPos]) - pagePos[colPos]++; - else - { - pagePos[colPos]=-2; - } - } - - var r = _columnIndex[colPos]._pages[pagePos[colPos]].IndexOffset + _columnIndex[colPos]._pages[pagePos[colPos]].Rows[cellPos[colPos]].Index; - if (r == row) - { - row = r; - } - else - { - } + private int DeletePage(int fromRow, int rows, ColumnIndex column, int pagePos, bool shift) { + PageIndex page = column._pages[pagePos]; + var startRows = rows; + while (page != null + && page.MinIndex >= fromRow + && ((shift && page.MaxIndex < fromRow + rows) + || (!shift && page.MaxIndex < fromRow + startRows))) { + //Delete entire page. + var delSize = page.MaxIndex - page.MinIndex + 1; + rows -= delSize; + var prevOffset = page.Offset; + Array.Copy( + column._pages, + pagePos + 1, + column._pages, + pagePos, + column.PageCount - pagePos + 1); + column.PageCount--; + if (column.PageCount == 0) { + return 0; + } + if (shift) { + for (int i = pagePos; i < column.PageCount; i++) { + column._pages[i].Offset -= delSize; + if (column._pages[i].Offset <= -_pageSize) { + column._pages[i].Index--; + column._pages[i].Offset += _pageSize; + } + } + } + if (column.PageCount > pagePos) { + page = column._pages[pagePos]; + //page.Offset = pagePos == 0 ? 1 : prevOffset; //First page can only reference to rows starting from Index == 1 + } else { + //No more pages, return 0 + return 0; + } + } + return rows; + } + + /// + private int DeleteCells(PageIndex page, int fromRow, int toRow, bool shift) { + var fromPos = page.GetPosition(fromRow - (page.IndexOffset)); + if (fromPos < 0) { + fromPos = ~fromPos; + } + var maxRow = page.MaxIndex; + var offset = toRow - page.IndexOffset; + if (offset > _pageSizeMax) { + offset = _pageSizeMax; + } + var toPos = page.GetPosition(offset); + if (toPos < 0) { + toPos = ~toPos; + } + + if (fromPos <= toPos && fromPos < page.RowCount && page.GetIndex(fromPos) < toRow) { + if (toRow > page.MaxIndex) { + if (fromRow + == page.MinIndex) //Delete entire page, late in the page delete method + { + return fromRow; + } + var r = page.MaxIndex; + var deletedRow = page.RowCount - fromPos; + page.RowCount -= deletedRow; + return r + 1; + } + var rows = toRow - fromRow; + if (shift) { + UpdateRowIndex(page, toPos, rows); + } + Array.Copy(page.Rows, toPos, page.Rows, fromPos, page.RowCount - toPos); + page.RowCount -= toPos - fromPos; + + return toRow; + } + if (shift) { + UpdateRowIndex(page, toPos, toRow - fromRow); + } + return toRow < maxRow ? toRow : maxRow; + } + + private static void UpdateRowIndex(PageIndex page, int toPos, int rows) { + for (int r = toPos; r < page.RowCount; r++) { + page.Rows[r].Index -= (short)rows; + } + } + + private void DeleteColumns(int fromCol, int columns, bool shift) { + var fPos = GetPosition(fromCol); + if (fPos < 0) { + fPos = ~fPos; + } + int tPos = fPos; + for (var c = fPos; c <= ColumnCount; c++) { + tPos = c; + if (tPos == ColumnCount || _columnIndex[c].Index >= fromCol + columns) { + break; + } + } + + if (ColumnCount <= fPos) { + return; + } + + if (_columnIndex[fPos].Index >= fromCol && _columnIndex[fPos].Index <= fromCol + columns) { + //if (_columnIndex[fPos].Index < ColumnCount) + //{ + if (tPos < ColumnCount) { + Array.Copy(_columnIndex, tPos, _columnIndex, fPos, ColumnCount - tPos); + } + ColumnCount -= (tPos - fPos); + //} + } + if (shift) { + for (var c = fPos; c < ColumnCount; c++) { + _columnIndex[c].Index -= (short)columns; + } + } + } + + private void UpdateIndexOffset(ColumnIndex column, int pagePos, int rowPos, int row, int rows) { + if (pagePos >= column.PageCount) { + return; //A page after last cell. + } + var page = column._pages[pagePos]; + if (rows > _pageSize) { + short addPages = (short)(rows >> _pageBits); + int offset = +(rows - (_pageSize * addPages)); + for (int p = pagePos + 1; p < column.PageCount; p++) { + if (column._pages[p].Offset + offset > _pageSize) { + column._pages[p].Index += (short)(addPages + 1); + column._pages[p].Offset += offset - _pageSize; + } else { + column._pages[p].Index += addPages; + column._pages[p].Offset += offset; + } + } + + var size = page.RowCount - rowPos; + if (page.RowCount > rowPos) { + if (column.PageCount - 1 + == pagePos) //No page after, create a new one. + { + //Copy rows to next page. + var newPage = CopyNew(page, rowPos, size); + newPage.Index = (short)((row + rows) >> _pageBits); + newPage.Offset = row + rows - (newPage.Index * _pageSize) - newPage.Rows[0].Index; + if (newPage.Offset > _pageSize) { + newPage.Index++; + newPage.Offset -= _pageSize; + } + AddPage(column, pagePos + 1, newPage); + page.RowCount = rowPos; + } else { + if (column._pages[pagePos + 1].RowCount + size + > _pageSizeMax) //Split Page + { + SplitPageInsert(column, pagePos, rowPos, rows, size, addPages); + } else //Copy Page. + { + CopyMergePage(page, rowPos, rows, size, column._pages[pagePos + 1]); + } + } + } + } else { + //Add to Pages. + for (int r = rowPos; r < page.RowCount; r++) { + page.Rows[r].Index += (short)rows; + } + if (page.Offset + page.Rows[page.RowCount - 1].Index + >= _pageSizeMax) //Can not be larger than the max size of the page. + { + AdjustIndex(column, pagePos); + if (page.Offset + page.Rows[page.RowCount - 1].Index >= _pageSizeMax) { + pagePos = SplitPage(column, pagePos); + } + //IndexItem[] newRows = new IndexItem[GetSize(page.RowCount - page.Rows[r].Index)]; + //var newPage = new PageIndex(newRows, r); + //newPage.Index = (short)(pagePos + 1); + //TODO: MoveRows to next page. + } + + for (int p = pagePos + 1; p < column.PageCount; p++) { + if (column._pages[p].Offset + rows < _pageSize) { + column._pages[p].Offset += rows; + } else { + column._pages[p].Index++; + column._pages[p].Offset = (column._pages[p].Offset + rows) % _pageSize; + } + } + } + } + + private void SplitPageInsert( + ColumnIndex column, + int pagePos, + int rowPos, + int rows, + int size, + int addPages) { + var newRows = new IndexItem[GetSize(size)]; + var page = column._pages[pagePos]; + + var rStart = -1; + for (int r = rowPos; r < page.RowCount; r++) { + if (page.IndexExpanded - (page.Rows[r].Index + rows) > _pageSize) { + rStart = r; + break; + } + page.Rows[r].Index += (short)rows; + } + var rc = page.RowCount - rStart; + page.RowCount = rStart; + if (rc > 0) { + //Copy to a new page + var row = page.IndexOffset; + var newPage = CopyNew(page, rStart, rc); + var ix = (short)(page.Index + addPages); + var offset = page.IndexOffset + rows - (ix * _pageSize); + if (offset > _pageSize) { + ix += (short)(offset / _pageSize); + offset %= _pageSize; + } + newPage.Index = ix; + newPage.Offset = offset; + AddPage(column, pagePos + 1, newPage); + } + + //Copy from next Row + } + + private void CopyMergePage(PageIndex page, int rowPos, int rows, int size, PageIndex toPage) { + var startRow = page.IndexOffset + page.Rows[rowPos].Index + rows; + var newRows = new IndexItem[GetSize(toPage.RowCount + size)]; + page.RowCount -= size; + Array.Copy(page.Rows, rowPos, newRows, 0, size); + for (int r = 0; r < size; r++) { + newRows[r].Index += (short)(page.IndexOffset + rows - toPage.IndexOffset); + } + + Array.Copy(toPage.Rows, 0, newRows, size, toPage.RowCount); + toPage.Rows = newRows; + toPage.RowCount += size; + } + + private void MergePage(ColumnIndex column, int pagePos) { + PageIndex page1 = column._pages[pagePos]; + PageIndex page2 = column._pages[pagePos + 1]; + + var newPage = new PageIndex(page1, 0, page1.RowCount + page2.RowCount); + newPage.RowCount = page1.RowCount + page2.RowCount; + Array.Copy(page1.Rows, 0, newPage.Rows, 0, page1.RowCount); + Array.Copy(page2.Rows, 0, newPage.Rows, page1.RowCount, page2.RowCount); + for (int r = page1.RowCount; r < newPage.RowCount; r++) { + newPage.Rows[r].Index += (short)(page2.IndexOffset - page1.IndexOffset); + } + + column._pages[pagePos] = newPage; + column.PageCount--; + + if (column.PageCount > (pagePos + 1)) { + Array.Copy( + column._pages, + pagePos + 2, + column._pages, + pagePos + 1, + column.PageCount - (pagePos + 1)); + for (int p = pagePos + 1; p < column.PageCount; p++) { + column._pages[p].Index--; + column._pages[p].Offset += _pageSize; + } + } + } + + private PageIndex CopyNew(PageIndex pageFrom, int rowPos, int size) { + IndexItem[] newRows = new IndexItem[GetSize(size)]; + Array.Copy(pageFrom.Rows, rowPos, newRows, 0, size); + return new(newRows, size); + } + + internal static int GetSize(int size) { + var newSize = 256; + while (newSize < size) { + newSize <<= 1; + } + return newSize; + } + + private void AddCell(ColumnIndex columnIndex, int pagePos, int pos, short ix, T value) { + PageIndex pageItem = columnIndex._pages[pagePos]; + if (pageItem.RowCount == pageItem.Rows.Length) { + if (pageItem.RowCount + == _pageSizeMax) //Max size-->Split + { + pagePos = SplitPage(columnIndex, pagePos); + if (columnIndex._pages[pagePos - 1].RowCount > pos) { + pagePos--; + } else { + pos -= columnIndex._pages[pagePos - 1].RowCount; + } + pageItem = columnIndex._pages[pagePos]; + } else //Expand to double size. + { + var rowsTmp = new IndexItem[pageItem.Rows.Length << 1]; + Array.Copy(pageItem.Rows, 0, rowsTmp, 0, pageItem.RowCount); + pageItem.Rows = rowsTmp; + } + } + if (pos < pageItem.RowCount) { + Array.Copy(pageItem.Rows, pos, pageItem.Rows, pos + 1, pageItem.RowCount - pos); + } + pageItem.Rows[pos] = new() { + Index = ix, + IndexPointer = _values.Count, + }; + _values.Add(value); + pageItem.RowCount++; + } + + private int SplitPage(ColumnIndex columnIndex, int pagePos) { + var page = columnIndex._pages[pagePos]; + if (page.Offset != 0) { + var offset = page.Offset; + page.Offset = 0; + for (int r = 0; r < page.RowCount; r++) { + page.Rows[r].Index -= (short)offset; + } + } + //Find Split pos + int splitPos = 0; + for (int r = 0; r < page.RowCount; r++) { + if (page.Rows[r].Index > _pageSize) { + splitPos = r; + break; + } + } + var newPage = new PageIndex(page, 0, splitPos); + var nextPage = new PageIndex( + page, + splitPos, + page.RowCount - splitPos, + (short)(page.Index + 1), + page.Offset); + + for (int r = 0; r < nextPage.RowCount; r++) { + nextPage.Rows[r].Index = (short)(nextPage.Rows[r].Index - _pageSize); + } + + columnIndex._pages[pagePos] = newPage; + if (columnIndex.PageCount + 1 > columnIndex._pages.Length) { + var pageTmp = new PageIndex[columnIndex._pages.Length << 1]; + Array.Copy(columnIndex._pages, 0, pageTmp, 0, columnIndex.PageCount); + columnIndex._pages = pageTmp; + } + Array.Copy( + columnIndex._pages, + pagePos + 1, + columnIndex._pages, + pagePos + 2, + columnIndex.PageCount - pagePos - 1); + columnIndex._pages[pagePos + 1] = nextPage; + page = nextPage; + //pos -= PageSize; + columnIndex.PageCount++; + return pagePos + 1; + } + + private PageIndex AdjustIndex(ColumnIndex columnIndex, int pagePos) { + PageIndex page = columnIndex._pages[pagePos]; + //First Adjust indexes + if (page.Offset + page.Rows[0].Index >= _pageSize + || page.Offset >= _pageSize + || page.Rows[0].Index >= _pageSize) { + page.Index++; + page.Offset -= _pageSize; + } else if (page.Offset + page.Rows[0].Index <= -_pageSize + || page.Offset <= -_pageSize + || page.Rows[0].Index <= -_pageSize) { + page.Index--; + page.Offset += _pageSize; + } + //else if (page.Rows[0].Index >= PageSize) //Delete + //{ + // page.Index++; + // AddPageRowOffset(page, -PageSize); + //} + //else if (page.Rows[0].Index <= -PageSize) //Delete + //{ + // page.Index--; + // AddPageRowOffset(page, PageSize); + //} + return page; + } + + private void AddPageRowOffset(PageIndex page, short offset) { + for (int r = 0; r < page.RowCount; r++) { + page.Rows[r].Index += offset; + } + } + + private void AddPage(ColumnIndex column, int pos, short index) { + AddPage(column, pos); + column._pages[pos] = new() { + Index = index, + }; + if (pos > 0) { + var pp = column._pages[pos - 1]; + if (pp.RowCount > 0 && pp.Rows[pp.RowCount - 1].Index > _pageSize) { + column._pages[pos].Offset = pp.Rows[pp.RowCount - 1].Index - _pageSize; + } + } + } + + /// <summary> + /// Add a new page to the collection + /// </summary> + /// <param name="column">The column</param> + /// <param name="pos">Position</param> + /// <param name="page">The new page object to add</param> + private void AddPage(ColumnIndex column, int pos, PageIndex page) { + AddPage(column, pos); + column._pages[pos] = page; + } + + /// <summary> + /// Add a new page to the collection + /// </summary> + /// <param name="column">The column</param> + /// <param name="pos">Position</param> + private void AddPage(ColumnIndex column, int pos) { + if (column.PageCount == column._pages.Length) { + var pageTmp = new PageIndex[column._pages.Length * 2]; + Array.Copy(column._pages, 0, pageTmp, 0, column.PageCount); + column._pages = pageTmp; + } + if (pos < column.PageCount) { + Array.Copy(column._pages, pos, column._pages, pos + 1, column.PageCount - pos); + } + column.PageCount++; + } + + private void AddColumn(int pos, int column) { + if (ColumnCount == _columnIndex.Length) { + var colTmp = new ColumnIndex[_columnIndex.Length * 2]; + Array.Copy(_columnIndex, 0, colTmp, 0, ColumnCount); + _columnIndex = colTmp; + } + if (pos < ColumnCount) { + Array.Copy(_columnIndex, pos, _columnIndex, pos + 1, ColumnCount - pos); + } + _columnIndex[pos] = new() { + Index = (short)(column), + }; + ColumnCount++; + } + + private int _colPos = -1, + _row; + + public ulong Current => ((ulong)_row << 32) | (uint)(_columnIndex[_colPos].Index); + + //object IEnumerator.Current + //{ + // get + // { + // return GetValue(_row+1, _columnIndex[_colPos].Index); + // } + //} + public bool MoveNext() { + return GetNextCell(ref _row, ref _colPos, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); + } + + internal bool NextCell(ref int row, ref int col) { + return NextCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); + } + + internal bool NextCell( + ref int row, + ref int col, + int minRow, + int minColPos, + int maxRow, + int maxColPos) { + if (minColPos >= ColumnCount) { + return false; + } + if (maxColPos >= ColumnCount) { + maxColPos = ColumnCount - 1; + } + var c = GetPosition(col); + if (c >= 0) { + if (c > maxColPos) { + if (col <= minColPos) { + return false; + } + col = minColPos; + return NextCell(ref row, ref col); + } + var r = GetNextCell(ref row, ref c, minColPos, maxRow, maxColPos); + col = _columnIndex[c].Index; + return r; + } + c = ~c; + if (c > _columnIndex[c].Index) { + if (col <= minColPos) { + return false; + } + col = minColPos; + return NextCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); + } + { + var r = GetNextCell(ref c, ref row, minColPos, maxRow, maxColPos); + col = _columnIndex[c].Index; + return r; + } + } + + internal bool GetNextCell( + ref int row, + ref int colPos, + int startColPos, + int endRow, + int endColPos) { + if (ColumnCount == 0) { + return false; + } + if (++colPos < ColumnCount && colPos <= endColPos) { + var r = _columnIndex[colPos].GetNextRow(row); + if (r + == row) //Exists next Row + { + return true; + } + int minRow, + minCol; + if (r > row) { + minRow = r; + minCol = colPos; + } else { + minRow = int.MaxValue; + minCol = 0; + } + + var c = colPos + 1; + while (c < ColumnCount && c <= endColPos) { + r = _columnIndex[c].GetNextRow(row); + if (r + == row) //Exists next Row + { + colPos = c; + return true; + } + if (r > row && r < minRow) { + minRow = r; + minCol = c; + } + c++; + } + c = startColPos; + if (row < endRow) { + row++; + while (c < colPos) { + r = _columnIndex[c].GetNextRow(row); + if (r + == row) //Exists next Row + { + colPos = c; return true; + } + if (r > row && (r < minRow || (r == minRow && c < minCol)) && r <= endRow) { + minRow = r; + minCol = c; + } + c++; } - internal bool PrevCell(ref int row, ref int col) - { - return PrevCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - } - internal bool PrevCell(ref int row, ref int col, int minRow, int minColPos, int maxRow, int maxColPos) - { - if (minColPos >= ColumnCount) - { - return false; - } - if (maxColPos >= ColumnCount) - { - maxColPos = ColumnCount - 1; - } - var c = GetPosition(col); - if(c>=0) - { - if (c == 0) - { - if (col >= maxColPos) - { - return false; - } - if (row == minRow) - { - return false; - } - row--; - col = maxColPos; - return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); - } - else - { - var ret=GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos); - if (ret) - { - col = _columnIndex[c].Index; - } - return ret; - } - } - else - { - c=~c; - if (c == 0) - { - if (col >= maxColPos || row<=0) - { - return false; - } - col = maxColPos; - row--; - return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); - } - else - { - var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos); - if (ret) - { - col = _columnIndex[c].Index; - } - return ret; - } - } - } - internal bool GetPrevCell(ref int row, ref int colPos, int startRow, int startColPos, int endColPos) - { - if (ColumnCount == 0) - { - return false; - } - else - { - if (--colPos >= startColPos) -// if (++colPos < ColumnCount && colPos <= endColPos) - { - var r = _columnIndex[colPos].GetNextRow(row); - if (r == row) //Exists next Row - { - return true; - } - else - { - int minRow, minCol; - if (r > row && r >= startRow) - { - minRow = r; - minCol = colPos; - } - else - { - minRow = int.MaxValue; - minCol = 0; - } + } - var c = colPos - 1; - if (c >= startColPos) - { - while (c >= startColPos) - { - r = _columnIndex[c].GetNextRow(row); - if (r == row) //Exists next Row - { - colPos = c; - return true; - } - if (r > row && r < minRow && r >= startRow) - { - minRow = r; - minCol = c; - } - c--; - } - } - if (row > startRow) - { - c = endColPos; - row--; - while (c > colPos) - { - r = _columnIndex[c].GetNextRow(row); - if (r == row) //Exists next Row - { - colPos = c; - return true; - } - if (r > row && r < minRow && r >= startRow) - { - minRow = r; - minCol = c; - } - c--; - } - } - if (minRow == int.MaxValue || startRow < minRow) - { - return false; - } - else - { - row = minRow; - colPos = minCol; - return true; - } - } - } - else - { - colPos = ColumnCount; - row--; - if (row < startRow) - { - Reset(); - return false; - } - else - { - return GetPrevCell(ref colPos, ref row, startRow, startColPos, endColPos); - } - } - } - } - public void Reset() - { - _colPos = -1; - _row= 0; - } - - //public IEnumerator<ulong> GetEnumerator() - //{ - // this.Reset(); - // return this; - //} - - //IEnumerator IEnumerable.GetEnumerator() - //{ - // this.Reset(); - // return this; - //} - + if (minRow == int.MaxValue || minRow > endRow) { + return false; + } + row = minRow; + colPos = minCol; + return true; } - internal class CellsStoreEnumerator<T> : IEnumerable<T>, IEnumerator<T> + if (colPos <= startColPos || row >= endRow) { + return false; + } + colPos = startColPos - 1; + row++; + return GetNextCell(ref row, ref colPos, startColPos, endRow, endColPos); + } + + internal bool GetNextCell( + ref int row, + ref int colPos, + int startColPos, + int endRow, + int endColPos, + ref int[] pagePos, + ref int[] cellPos) { + if (colPos == endColPos) { + colPos = startColPos; + row++; + } else { + colPos++; + } + + if (pagePos[colPos] < 0) { + if (pagePos[colPos] == -1) { + pagePos[colPos] = _columnIndex[colPos].GetPosition(row); + } + } else if (_columnIndex[colPos]._pages[pagePos[colPos]].RowCount <= row) { + if (_columnIndex[colPos].PageCount > pagePos[colPos]) { + pagePos[colPos]++; + } else { + pagePos[colPos] = -2; + } + } + + var r = + _columnIndex[colPos]._pages[pagePos[colPos]].IndexOffset + + _columnIndex[colPos]._pages[pagePos[colPos]].Rows[cellPos[colPos]].Index; + if (r == row) { + row = r; + } + return true; + } + + internal bool PrevCell(ref int row, ref int col) { + return PrevCell(ref row, ref col, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); + } + + internal bool PrevCell( + ref int row, + ref int col, + int minRow, + int minColPos, + int maxRow, + int maxColPos) { + if (minColPos >= ColumnCount) { + return false; + } + if (maxColPos >= ColumnCount) { + maxColPos = ColumnCount - 1; + } + var c = GetPosition(col); + if (c >= 0) { + if (c == 0) { + if (col >= maxColPos) { + return false; + } + if (row == minRow) { + return false; + } + row--; + col = maxColPos; + return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); + } + var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos); + if (ret) { + col = _columnIndex[c].Index; + } + return ret; + } + c = ~c; + if (c == 0) { + if (col >= maxColPos || row <= 0) { + return false; + } + col = maxColPos; + row--; + return PrevCell(ref row, ref col, minRow, minColPos, maxRow, maxColPos); + } { - CellStore<T> _cellStore; - int row, colPos; - int[] pagePos, cellPos; - int _startRow, _startCol, _endRow, _endCol; - int minRow, minColPos, maxRow, maxColPos; - public CellsStoreEnumerator(CellStore<T> cellStore) : - this(cellStore, 0,0,ExcelPackage.MaxRows, ExcelPackage.MaxColumns) - { - } - public CellsStoreEnumerator(CellStore<T> cellStore, int StartRow, int StartCol, int EndRow, int EndCol) - { - _cellStore = cellStore; - - _startRow=StartRow; - _startCol=StartCol; - _endRow=EndRow; - _endCol=EndCol; - - Init(); - - } - - internal void Init() - { - minRow = _startRow; - maxRow = _endRow; - - minColPos = _cellStore.GetPosition(_startCol); - if (minColPos < 0) minColPos = ~minColPos; - maxColPos = _cellStore.GetPosition(_endCol); - if (maxColPos < 0) maxColPos = ~maxColPos-1; - row = minRow; - colPos = minColPos - 1; - - var cols = maxColPos - minColPos + 1; - pagePos = new int[cols]; - cellPos = new int[cols]; - for (int i = 0; i < cols; i++) - { - pagePos[i] = -1; - cellPos[i] = -1; - } - } - internal int Row - { - get - { - return row; - } - } - internal int Column - { - get - { - if (colPos == -1) MoveNext(); - if (colPos == -1) return 0; - return _cellStore._columnIndex[colPos].Index; - } - } - internal T Value - { - get - { - lock (_cellStore) - { - return _cellStore.GetValue(row, Column); - } - } - set - { - lock (_cellStore) - { - _cellStore.SetValue(row, Column, value); - } - } - } - internal bool Next() - { - //return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos); - return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos); - } - internal bool Previous() - { - lock (_cellStore) - { - return _cellStore.GetPrevCell(ref row, ref colPos, minRow, minColPos, maxColPos); - } - } - - public string CellAddress - { - get - { - return ExcelAddressBase.GetAddress(Row, Column); - } - } - - public IEnumerator<T> GetEnumerator() - { - Reset(); - return this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - Reset(); - return this; - } - - public T Current - { - get - { - return Value; - } - } - - public void Dispose() { } - - object IEnumerator.Current - { - get - { - Reset(); - return this; - } - } - - public bool MoveNext() - { - return Next(); - } - - public void Reset() - { - Init(); - } + var ret = GetPrevCell(ref row, ref c, minRow, minColPos, maxColPos); + if (ret) { + col = _columnIndex[c].Index; + } + return ret; } - internal class FlagCellStore : CellStore<byte> + } + + internal bool GetPrevCell( + ref int row, + ref int colPos, + int startRow, + int startColPos, + int endColPos) { + if (ColumnCount == 0) { + return false; + } + if (--colPos >= startColPos) + // if (++colPos < ColumnCount && colPos <= endColPos) { - internal void SetFlagValue(int Row, int Col, bool value, CellFlags cellFlags) - { - CellFlags currentValue = (CellFlags) GetValue(Row, Col); - if (value) - { - SetValue(Row, Col, (byte)(currentValue | cellFlags)); // add the CellFlag bit - } - else - { - SetValue(Row, Col, (byte)(currentValue & ~cellFlags)); // remove the CellFlag bit - } + var r = _columnIndex[colPos].GetNextRow(row); + if (r + == row) //Exists next Row + { + return true; + } + int minRow, + minCol; + if (r > row && r >= startRow) { + minRow = r; + minCol = colPos; + } else { + minRow = int.MaxValue; + minCol = 0; + } + + var c = colPos - 1; + if (c >= startColPos) { + while (c >= startColPos) { + r = _columnIndex[c].GetNextRow(row); + if (r + == row) //Exists next Row + { + colPos = c; + return true; + } + if (r > row && r < minRow && r >= startRow) { + minRow = r; + minCol = c; + } + c--; } - internal bool GetFlagValue(int Row, int Col, CellFlags cellFlags) - { - return !(((byte)cellFlags & GetValue(Row, Col)) == 0); + } + if (row > startRow) { + c = endColPos; + row--; + while (c > colPos) { + r = _columnIndex[c].GetNextRow(row); + if (r + == row) //Exists next Row + { + colPos = c; + return true; + } + if (r > row && r < minRow && r >= startRow) { + minRow = r; + minCol = c; + } + c--; } + } + if (minRow == int.MaxValue || startRow < minRow) { + return false; + } + row = minRow; + colPos = minCol; + return true; } + colPos = ColumnCount; + row--; + if (row < startRow) { + Reset(); + return false; + } + return GetPrevCell(ref colPos, ref row, startRow, startColPos, endColPos); + } + + public void Reset() { + _colPos = -1; + _row = 0; + } + + //public IEnumerator<ulong> GetEnumerator() + //{ + // this.Reset(); + // return this; + //} + + //IEnumerator IEnumerable.GetEnumerator() + //{ + // this.Reset(); + // return this; + //} +} + +internal class CellsStoreEnumerator<T> : IEnumerable<T>, IEnumerator<T> { + private CellStore<T> _cellStore; + private int row, + colPos; + private int[] pagePos, + cellPos; + private int _startRow, + _startCol, + _endRow, + _endCol; + private int minRow, + minColPos, + maxRow, + maxColPos; + + public CellsStoreEnumerator(CellStore<T> cellStore) + : this(cellStore, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns) {} + + public CellsStoreEnumerator( + CellStore<T> cellStore, + int startRow, + int startCol, + int endRow, + int endCol) { + _cellStore = cellStore; + + _startRow = startRow; + _startCol = startCol; + _endRow = endRow; + _endCol = endCol; + + Init(); + } + + internal void Init() { + minRow = _startRow; + maxRow = _endRow; + + minColPos = _cellStore.GetPosition(_startCol); + if (minColPos < 0) { + minColPos = ~minColPos; + } + maxColPos = _cellStore.GetPosition(_endCol); + if (maxColPos < 0) { + maxColPos = ~maxColPos - 1; + } + row = minRow; + colPos = minColPos - 1; + + var cols = maxColPos - minColPos + 1; + pagePos = new int[cols]; + cellPos = new int[cols]; + for (int i = 0; i < cols; i++) { + pagePos[i] = -1; + cellPos[i] = -1; + } + } + + internal int Row => row; + + internal int Column { + get { + if (colPos == -1) { + MoveNext(); + } + if (colPos == -1) { + return 0; + } + return _cellStore._columnIndex[colPos].Index; + } + } + + internal T Value { + get { + lock (_cellStore) { + return _cellStore.GetValue(row, Column); + } + } + set { + lock (_cellStore) { + _cellStore.SetValue(row, Column, value); + } + } + } + + internal bool Next() { + //return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos); + return _cellStore.GetNextCell(ref row, ref colPos, minColPos, maxRow, maxColPos); + } + + internal bool Previous() { + lock (_cellStore) { + return _cellStore.GetPrevCell(ref row, ref colPos, minRow, minColPos, maxColPos); + } + } + + public string CellAddress => ExcelCellBase.GetAddress(Row, Column); + + public IEnumerator<T> GetEnumerator() { + Reset(); + return this; + } + + IEnumerator IEnumerable.GetEnumerator() { + Reset(); + return this; + } + + public T Current => Value; + + public void Dispose() {} + + object IEnumerator.Current { + get { + Reset(); + return this; + } + } + + public bool MoveNext() { + return Next(); + } + + public void Reset() { + Init(); + } +} + +internal class FlagCellStore : CellStore<byte> { + internal void SetFlagValue(int row, int col, bool value, CellFlags cellFlags) { + CellFlags currentValue = (CellFlags)GetValue(row, col); + if (value) { + SetValue(row, col, (byte)(currentValue | cellFlags)); // add the CellFlag bit + } else { + SetValue(row, col, (byte)(currentValue & ~cellFlags)); // remove the CellFlag bit + } + } + + internal bool GetFlagValue(int row, int col, CellFlags cellFlags) { + return !(((byte)cellFlags & GetValue(row, col)) == 0); + } +}
diff --git a/EPPlus/ConditionalFormatting/CF Implementation.cs b/EPPlus/ConditionalFormatting/CF Implementation.cs deleted file mode 100644 index 137d3c4..0000000 --- a/EPPlus/ConditionalFormatting/CF Implementation.cs +++ /dev/null
@@ -1,392 +0,0 @@ -#region TODO -//TODO: Add the "DataBar" extended options -//TODO: Add tests for all the rules -//TODO: Add the IconSet options -//TODO: Add all the "extList" options -#endregion - -#region §18.3.1.18 conditionalFormatting (Conditional Formatting) -//Childs: -//cfRule (Conditional Formatting Rule) §18.3.1.10 -//extLst (Future Feature Data Storage Area) §18.2.10 - -//Attributes: -//pivot -//sqref ST_Sqref simple type (§18.18.76) -#endregion - -#region §18.3.1.10 cfRule (Conditional Formatting Rule) -//Childs: -//colorScale (Color Scale) §18.3.1.16 -//dataBar (Data Bar) §18.3.1.28 -//extLst (Future Feature Data Storage Area) §18.2.10 -//formula (Formula) §18.3.1.43 -//iconSet (Icon Set) §18.3.1.49 - -//Attributes: -//----------- -//priority (Priority) The priority of this conditional formatting rule. This value is used to determine which -// format should be evaluated and rendered. Lower numeric values are higher priority than -// higher numeric values, where 1 is the highest priority. -//stopIfTrue (Stop If True) If this flag is 1, no rules with lower priority shall be applied over this rule, when this rule -// evaluates to true. -//type (Type) Type of conditional formatting rule. ST_CfType §18.18.12. -//aboveAverage Indicates whether the rule is an "above average" rule. 1 indicates 'above average'. -// This attribute is ignored if type is not equal to aboveAverage. -//equalAverage (Equal Average) -// Flag indicating whether the 'aboveAverage' and 'belowAverage' criteria is inclusive of the -// average itself, or exclusive of that value. 1 indicates to include the average value in the -// criteria. This attribute is ignored if type is not equal to aboveAverage. -//bottom (Bottom N) Indicates whether a "top/bottom n" rule is a "bottom n" rule. 1 indicates 'bottom'. -// This attribute is ignored if type is not equal to top10. -//dxfId (Differential Formatting Id) -// This is an index to a dxf element in the Styles Part indicating which cell formatting to -// apply when the conditional formatting rule criteria is met. ST_DxfId simple type (§18.18.25). -//operator (Operator) The operator in a "cell value is" conditional formatting rule. This attribute is ignored if -// type is not equal to cellIs. The possible values ST_ConditionalFormattingOperator simple type (§18.18.15). -//percent (Top 10 Percent) -// Indicates whether a "top/bottom n" rule is a "top/bottom n percent" rule. This attribute -// is ignored if type is not equal to top10. -//rank (Rank) The value of "n" in a "top/bottom n" conditional formatting rule. This attribute is ignored -// if type is not equal to top10. -//stdDev (StdDev) The number of standard deviations to include above or below the average in the -// conditional formatting rule. This attribute is ignored if type is not equal to aboveAverage. -// If a value is present for stdDev and the rule type = aboveAverage, then this rule is automatically an -// "above or below N standard deviations" rule. -//text (Text) The text value in a "text contains" conditional formatting rule. This attribute is ignored if -// type is not equal to containsText. -//timePeriod (Time Period) The applicable time period in a "date occurring…" conditional formatting rule. This -// attribute is ignored if type is not equal to timePeriod. ST_TimePeriod §18.18.82. -#endregion - -#region Conditional Formatting XML examples -// All the examples are assumed to be inside <conditionalFormatting sqref="A1:A10"> - -#region Example "beginsWith" -//<x:cfRule type="beginsWith" dxfId="6" priority="5" operator="beginsWith" text="a"> -// <x:formula>LEFT(A1,LEN("a"))="a"</x:formula> -//</x:cfRule> - -//<x:cfRule type="beginsWith" dxfId="5" priority="14" operator="beginsWith" text=""<>"> -// <x:formula>LEFT(A3,LEN("""<>"))="""<>"</x:formula> -//</x:cfRule> -#endregion - -#region Example "between" -//<x:cfRule type="cellIs" dxfId="8" priority="10" operator="between"> -// <x:formula>3</x:formula> -// <x:formula>7</x:formula> -//</x:cfRule> -#endregion - -#region Example "containsText" -//<x:cfRule type="containsText" dxfId="5" priority="4" operator="containsText" text="c"> -// <x:formula>NOT(ISERROR(SEARCH("c",A1)))</x:formula> -//</x:cfRule> -#endregion - -#region Example "endsWith" -//<x:cfRule type="endsWith" dxfId="9" priority="11" operator="endsWith" text="c"> -// <x:formula>RIGHT(A1,LEN("c"))="c"</x:formula> -//</x:cfRule> -#endregion - -#region Example "equal" -//<x:cfRule type="cellIs" dxfId="7" priority="8" operator="equal"> -// <x:formula>"ab"</x:formula> -//</x:cfRule> -#endregion - -#region Example "greaterThan" -//<x:cfRule type="cellIs" dxfId="6" priority="7" operator="greaterThan"> -// <x:formula>4</x:formula> -//</x:cfRule> -#endregion - -#region Example "greaterThanOrEqual" -//<x:cfRule type="cellIs" dxfId="3" priority="4" operator="greaterThanOrEqual"> -// <x:formula>4</x:formula> -//</x:cfRule> -#endregion - -#region Example "lessThan" -//<x:cfRule type="cellIs" dxfId="5" priority="6" operator="lessThan"> -// <x:formula>4</x:formula> -//</x:cfRule> -#endregion - -#region Example "lessThanOrEqual" -//<x:cfRule type="cellIs" dxfId="4" priority="5" operator="lessThanOrEqual"> -// <x:formula>4</x:formula> -//</x:cfRule> -#endregion - -#region Example "notBetween" -//<x:cfRule type="cellIs" dxfId="2" priority="3" operator="notBetween"> -// <x:formula>3</x:formula> -// <x:formula>7</x:formula> -//</x:cfRule> -#endregion - -#region Example "notContainsText" -//<x:cfRule type="notContainsText" dxfId="4" priority="3" operator="notContains" text="c"> -// <x:formula>ISERROR(SEARCH("c",A1))</x:formula> -//</x:cfRule> -#endregion - -#region Example "notEqual" -//<x:cfRule type="cellIs" dxfId="1" priority="2" operator="notEqual"> -// <x:formula>"ab"</x:formula> -//</x:cfRule> -#endregion - -#region Example "containsBlanks" -//<x:cfRule type="containsBlanks" dxfId="20" priority="37"> -// <x:formula>LEN(TRIM(A1))=0</x:formula> -//</x:cfRule> -#endregion - -#region Example "containsErrors" -//<x:cfRule type="containsErrors" dxfId="15" priority="19"> -// <x:formula>ISERROR(A1)</x:formula> -//</x:cfRule> -#endregion - -#region Example "expression" -//<x:cfRule type="expression" dxfId="0" priority="1"> -// <x:formula>RIGHT(J16,1)="b"</x:formula> -//</x:cfRule> -#endregion - -#region Example "duplicateValues" -//<x:cfRule type="duplicateValues" dxfId="14" priority="16" /> -#endregion - -#region Example "notContainsBlanks" -//<x:cfRule type="notContainsBlanks" dxfId="12" priority="14"> -// <x:formula>LEN(TRIM(A1))>0</x:formula> -//</x:cfRule> -#endregion - -#region Example "notContainsErrors" -//<x:cfRule type="notContainsErrors" dxfId="11" priority="36"> -// <x:formula>NOT(ISERROR(A1))</x:formula> -//</x:cfRule> -#endregion - -#region Example "uniqueValues" -//<x:cfRule type="uniqueValues" dxfId="13" priority="15" /> -#endregion - -#region Example "last7Days" -//<x:cfRule type="timePeriod" dxfId="39" priority="10" timePeriod="last7Days"> -// <x:formula>AND(TODAY()-FLOOR(A1,1)<=6,FLOOR(A1,1)<=TODAY())</x:formula> -//</x:cfRule> -#endregion - -#region Example "lastMonth" -//<x:cfRule type="timePeriod" dxfId="38" priority="9" timePeriod="lastMonth"> -// <x:formula>AND(MONTH(A1)=MONTH(EDATE(TODAY(),0-1)),YEAR(A1)=YEAR(EDATE(TODAY(),0-1)))</x:formula> -//</x:cfRule> -#endregion - -#region Example "lastWeek" -//<x:cfRule type="timePeriod" dxfId="37" priority="8" timePeriod="lastWeek"> -// <x:formula>AND(TODAY()-ROUNDDOWN(A1,0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN(A1,0)<(WEEKDAY(TODAY())+7))</x:formula> -//</x:cfRule> -#endregion - -#region Example "nextMonth" -//<x:cfRule type="timePeriod" dxfId="36" priority="7" timePeriod="nextMonth"> -// <x:formula>AND(MONTH(A1)=MONTH(EDATE(TODAY(),0+1)),YEAR(A1)=YEAR(EDATE(TODAY(),0+1)))</x:formula> -//</x:cfRule> -#endregion - -#region Example "nextWeek" -//<x:cfRule type="timePeriod" dxfId="35" priority="6" timePeriod="nextWeek"> -// <x:formula>AND(ROUNDDOWN(A1,0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN(A1,0)-TODAY()<(15-WEEKDAY(TODAY())))</x:formula> -//</x:cfRule> -#endregion - -#region Example "thisMonth" -//<x:cfRule type="timePeriod" dxfId="34" priority="5" timePeriod="thisMonth"> -// <x:formula>AND(MONTH(A1)=MONTH(TODAY()),YEAR(A1)=YEAR(TODAY()))</x:formula> -//</x:cfRule> -#endregion - -#region Example "thisWeek" -//<x:cfRule type="timePeriod" dxfId="33" priority="4" timePeriod="thisWeek"> -// <x:formula>AND(TODAY()-ROUNDDOWN(A1,0)<=WEEKDAY(TODAY())-1,ROUNDDOWN(A1,0)-TODAY()<=7-WEEKDAY(TODAY()))</x:formula> -//</x:cfRule> -#endregion - -#region Example "today" -//<x:cfRule type="timePeriod" dxfId="32" priority="3" timePeriod="today"> -// <x:formula>FLOOR(A1,1)=TODAY()</x:formula> -//</x:cfRule> -#endregion - -#region Example "tomorrow" -//<x:cfRule type="timePeriod" dxfId="31" priority="2" timePeriod="tomorrow"> -// <x:formula>FLOOR(A1,1)=TODAY()+1</x:formula> -//</x:cfRule> -#endregion - -#region Example "yesterday" -//<x:cfRule type="timePeriod" dxfId="1" priority="1" timePeriod="yesterday"> -// <x:formula>FLOOR(A1,1)=TODAY()-1</x:formula> -//</x:cfRule> -#endregion - -#region Example "twoColorScale" -//<cfRule type="colorScale" priority="1"> -// <colorScale> -// <cfvo type="min"/> -// <cfvo type="max"/> -// <color rgb="FFF8696B"/> -// <color rgb="FF63BE7B"/> -// </colorScale> -//</cfRule> -#endregion - -#region Examples "iconSet3" (x all the 3 IconSet options) -//<x:cfRule type="iconSet" priority="30"> -// <x:iconSet> -// <x:cfvo type="percent" val="0" /> -// <x:cfvo type="percent" val="33" /> -// <x:cfvo type="percent" val="67" /> -// </x:iconSet> -//</x:cfRule> - -//<x:cfRule type="iconSet" priority="38"> -// <x:iconSet iconSet="3Arrows"> -// <x:cfvo type="percent" val="0" /> -// <x:cfvo type="percent" val="33" /> -// <x:cfvo type="percent" val="67" /> -// </x:iconSet> -//</x:cfRule> -#endregion - -#region Examples "iconSet4" (x all the 4 IconSet options) -//<x:cfRule type="iconSet" priority="34"> -// <x:iconSet iconSet="4ArrowsGray"> -// <x:cfvo type="percent" val="0" /> -// <x:cfvo type="percent" val="25" /> -// <x:cfvo type="percent" val="50" /> -// <x:cfvo type="percent" val="75" /> -// </x:iconSet> -//</x:cfRule> -#endregion - -#region Examples "iconSet5" (x all the 5 IconSet options) -//<x:cfRule type="iconSet" priority="32"> -// <x:iconSet iconSet="5ArrowsGray"> -// <x:cfvo type="percent" val="0" /> -// <x:cfvo type="percent" val="20" /> -// <x:cfvo type="percent" val="40" /> -// <x:cfvo type="percent" val="60" /> -// <x:cfvo type="percent" val="80" /> -// </x:iconSet> -//</x:cfRule> -#endregion - -#region Examples "iconSet" Extended (not implemented yet) -//<x:extLst> -// <x:ext xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main" uri="{78C0D931-6437-407d-A8EE-F0AAD7539E65}"> -// <x14:conditionalFormattings> -// <x14:conditionalFormatting xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"> -// <x14:cfRule type="iconSet" priority="35" id="{F5114369-080A-47E6-B7EE-499137A3C896}"> -// <x14:iconSet iconSet="3Triangles"> -// <x14:cfvo type="percent"> -// <xm:f>0</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>33</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>67</xm:f> -// </x14:cfvo> -// </x14:iconSet> -// </x14:cfRule> -// <xm:sqref>C3:C12</xm:sqref> -// </x14:conditionalFormatting> -// <x14:conditionalFormatting xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"> -// <x14:cfRule type="iconSet" priority="6" id="{0A327384-BF2F-4BF5-9767-123CD690A536}"> -// <x14:iconSet iconSet="3Stars"> -// <x14:cfvo type="percent"> -// <xm:f>0</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>33</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>67</xm:f> -// </x14:cfvo> -// </x14:iconSet> -// </x14:cfRule> -// <xm:sqref>A16:A25</xm:sqref> -// </x14:conditionalFormatting> -// <x14:conditionalFormatting xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"> -// <x14:cfRule type="iconSet" priority="19" id="{0DDCA3E4-3536-44B3-A663-4877587295B8}"> -// <x14:iconSet iconSet="3Triangles"> -// <x14:cfvo type="percent"> -// <xm:f>0</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>33</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>67</xm:f> -// </x14:cfvo> -// </x14:iconSet> -// </x14:cfRule> -// <xm:sqref>C16:C25</xm:sqref> -// </x14:conditionalFormatting> -// <x14:conditionalFormatting xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"> -// <x14:cfRule type="iconSet" priority="2" id="{E4EDD7FB-880C-408F-B87C-C8DA446AEB78}"> -// <x14:iconSet iconSet="5Boxes"> -// <x14:cfvo type="percent"> -// <xm:f>0</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>20</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>40</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>60</xm:f> -// </x14:cfvo> -// <x14:cfvo type="percent"> -// <xm:f>80</xm:f> -// </x14:cfvo> -// </x14:iconSet> -// </x14:cfRule> -// <xm:sqref>E16:E25</xm:sqref> -// </x14:conditionalFormatting> -// <x14:conditionalFormatting xmlns:xm="http://schemas.microsoft.com/office/excel/2006/main"> -// <x14:cfRule type="iconSet" priority="1" id="{4CC82060-CB0A-4A31-AEF2-D1A587AC1674}"> -// <x14:iconSet iconSet="3Stars" showValue="0" custom="1"> -// <x14:cfvo type="percent"> -// <xm:f>0</xm:f> -// </x14:cfvo> -// <x14:cfvo type="formula"> -// <xm:f>$F$17</xm:f> -// </x14:cfvo> -// <x14:cfvo type="num"> -// <xm:f>4</xm:f> -// </x14:cfvo> -// <x14:cfIcon iconSet="3Triangles" iconId="1" /> -// <x14:cfIcon iconSet="4RedToBlack" iconId="3" /> -// <x14:cfIcon iconSet="3Stars" iconId="2" /> -// </x14:iconSet> -// </x14:cfRule> -// <xm:sqref>F16:F25</xm:sqref> -// </x14:conditionalFormatting> -// </x14:conditionalFormattings> -// </x:ext> -//</x:extLst> -#endregion - - -#endregion \ No newline at end of file
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs index da5bc83..77efc3f 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingAverageGroup.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingAverageGroup - /// </summary> - public interface IExcelConditionalFormattingAverageGroup - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} +/// <summary> +/// IExcelConditionalFormattingAverageGroup +/// </summary> +public interface IExcelConditionalFormattingAverageGroup : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs index 91bc11b..8bc7c8f 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBeginsWith.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingBeginsWith - /// </summary> - public interface IExcelConditionalFormattingBeginsWith +/// <summary> +/// IExcelConditionalFormattingBeginsWith +/// </summary> +public interface IExcelConditionalFormattingBeginsWith : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithText - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs index 86895a8..6d56a9e 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingBetween.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingBetween - /// </summary> - public interface IExcelConditionalFormattingBetween +/// <summary> +/// IExcelConditionalFormattingBetween +/// </summary> +public interface IExcelConditionalFormattingBetween : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula2 - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula2 {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs index 4276211..8f33fc0 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingColorScaleGroup.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingColorScaleGroup - /// </summary> - public interface IExcelConditionalFormattingColorScaleGroup - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingColorScaleGroup +/// </summary> +public interface IExcelConditionalFormattingColorScaleGroup : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs index 7381e32..4d05109 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsBlanks.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingContainsBlanks - /// </summary> - public interface IExcelConditionalFormattingContainsBlanks - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingContainsBlanks +/// </summary> +public interface IExcelConditionalFormattingContainsBlanks : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs index 37fe317..a668e11 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsErrors.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingContainsErrors - /// </summary> - public interface IExcelConditionalFormattingContainsErrors - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingContainsErrors +/// </summary> +public interface IExcelConditionalFormattingContainsErrors : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs index 069b9c8..5919f90 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingContainsText.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingContainsText - /// </summary> - public interface IExcelConditionalFormattingContainsText +/// <summary> +/// IExcelConditionalFormattingContainsText +/// </summary> +public interface IExcelConditionalFormattingContainsText : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithText - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs index 31b9002..99a44a1 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDataBarGroup.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,55 +13,47 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; using System.Drawing; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingDataBar - /// </summary> - public interface IExcelConditionalFormattingDataBarGroup - : IExcelConditionalFormattingRule - { - #region Public Properties - /// <summary> - /// ShowValue - /// </summary> - bool ShowValue { get; set; } - /// <summary> - /// Databar Low Value - /// </summary> - ExcelConditionalFormattingIconDataBarValue LowValue { get; } +namespace OfficeOpenXml.ConditionalFormatting.Contracts; - /// <summary> - /// Databar High Value - /// </summary> - ExcelConditionalFormattingIconDataBarValue HighValue { get; } - /// <summary> - /// The color of the databar - /// </summary> - Color Color { get; set;} - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingDataBar +/// </summary> +public interface IExcelConditionalFormattingDataBarGroup : IExcelConditionalFormattingRule { + /// <summary> + /// ShowValue + /// </summary> + bool ShowValue { get; set; } + + /// <summary> + /// Databar Low Value + /// </summary> + ExcelConditionalFormattingIconDataBarValue LowValue { get; } + + /// <summary> + /// Databar High Value + /// </summary> + ExcelConditionalFormattingIconDataBarValue HighValue { get; } + + /// <summary> + /// The color of the databar + /// </summary> + Color Color { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs index 768be37..32427f9 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingDuplicateValues.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingDuplicateValues - /// </summary> - public interface IExcelConditionalFormattingDuplicateValues - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingDuplicateValues +/// </summary> +public interface IExcelConditionalFormattingDuplicateValues : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs index 07f58d1..d45c296 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEndsWith.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingEndsWith - /// </summary> - public interface IExcelConditionalFormattingEndsWith +/// <summary> +/// IExcelConditionalFormattingEndsWith +/// </summary> +public interface IExcelConditionalFormattingEndsWith : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithText - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs index 16bce16..91c9663 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingEqual - /// </summary> - public interface IExcelConditionalFormattingEqual +/// <summary> +/// IExcelConditionalFormattingEqual +/// </summary> +public interface IExcelConditionalFormattingEqual : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs index 340db52..aa23a69 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingExpression.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingExpression - /// </summary> - public interface IExcelConditionalFormattingExpression +/// <summary> +/// IExcelConditionalFormattingExpression +/// </summary> +public interface IExcelConditionalFormattingExpression : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs index e81d499..2954b3e 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFiveIconSet.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingFiveIconSet +/// </summary>eExcelconditionalFormatting4IconsSetType +public interface IExcelConditionalFormattingFiveIconSet + : IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting5IconsSetType> { /// <summary> - /// IExcelConditionalFormattingFiveIconSet - /// </summary>eExcelconditionalFormatting4IconsSetType - public interface IExcelConditionalFormattingFiveIconSet : IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting5IconsSetType> - { - #region Public Properties - /// <summary> - /// Icon5 (part of the 5 Icon Set) - /// </summary> - ExcelConditionalFormattingIconDataBarValue Icon5 { get; } - #endregion Public Properties - } -} \ No newline at end of file + /// Icon5 (part of the 5 Icon Set) + /// </summary> + ExcelConditionalFormattingIconDataBarValue Icon5 { get; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs index 496ad61..67da2ba 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingFourIconSet.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingFourIconSet +/// </summary> +public interface IExcelConditionalFormattingFourIconSet<T> + : IExcelConditionalFormattingThreeIconSet<T> { /// <summary> - /// IExcelConditionalFormattingFourIconSet + /// Icon4 (part of the 4 ou 5 Icon Set) /// </summary> - public interface IExcelConditionalFormattingFourIconSet<T> : IExcelConditionalFormattingThreeIconSet<T> - { - #region Public Properties - /// <summary> - /// Icon4 (part of the 4 ou 5 Icon Set) - /// </summary> - ExcelConditionalFormattingIconDataBarValue Icon4 { get; } - #endregion Public Properties - } + ExcelConditionalFormattingIconDataBarValue Icon4 { get; } }
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs index 7d739fa..9287f3f 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThan.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingGreaterThan - /// </summary> - public interface IExcelConditionalFormattingGreaterThan +/// <summary> +/// IExcelConditionalFormattingGreaterThan +/// </summary> +public interface IExcelConditionalFormattingGreaterThan : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs index 1c3e193..aa084cc 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingGreaterThanOrEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingGreaterThanOrEqual - /// </summary> - public interface IExcelConditionalFormattingGreaterThanOrEqual +/// <summary> +/// IExcelConditionalFormattingGreaterThanOrEqual +/// </summary> +public interface IExcelConditionalFormattingGreaterThanOrEqual : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs index 78e8d7c..700ffd6 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingIconSetGroup.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,51 +13,40 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingIconSetGroup - /// </summary> - public interface IExcelConditionalFormattingIconSetGroup<T> - : IExcelConditionalFormattingRule - { - #region Public Properties - /// <summary> - /// Reverse - /// </summary> - bool Reverse { get; set; } +/// <summary> +/// IExcelConditionalFormattingIconSetGroup +/// </summary> +public interface IExcelConditionalFormattingIconSetGroup<T> : IExcelConditionalFormattingRule { + /// <summary> + /// Reverse + /// </summary> + bool Reverse { get; set; } - /// <summary> - /// ShowValue - /// </summary> - bool ShowValue { get; set; } + /// <summary> + /// ShowValue + /// </summary> + bool ShowValue { get; set; } - /// <summary> - /// IconSet (3, 4 ou 5 IconSet) - /// </summary> - T IconSet { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + /// <summary> + /// IconSet (3, 4 ou 5 IconSet) + /// </summary> + T IconSet { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs index 59e25a5..162a16c 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThan.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingLessThan - /// </summary> - public interface IExcelConditionalFormattingLessThan +/// <summary> +/// IExcelConditionalFormattingLessThan +/// </summary> +public interface IExcelConditionalFormattingLessThan : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs index c9a8a2a..fce6064 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingLessThanOrEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingGreaterThanOrEqual - /// </summary> - public interface IExcelConditionalFormattingLessThanOrEqual +/// <summary> +/// IExcelConditionalFormattingGreaterThanOrEqual +/// </summary> +public interface IExcelConditionalFormattingLessThanOrEqual : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs index 49835dd..a017b81 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotBetween.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingNotBetween - /// </summary> - public interface IExcelConditionalFormattingNotBetween +/// <summary> +/// IExcelConditionalFormattingNotBetween +/// </summary> +public interface IExcelConditionalFormattingNotBetween : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula2 - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula2 {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs index 0152916..4743b3b 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsBlanks.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingNotContainsBlanks - /// </summary> - public interface IExcelConditionalFormattingNotContainsBlanks - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingNotContainsBlanks +/// </summary> +public interface IExcelConditionalFormattingNotContainsBlanks : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs index bd7cfee..aa42a1c 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsErrors.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingNotContainsErrors - /// </summary> - public interface IExcelConditionalFormattingNotContainsErrors - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingNotContainsErrors +/// </summary> +public interface IExcelConditionalFormattingNotContainsErrors : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs index 9cbcb4a..5a427f4 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotContainsText.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingNotContainsText - /// </summary> - public interface IExcelConditionalFormattingNotContainsText +/// <summary> +/// IExcelConditionalFormattingNotContainsText +/// </summary> +public interface IExcelConditionalFormattingNotContainsText : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithText - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithText {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs index 17f7c3b..f20f33a 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingNotEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingNotEqual - /// </summary> - public interface IExcelConditionalFormattingNotEqual +/// <summary> +/// IExcelConditionalFormattingNotEqual +/// </summary> +public interface IExcelConditionalFormattingNotEqual : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithFormula - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithFormula {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs index cdb899a..e88b5af 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingRule.cs
@@ -13,75 +13,70 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using System.Xml; using OfficeOpenXml.Style.Dxf; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// Interface for conditional formatting rule - /// </summary> - public interface IExcelConditionalFormattingRule - { - /// <summary> - /// The 'cfRule' XML node - /// </summary> - XmlNode Node { get; } +namespace OfficeOpenXml.ConditionalFormatting.Contracts; - /// <summary> - /// Type of conditional formatting rule. ST_CfType §18.18.12. - /// </summary> - eExcelConditionalFormattingRuleType Type { get; } +/// <summary> +/// Interface for conditional formatting rule +/// </summary> +public interface IExcelConditionalFormattingRule { + /// <summary> + /// The 'cfRule' XML node + /// </summary> + XmlNode Node { get; } - /// <summary> - /// <para>Range over which these conditional formatting rules apply.</para> - /// <para>The possible values for this attribute are defined by the - /// ST_Sqref simple type (§18.18.76).</para> - /// </summary> - ExcelAddress Address { get; set; } + /// <summary> + /// Type of conditional formatting rule. ST_CfType §18.18.12. + /// </summary> + eExcelConditionalFormattingRuleType Type { get; } - /// <summary> - /// The priority of this conditional formatting rule. This value is used to determine - /// which format should be evaluated and rendered. Lower numeric values are higher - /// priority than higher numeric values, where 1 is the highest priority. - /// </summary> - int Priority { get; set; } + /// <summary> + /// <para>Range over which these conditional formatting rules apply.</para> + /// <para>The possible values for this attribute are defined by the + /// ST_Sqref simple type (§18.18.76).</para> + /// </summary> + ExcelAddress Address { get; set; } - /// <summary> - /// If this flag is 1, no rules with lower priority shall be applied over this rule, - /// when this rule evaluates to true. - /// </summary> - bool StopIfTrue { get; set; } + /// <summary> + /// The priority of this conditional formatting rule. This value is used to determine + /// which format should be evaluated and rendered. Lower numeric values are higher + /// priority than higher numeric values, where 1 is the highest priority. + /// </summary> + int Priority { get; set; } - ///// <summary> - ///// <para>This is an index to a dxf element in the Styles Part indicating which cell - ///// formatting to apply when the conditional formatting rule criteria is met.</para> - ///// <para>The possible values for this attribute are defined by the ST_DxfId simple type - ///// (§18.18.25).</para> - ///// </summary> -// int DxfId { get; set; } - /// <summary> - /// Gives access to the differencial styling (DXF) for the rule. - /// </summary> - ExcelDxfStyleConditionalFormatting Style{ get; } - } -} \ No newline at end of file + /// <summary> + /// If this flag is 1, no rules with lower priority shall be applied over this rule, + /// when this rule evaluates to true. + /// </summary> + bool StopIfTrue { get; set; } + + ///// <summary> + ///// <para>This is an index to a dxf element in the Styles Part indicating which cell + ///// formatting to apply when the conditional formatting rule criteria is met.</para> + ///// <para>The possible values for this attribute are defined by the ST_DxfId simple type + ///// (§18.18.25).</para> + ///// </summary> + // int DxfId { get; set; } + /// <summary> + /// Gives access to the differencial styling (DXF) for the rule. + /// </summary> + ExcelDxfStyleConditionalFormatting Style { get; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs index 6bd768f..1aca982 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingStdDevGroup.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingStdDevGroup - /// </summary> - public interface IExcelConditionalFormattingStdDevGroup +/// <summary> +/// IExcelConditionalFormattingStdDevGroup +/// </summary> +public interface IExcelConditionalFormattingStdDevGroup : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithStdDev - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithStdDev {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs index ed2f11f..eca66d1 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeColorScale.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,41 +13,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingThreeColorScale - /// </summary> - public interface IExcelConditionalFormattingThreeColorScale - : IExcelConditionalFormattingTwoColorScale - { - #region Public Properties - /// <summary> - /// Three Color Scale Middle Value - /// </summary> - ExcelConditionalFormattingColorScaleValue MiddleValue { get; set; } - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingThreeColorScale +/// </summary> +public interface IExcelConditionalFormattingThreeColorScale + : IExcelConditionalFormattingTwoColorScale { + /// <summary> + /// Three Color Scale Middle Value + /// </summary> + ExcelConditionalFormattingColorScaleValue MiddleValue { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs index 3921eb2..0fdc397 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingThreeIconSet.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,51 +13,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingThreeIconSet - /// </summary> - public interface IExcelConditionalFormattingThreeIconSet<T> - : IExcelConditionalFormattingIconSetGroup<T> - { - #region Public Properties - /// <summary> - /// Icon1 (part of the 3, 4 ou 5 Icon Set) - /// </summary> - ExcelConditionalFormattingIconDataBarValue Icon1 { get; } +/// <summary> +/// IExcelConditionalFormattingThreeIconSet +/// </summary> +public interface IExcelConditionalFormattingThreeIconSet<T> + : IExcelConditionalFormattingIconSetGroup<T> { + /// <summary> + /// Icon1 (part of the 3, 4 ou 5 Icon Set) + /// </summary> + ExcelConditionalFormattingIconDataBarValue Icon1 { get; } - /// <summary> - /// Icon2 (part of the 3, 4 ou 5 Icon Set) - /// </summary> - ExcelConditionalFormattingIconDataBarValue Icon2 { get; } + /// <summary> + /// Icon2 (part of the 3, 4 ou 5 Icon Set) + /// </summary> + ExcelConditionalFormattingIconDataBarValue Icon2 { get; } - /// <summary> - /// Icon3 (part of the 3, 4 ou 5 Icon Set) - /// </summary> - ExcelConditionalFormattingIconDataBarValue Icon3 { get; } - #endregion Public Properties - } -} \ No newline at end of file + /// <summary> + /// Icon3 (part of the 3, 4 ou 5 Icon Set) + /// </summary> + ExcelConditionalFormattingIconDataBarValue Icon3 { get; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs index ddde55e..266c1b8 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTimePeriodGroup.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingTimePeriod - /// </summary> - public interface IExcelConditionalFormattingTimePeriodGroup - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} +/// <summary> +/// IExcelConditionalFormattingTimePeriod +/// </summary> +public interface IExcelConditionalFormattingTimePeriodGroup : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs index 24f8283..234d925 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTopBottomGroup.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingTopBottomGroup - /// </summary> - public interface IExcelConditionalFormattingTopBottomGroup +/// <summary> +/// IExcelConditionalFormattingTopBottomGroup +/// </summary> +public interface IExcelConditionalFormattingTopBottomGroup : IExcelConditionalFormattingRule, - IExcelConditionalFormattingWithRank - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file + IExcelConditionalFormattingWithRank {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs index 936ed0d..2662b9a 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingTwoColorScale.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,46 +13,36 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingTwoColorScale - /// </summary> - public interface IExcelConditionalFormattingTwoColorScale - : IExcelConditionalFormattingColorScaleGroup - { - #region Public Properties - /// <summary> - /// Two Color Scale Low Value - /// </summary> - ExcelConditionalFormattingColorScaleValue LowValue { get; set; } +/// <summary> +/// IExcelConditionalFormattingTwoColorScale +/// </summary> +public interface IExcelConditionalFormattingTwoColorScale + : IExcelConditionalFormattingColorScaleGroup { + /// <summary> + /// Two Color Scale Low Value + /// </summary> + ExcelConditionalFormattingColorScaleValue LowValue { get; set; } - /// <summary> - /// Two Color Scale High Value - /// </summary> - ExcelConditionalFormattingColorScaleValue HighValue { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + /// <summary> + /// Two Color Scale High Value + /// </summary> + ExcelConditionalFormattingColorScaleValue HighValue { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs index e5aa021..ee55553 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingUniqueValues.cs
@@ -13,37 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ - /// <summary> - /// IExcelConditionalFormattingUniqueValues - /// </summary> - public interface IExcelConditionalFormattingUniqueValues - : IExcelConditionalFormattingRule - { - #region Public Properties - #endregion Public Properties - } -} \ No newline at end of file +/// <summary> +/// IExcelConditionalFormattingUniqueValues +/// </summary> +public interface IExcelConditionalFormattingUniqueValues : IExcelConditionalFormattingRule {}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs index d5d0fa1..d612008 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingWithFormula +/// </summary> +public interface IExcelConditionalFormattingWithFormula { /// <summary> - /// IExcelConditionalFormattingWithFormula + /// Formula Attribute /// </summary> - public interface IExcelConditionalFormattingWithFormula - { - #region Public Properties - /// <summary> - /// Formula Attribute - /// </summary> - string Formula { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + string Formula { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs index 7b4e70e..b7a940a 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithFormula2.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,41 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingWithFormula2 +/// </summary> +public interface IExcelConditionalFormattingWithFormula2 : IExcelConditionalFormattingWithFormula { /// <summary> - /// IExcelConditionalFormattingWithFormula2 + /// Formula2 Attribute /// </summary> - public interface IExcelConditionalFormattingWithFormula2 - : IExcelConditionalFormattingWithFormula - { - #region Public Properties - /// <summary> - /// Formula2 Attribute - /// </summary> - string Formula2 { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + string Formula2 { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs index f5b0f92..de220ed 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithRank.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,32 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingWithRank +/// </summary> +public interface IExcelConditionalFormattingWithRank { /// <summary> - /// IExcelConditionalFormattingWithRank + /// Rank Attribute /// </summary> - public interface IExcelConditionalFormattingWithRank - { - #region Public Properties - /// <summary> - /// Rank Attribute - /// </summary> - UInt16 Rank { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + UInt16 Rank { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs index a710354..405a8a5 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithReverse.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingWithReverse +/// </summary> +public interface IExcelConditionalFormattingWithReverse { /// <summary> - /// IExcelConditionalFormattingWithReverse + /// Reverse Attribute /// </summary> - public interface IExcelConditionalFormattingWithReverse - { - #region Public Properties - /// <summary> - /// Reverse Attribute - /// </summary> - bool Reverse { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + bool Reverse { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs index c12dbeb..479627b 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithShowValue.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingWithShowValue +/// </summary> +public interface IExcelConditionalFormattingWithShowValue { /// <summary> - /// IExcelConditionalFormattingWithShowValue + /// ShowValue Attribute /// </summary> - public interface IExcelConditionalFormattingWithShowValue - { - #region Public Properties - /// <summary> - /// ShowValue Attribute - /// </summary> - bool ShowValue { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + bool ShowValue { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs index 96ae1c6..d3cf330 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithStdDev.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,32 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingWithStdDev +/// </summary> +public interface IExcelConditionalFormattingWithStdDev { /// <summary> - /// IExcelConditionalFormattingWithStdDev + /// StdDev Attribute /// </summary> - public interface IExcelConditionalFormattingWithStdDev - { - #region Public Properties - /// <summary> - /// StdDev Attribute - /// </summary> - UInt16 StdDev { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + UInt16 StdDev { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs index 4602ac4..bfe91a4 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IExcelConditionalFormattingWithText.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,40 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.ConditionalFormatting; +namespace OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting.Contracts -{ +/// <summary> +/// IExcelConditionalFormattingWithText +/// </summary> +public interface IExcelConditionalFormattingWithText { /// <summary> - /// IExcelConditionalFormattingWithText + /// Text Attribute /// </summary> - public interface IExcelConditionalFormattingWithText - { - #region Public Properties - /// <summary> - /// Text Attribute - /// </summary> - string Text { get; set; } - #endregion Public Properties - } -} \ No newline at end of file + string Text { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs b/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs index 6b4f85a..b2d99bf 100644 --- a/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs +++ b/EPPlus/ConditionalFormatting/Contracts/IRangeConditionalFormatting.cs
@@ -13,301 +13,306 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting 2012-04-03 *******************************************************************************/ -using OfficeOpenXml.ConditionalFormatting.Contracts; + using System.Drawing; +using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// Provides functionality for adding Conditional Formatting to a range (<see cref="ExcelRangeBase"/>). - /// Each method will return a configurable condtional formatting type. - /// </summary> - public interface IRangeConditionalFormatting - { - /// <summary> - /// Adds a Above Average rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingAverageGroup AddAboveAverage(); +namespace OfficeOpenXml.ConditionalFormatting; - /// <summary> - /// Adds a Above Or Equal Average rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage(); +/// <summary> +/// Provides functionality for adding Conditional Formatting to a range (<see cref="ExcelRangeBase"/>). +/// Each method will return a configurable condtional formatting type. +/// </summary> +public interface IRangeConditionalFormatting { + /// <summary> + /// Adds a Above Average rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingAverageGroup AddAboveAverage(); - /// <summary> - /// Adds a Below Average rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingAverageGroup AddBelowAverage(); + /// <summary> + /// Adds a Above Or Equal Average rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage(); - /// <summary> - /// Adds a Below Or Equal Average rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage(); + /// <summary> + /// Adds a Below Average rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingAverageGroup AddBelowAverage(); - /// <summary> - /// Adds a Above StdDev rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingStdDevGroup AddAboveStdDev(); + /// <summary> + /// Adds a Below Or Equal Average rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage(); - /// <summary> - /// Adds a Below StdDev rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingStdDevGroup AddBelowStdDev(); + /// <summary> + /// Adds a Above StdDev rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingStdDevGroup AddAboveStdDev(); - /// <summary> - /// Adds a Bottom rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTopBottomGroup AddBottom(); + /// <summary> + /// Adds a Below StdDev rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingStdDevGroup AddBelowStdDev(); - /// <summary> - /// Adds a Bottom Percent rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTopBottomGroup AddBottomPercent(); + /// <summary> + /// Adds a Bottom rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTopBottomGroup AddBottom(); - /// <summary> - /// Adds a Top rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTopBottomGroup AddTop(); + /// <summary> + /// Adds a Bottom Percent rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTopBottomGroup AddBottomPercent(); - /// <summary> - /// Adds a Top Percent rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTopBottomGroup AddTopPercent(); + /// <summary> + /// Adds a Top rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTopBottomGroup AddTop(); - /// <summary> - /// Adds a Last 7 Days rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddLast7Days(); + /// <summary> + /// Adds a Top Percent rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTopBottomGroup AddTopPercent(); - /// <summary> - /// Adds a Last Month rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddLastMonth(); + /// <summary> + /// Adds a Last 7 Days rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddLast7Days(); - /// <summary> - /// Adds a Last Week rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddLastWeek(); + /// <summary> + /// Adds a Last Month rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddLastMonth(); - /// <summary> - /// Adds a Next Month rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddNextMonth(); + /// <summary> + /// Adds a Last Week rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddLastWeek(); - /// <summary> - /// Adds a Next Week rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddNextWeek(); + /// <summary> + /// Adds a Next Month rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddNextMonth(); - /// <summary> - /// Adds a This Month rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddThisMonth(); + /// <summary> + /// Adds a Next Week rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddNextWeek(); - /// <summary> - /// Adds a This Week rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddThisWeek(); + /// <summary> + /// Adds a This Month rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddThisMonth(); - /// <summary> - /// Adds a Today rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddToday(); + /// <summary> + /// Adds a This Week rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddThisWeek(); - /// <summary> - /// Adds a Tomorrow rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddTomorrow(); + /// <summary> + /// Adds a Today rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddToday(); - /// <summary> - /// Adds a Yesterday rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTimePeriodGroup AddYesterday(); + /// <summary> + /// Adds a Tomorrow rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddTomorrow(); - /// <summary> - /// Adds a Begins With rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingBeginsWith AddBeginsWith(); + /// <summary> + /// Adds a Yesterday rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTimePeriodGroup AddYesterday(); - /// <summary> - /// Adds a Between rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingBetween AddBetween(); + /// <summary> + /// Adds a Begins With rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingBeginsWith AddBeginsWith(); - /// <summary> - /// Adds a ContainsBlanks rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingContainsBlanks AddContainsBlanks(); + /// <summary> + /// Adds a Between rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingBetween AddBetween(); - /// <summary> - /// Adds a ContainsErrors rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingContainsErrors AddContainsErrors(); + /// <summary> + /// Adds a ContainsBlanks rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingContainsBlanks AddContainsBlanks(); - /// <summary> - /// Adds a ContainsText rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingContainsText AddContainsText(); + /// <summary> + /// Adds a ContainsErrors rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingContainsErrors AddContainsErrors(); - /// <summary> - /// Adds a DuplicateValues rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingDuplicateValues AddDuplicateValues(); + /// <summary> + /// Adds a ContainsText rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingContainsText AddContainsText(); - /// <summary> - /// Adds a EndsWith rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingEndsWith AddEndsWith(); + /// <summary> + /// Adds a DuplicateValues rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingDuplicateValues AddDuplicateValues(); - /// <summary> - /// Adds a Equal rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingEqual AddEqual(); + /// <summary> + /// Adds a EndsWith rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingEndsWith AddEndsWith(); - /// <summary> - /// Adds a Expression rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingExpression AddExpression(); + /// <summary> + /// Adds a Equal rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingEqual AddEqual(); - /// <summary> - /// Adds a GreaterThan rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingGreaterThan AddGreaterThan(); + /// <summary> + /// Adds a Expression rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingExpression AddExpression(); - /// <summary> - /// Adds a GreaterThanOrEqual rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual(); + /// <summary> + /// Adds a GreaterThan rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingGreaterThan AddGreaterThan(); - /// <summary> - /// Adds a LessThan rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingLessThan AddLessThan(); + /// <summary> + /// Adds a GreaterThanOrEqual rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual(); - /// <summary> - /// Adds a LessThanOrEqual rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual(); + /// <summary> + /// Adds a LessThan rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingLessThan AddLessThan(); - /// <summary> - /// Adds a NotBetween rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingNotBetween AddNotBetween(); + /// <summary> + /// Adds a LessThanOrEqual rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual(); - /// <summary> - /// Adds a NotContainsBlanks rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks(); + /// <summary> + /// Adds a NotBetween rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingNotBetween AddNotBetween(); - /// <summary> - /// Adds a NotContainsErrors rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors(); + /// <summary> + /// Adds a NotContainsBlanks rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks(); - /// <summary> - /// Adds a NotContainsText rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingNotContainsText AddNotContainsText(); + /// <summary> + /// Adds a NotContainsErrors rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors(); - /// <summary> - /// Adds a NotEqual rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingNotEqual AddNotEqual(); + /// <summary> + /// Adds a NotContainsText rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingNotContainsText AddNotContainsText(); - /// <summary> - /// Adds a UniqueValues rule to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingUniqueValues AddUniqueValues(); + /// <summary> + /// Adds a NotEqual rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingNotEqual AddNotEqual(); - /// <summary> - /// Adds a <see cref="ExcelConditionalFormattingThreeColorScale"/> to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingThreeColorScale AddThreeColorScale(); + /// <summary> + /// Adds a UniqueValues rule to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingUniqueValues AddUniqueValues(); - /// <summary> - /// Adds a <see cref="ExcelConditionalFormattingTwoColorScale"/> to the range - /// </summary> - /// <returns></returns> - IExcelConditionalFormattingTwoColorScale AddTwoColorScale(); + /// <summary> + /// Adds a <see cref="ExcelConditionalFormattingThreeColorScale"/> to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingThreeColorScale AddThreeColorScale(); - /// <summary> - /// Adds a <see cref="IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>"/> to the range - /// </summary> - /// <param name="IconSet"></param> - /// <returns></returns> - IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet(eExcelconditionalFormatting3IconsSetType IconSet); - /// <summary> - /// Adds a <see cref="IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>"/> to the range - /// </summary> - /// <param name="IconSet"></param> - /// <returns></returns> - IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet(eExcelconditionalFormatting4IconsSetType IconSet); - /// <summary> - /// Adds a <see cref="IExcelConditionalFormattingFiveIconSet"/> to the range - /// </summary> - /// <param name="IconSet"></param> - /// <returns></returns> - IExcelConditionalFormattingFiveIconSet AddFiveIconSet(eExcelconditionalFormatting5IconsSetType IconSet); - /// <summary> - /// Adds a <see cref="IExcelConditionalFormattingDataBarGroup"/> to the range - /// </summary> - /// <param name="color"></param> - /// <returns></returns> - IExcelConditionalFormattingDataBarGroup AddDatabar(Color color); - } -} \ No newline at end of file + /// <summary> + /// Adds a <see cref="ExcelConditionalFormattingTwoColorScale"/> to the range + /// </summary> + /// <returns></returns> + IExcelConditionalFormattingTwoColorScale AddTwoColorScale(); + + /// <summary> + /// Adds a <see cref="IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>"/> to the range + /// </summary> + /// <param name="iconSet"></param> + /// <returns></returns> + IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet( + eExcelconditionalFormatting3IconsSetType iconSet); + + /// <summary> + /// Adds a <see cref="IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>"/> to the range + /// </summary> + /// <param name="iconSet"></param> + /// <returns></returns> + IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet( + eExcelconditionalFormatting4IconsSetType iconSet); + + /// <summary> + /// Adds a <see cref="IExcelConditionalFormattingFiveIconSet"/> to the range + /// </summary> + /// <param name="iconSet"></param> + /// <returns></returns> + IExcelConditionalFormattingFiveIconSet AddFiveIconSet( + eExcelconditionalFormatting5IconsSetType iconSet); + + /// <summary> + /// Adds a <see cref="IExcelConditionalFormattingDataBarGroup"/> to the range + /// </summary> + /// <param name="color"></param> + /// <returns></returns> + IExcelConditionalFormattingDataBarGroup AddDatabar(Color color); +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs index 969bcd1..4fe42f4 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,987 +13,857 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Collections; -using OfficeOpenXml.Utils; +using System.Collections.Generic; +using System.Drawing; using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -using System.Text.RegularExpressions; -using System.Drawing; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// Collection of <see cref="ExcelConditionalFormattingRule"/>. - /// This class is providing the API for EPPlus conditional formatting. - /// </summary> - /// <remarks> - /// <para> - /// The public methods of this class (Add[...]ConditionalFormatting) will create a ConditionalFormatting/CfRule entry in the worksheet. When this - /// Conditional Formatting has been created changes to the properties will affect the workbook immediately. - /// </para> - /// <para> - /// Each type of Conditional Formatting Rule has diferente set of properties. - /// </para> - /// <code> - /// // Add a Three Color Scale conditional formatting - /// var cf = worksheet.ConditionalFormatting.AddThreeColorScale(new ExcelAddress("A1:C10")); - /// // Set the conditional formatting properties - /// cf.LowValue.Type = ExcelConditionalFormattingValueObjectType.Min; - /// cf.LowValue.Color = Color.White; - /// cf.MiddleValue.Type = ExcelConditionalFormattingValueObjectType.Percent; - /// cf.MiddleValue.Value = 50; - /// cf.MiddleValue.Color = Color.Blue; - /// cf.HighValue.Type = ExcelConditionalFormattingValueObjectType.Max; - /// cf.HighValue.Color = Color.Black; - /// </code> - /// </remarks> - public class ExcelConditionalFormattingCollection +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// Collection of <see cref="ExcelConditionalFormattingRule"/>. +/// This class is providing the API for EPPlus conditional formatting. +/// </summary> +/// <remarks> +/// <para> +/// The public methods of this class (Add[...]ConditionalFormatting) will create a ConditionalFormatting/CfRule entry in the worksheet. When this +/// Conditional Formatting has been created changes to the properties will affect the workbook immediately. +/// </para> +/// <para> +/// Each type of Conditional Formatting Rule has diferente set of properties. +/// </para> +/// <code> +/// // Add a Three Color Scale conditional formatting +/// var cf = worksheet.ConditionalFormatting.AddThreeColorScale(new ExcelAddress("A1:C10")); +/// // Set the conditional formatting properties +/// cf.LowValue.Type = ExcelConditionalFormattingValueObjectType.Min; +/// cf.LowValue.Color = Color.White; +/// cf.MiddleValue.Type = ExcelConditionalFormattingValueObjectType.Percent; +/// cf.MiddleValue.Value = 50; +/// cf.MiddleValue.Color = Color.Blue; +/// cf.HighValue.Type = ExcelConditionalFormattingValueObjectType.Max; +/// cf.HighValue.Color = Color.Black; +/// </code> +/// </remarks> +public class ExcelConditionalFormattingCollection : XmlHelper, - IEnumerable<IExcelConditionalFormattingRule> - { - /****************************************************************************************/ + IEnumerable<IExcelConditionalFormattingRule> { + /****************************************************************************************/ - #region Private Properties - private List<IExcelConditionalFormattingRule> _rules = new List<IExcelConditionalFormattingRule>(); - private ExcelWorksheet _worksheet = null; - #endregion Private Properties - /****************************************************************************************/ + private List<IExcelConditionalFormattingRule> _rules = new(); + private ExcelWorksheet _worksheet; - #region Constructors - /// <summary> - /// Initialize the <see cref="ExcelConditionalFormattingCollection"/> - /// </summary> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingCollection( - ExcelWorksheet worksheet) - : base( - worksheet.NameSpaceManager, - worksheet.WorksheetXml.DocumentElement) - { - Require.Argument(worksheet).IsNotNull("worksheet"); + /****************************************************************************************/ - _worksheet = worksheet; - SchemaNodeOrder = _worksheet.SchemaNodeOrder; - // Look for all the <conditionalFormatting> - var conditionalFormattingNodes = TopNode.SelectNodes( - "//" + ExcelConditionalFormattingConstants.Paths.ConditionalFormatting, + /// <summary> + /// Initialize the <see cref="ExcelConditionalFormattingCollection"/> + /// </summary> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingCollection(ExcelWorksheet worksheet) + : base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) { + Require.Argument(worksheet).IsNotNull("worksheet"); + + _worksheet = worksheet; + SchemaNodeOrder = _worksheet.SchemaNodeOrder; + + // Look for all the <conditionalFormatting> + var conditionalFormattingNodes = TopNode.SelectNodes( + "//" + ExcelConditionalFormattingConstants.Paths._conditionalFormatting, _worksheet.NameSpaceManager); - // Check if we found at least 1 node - if ((conditionalFormattingNodes != null) - && (conditionalFormattingNodes.Count > 0)) - { - // Foreach <conditionalFormatting> - foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) - { - // Check if @sqref attribute exists - if (conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Sqref] == null) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingSqrefAttribute); - } + // Check if we found at least 1 node + if ((conditionalFormattingNodes != null) && (conditionalFormattingNodes.Count > 0)) { + // Foreach <conditionalFormatting> + foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) { + // Check if @sqref attribute exists + if (conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants + .Attributes + ._sqref] == null) { + throw new(ExcelConditionalFormattingConstants.Errors._missingSqrefAttribute); + } - // Get the @sqref attribute - ExcelAddress address = new ExcelAddress( - conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Sqref].Value); + // Get the @sqref attribute + ExcelAddress address = new ExcelAddress( + conditionalFormattingNode.Attributes[ExcelConditionalFormattingConstants + .Attributes + ._sqref].Value); - // Check for all the <cfRules> nodes and load them - var cfRuleNodes = conditionalFormattingNode.SelectNodes( - ExcelConditionalFormattingConstants.Paths.CfRule, + // Check for all the <cfRules> nodes and load them + var cfRuleNodes = conditionalFormattingNode.SelectNodes( + ExcelConditionalFormattingConstants.Paths._cfRule, _worksheet.NameSpaceManager); - // Foreach <cfRule> inside the current <conditionalFormatting> - foreach (XmlNode cfRuleNode in cfRuleNodes) - { - // Check if @type attribute exists - if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Type] == null) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingTypeAttribute); - } + // Foreach <cfRule> inside the current <conditionalFormatting> + foreach (XmlNode cfRuleNode in cfRuleNodes) { + // Check if @type attribute exists + if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes._type] == null) { + throw new(ExcelConditionalFormattingConstants.Errors._missingTypeAttribute); + } - // Check if @priority attribute exists - if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Priority] == null) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingPriorityAttribute); - } + // Check if @priority attribute exists + if (cfRuleNode.Attributes[ExcelConditionalFormattingConstants.Attributes._priority] + == null) { + throw new(ExcelConditionalFormattingConstants.Errors._missingPriorityAttribute); + } - // Get the <cfRule> main attributes - string typeAttribute = ExcelConditionalFormattingHelper.GetAttributeString( + // Get the <cfRule> main attributes + string typeAttribute = ExcelConditionalFormattingHelper.GetAttributeString( cfRuleNode, - ExcelConditionalFormattingConstants.Attributes.Type); + ExcelConditionalFormattingConstants.Attributes._type); - int priority = ExcelConditionalFormattingHelper.GetAttributeInt( + int priority = ExcelConditionalFormattingHelper.GetAttributeInt( cfRuleNode, - ExcelConditionalFormattingConstants.Attributes.Priority); + ExcelConditionalFormattingConstants.Attributes._priority); - // Transform the @type attribute to EPPlus Rule Type (slighty diferente) - var type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute( + // Transform the @type attribute to EPPlus Rule Type (slighty diferente) + var type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute( typeAttribute, cfRuleNode, _worksheet.NameSpaceManager); - // Create the Rule according to the correct type, address and priority - var cfRule = ExcelConditionalFormattingRuleFactory.Create( + // Create the Rule according to the correct type, address and priority + var cfRule = ExcelConditionalFormattingRuleFactory.Create( type, address, priority, _worksheet, cfRuleNode); - // Add the new rule to the list - if(cfRule!=null) - _rules.Add(cfRule); + // Add the new rule to the list + if (cfRule != null) { + _rules.Add(cfRule); } } } } - #endregion Constructors + } - /****************************************************************************************/ + /****************************************************************************************/ - #region Methods - /// <summary> - /// - /// </summary> - private void EnsureRootElementExists() - { - // Find the <worksheet> node - if (_worksheet.WorksheetXml.DocumentElement == null) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingWorksheetNode); + + /// <summary> + /// + /// </summary> + private void EnsureRootElementExists() { + // Find the <worksheet> node + if (_worksheet.WorksheetXml.DocumentElement == null) { + throw new(ExcelConditionalFormattingConstants.Errors._missingWorksheetNode); + } + } + + /// <summary> + /// GetRootNode + /// </summary> + /// <returns></returns> + private XmlNode GetRootNode() { + EnsureRootElementExists(); + return _worksheet.WorksheetXml.DocumentElement; + } + + /// <summary> + /// Validates address - not empty (collisions are allowded) + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + private ExcelAddress ValidateAddress(ExcelAddress address) { + Require.Argument(address).IsNotNull("address"); + + //TODO: Are there any other validation we need to do? + return address; + } + + /// <summary> + /// Get the next priority sequencial number + /// </summary> + /// <returns></returns> + private int GetNextPriority() { + // Consider zero as the last priority when we have no CF rules + int lastPriority = 0; + + // Search for the last priority + foreach (var cfRule in _rules) { + if (cfRule.Priority > lastPriority) { + lastPriority = cfRule.Priority; } } - /// <summary> - /// GetRootNode - /// </summary> - /// <returns></returns> - private XmlNode GetRootNode() - { - EnsureRootElementExists(); - return _worksheet.WorksheetXml.DocumentElement; - } + // Our next priority is the last plus one + return lastPriority + 1; + } - /// <summary> - /// Validates address - not empty (collisions are allowded) - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - private ExcelAddress ValidateAddress( - ExcelAddress address) - { - Require.Argument(address).IsNotNull("address"); + /****************************************************************************************/ - //TODO: Are there any other validation we need to do? - return address; - } - /// <summary> - /// Get the next priority sequencial number - /// </summary> - /// <returns></returns> - private int GetNextPriority() - { - // Consider zero as the last priority when we have no CF rules - int lastPriority = 0; + /// <summary> + /// Number of validations + /// </summary> + public int Count => _rules.Count; - // Search for the last priority - foreach (var cfRule in _rules) - { - if (cfRule.Priority > lastPriority) - { - lastPriority = cfRule.Priority; - } - } + /// <summary> + /// Index operator, returns by 0-based index + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public IExcelConditionalFormattingRule this[int index] { + get => _rules[index]; + set => _rules[index] = value; + } - // Our next priority is the last plus one - return lastPriority + 1; - } - #endregion Methods + /// <summary> + /// Get the 'cfRule' enumerator + /// </summary> + /// <returns></returns> + IEnumerator<IExcelConditionalFormattingRule> IEnumerable<IExcelConditionalFormattingRule>.GetEnumerator() { + return _rules.GetEnumerator(); + } - /****************************************************************************************/ + /// <summary> + /// Get the 'cfRule' enumerator + /// </summary> + /// <returns></returns> + IEnumerator IEnumerable.GetEnumerator() { + return _rules.GetEnumerator(); + } - #region IEnumerable<IExcelConditionalFormatting> - /// <summary> - /// Number of validations - /// </summary> - public int Count - { - get { return _rules.Count; } - } - - /// <summary> - /// Index operator, returns by 0-based index - /// </summary> - /// <param name="index"></param> - /// <returns></returns> - public IExcelConditionalFormattingRule this[int index] - { - get { return _rules[index]; } - set { _rules[index] = value; } - } - - /// <summary> - /// Get the 'cfRule' enumerator - /// </summary> - /// <returns></returns> - IEnumerator<IExcelConditionalFormattingRule> IEnumerable<IExcelConditionalFormattingRule>.GetEnumerator() - { - return _rules.GetEnumerator(); - } - - /// <summary> - /// Get the 'cfRule' enumerator - /// </summary> - /// <returns></returns> - IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _rules.GetEnumerator(); - } - - /// <summary> - /// Removes all 'cfRule' from the collection and from the XML. - /// <remarks> - /// This is the same as removing all the 'conditionalFormatting' nodes. - /// </remarks> - /// </summary> - public void RemoveAll() - { - // Look for all the <conditionalFormatting> nodes - var conditionalFormattingNodes = TopNode.SelectNodes( - "//" + ExcelConditionalFormattingConstants.Paths.ConditionalFormatting, + /// <summary> + /// Removes all 'cfRule' from the collection and from the XML. + /// <remarks> + /// This is the same as removing all the 'conditionalFormatting' nodes. + /// </remarks> + /// </summary> + public void RemoveAll() { + // Look for all the <conditionalFormatting> nodes + var conditionalFormattingNodes = TopNode.SelectNodes( + "//" + ExcelConditionalFormattingConstants.Paths._conditionalFormatting, _worksheet.NameSpaceManager); - // Remove all the <conditionalFormatting> nodes one by one - foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) - { - conditionalFormattingNode.ParentNode.RemoveChild(conditionalFormattingNode); - } - - // Clear the <cfRule> item list - _rules.Clear(); + // Remove all the <conditionalFormatting> nodes one by one + foreach (XmlNode conditionalFormattingNode in conditionalFormattingNodes) { + conditionalFormattingNode.ParentNode.RemoveChild(conditionalFormattingNode); } - /// <summary> - /// Remove a Conditional Formatting Rule by its object - /// </summary> - /// <param name="item"></param> - public void Remove( - IExcelConditionalFormattingRule item) - { - Require.Argument(item).IsNotNull("item"); + // Clear the <cfRule> item list + _rules.Clear(); + } - try - { - // Point to the parent node - var oldParentNode = item.Node.ParentNode; + /// <summary> + /// Remove a Conditional Formatting Rule by its object + /// </summary> + /// <param name="item"></param> + public void Remove(IExcelConditionalFormattingRule item) { + Require.Argument(item).IsNotNull("item"); - // Remove the <cfRule> from the old <conditionalFormatting> parent node - oldParentNode.RemoveChild(item.Node); + try { + // Point to the parent node + var oldParentNode = item.Node.ParentNode; - // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it - if (!oldParentNode.HasChildNodes) - { - // Remove the old parent node - oldParentNode.ParentNode.RemoveChild(oldParentNode); - } + // Remove the <cfRule> from the old <conditionalFormatting> parent node + oldParentNode.RemoveChild(item.Node); - _rules.Remove(item); + // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it + if (!oldParentNode.HasChildNodes) { + // Remove the old parent node + oldParentNode.ParentNode.RemoveChild(oldParentNode); } - catch - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.InvalidRemoveRuleOperation); - } + + _rules.Remove(item); + } catch { + throw new(ExcelConditionalFormattingConstants.Errors._invalidRemoveRuleOperation); } + } - /// <summary> - /// Remove a Conditional Formatting Rule by its 0-based index - /// </summary> - /// <param name="index"></param> - public void RemoveAt( - int index) - { - Require.Argument(index).IsInRange(0, this.Count - 1, "index"); + /// <summary> + /// Remove a Conditional Formatting Rule by its 0-based index + /// </summary> + /// <param name="index"></param> + public void RemoveAt(int index) { + Require.Argument(index).IsInRange(0, Count - 1, "index"); - Remove(this[index]); - } + Remove(this[index]); + } - /// <summary> - /// Remove a Conditional Formatting Rule by its priority - /// </summary> - /// <param name="priority"></param> - public void RemoveByPriority( - int priority) - { - try - { - Remove(RulesByPriority(priority)); - } - catch - { - } - } + /// <summary> + /// Remove a Conditional Formatting Rule by its priority + /// </summary> + /// <param name="priority"></param> + public void RemoveByPriority(int priority) { + try { + Remove(RulesByPriority(priority)); + } catch {} + } - /// <summary> - /// Get a rule by its priority - /// </summary> - /// <param name="priority"></param> - /// <returns></returns> - public IExcelConditionalFormattingRule RulesByPriority( - int priority) - { - return _rules.Find(x => x.Priority == priority); - } - #endregion IEnumerable<IExcelConditionalFormatting> + /// <summary> + /// Get a rule by its priority + /// </summary> + /// <param name="priority"></param> + /// <returns></returns> + public IExcelConditionalFormattingRule RulesByPriority(int priority) { + return _rules.Find(x => x.Priority == priority); + } - /****************************************************************************************/ + /****************************************************************************************/ - #region Conditional Formatting Rules - /// <summary> - /// Add rule (internal) - /// </summary> - /// <param name="type"></param> - /// <param name="address"></param> - /// <returns></returns>F - internal IExcelConditionalFormattingRule AddRule( + + /// <summary> + /// Add rule (internal) + /// </summary> + /// <param name="type"></param> + /// <param name="address"></param> + /// <returns></returns>F + internal IExcelConditionalFormattingRule AddRule( eExcelConditionalFormattingRuleType type, - ExcelAddress address) - { - Require.Argument(address).IsNotNull("address"); + ExcelAddress address) { + Require.Argument(address).IsNotNull("address"); - address = ValidateAddress(address); - EnsureRootElementExists(); + address = ValidateAddress(address); + EnsureRootElementExists(); - // Create the Rule according to the correct type, address and priority - IExcelConditionalFormattingRule cfRule = ExcelConditionalFormattingRuleFactory.Create( + // Create the Rule according to the correct type, address and priority + IExcelConditionalFormattingRule cfRule = ExcelConditionalFormattingRuleFactory.Create( type, address, GetNextPriority(), _worksheet, null); - // Add the newly created rule to the list - _rules.Add(cfRule); + // Add the newly created rule to the list + _rules.Add(cfRule); - // Return the newly created rule - return cfRule; - } + // Return the newly created rule + return cfRule; + } - /// <summary> - /// Add AboveAverage Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddAboveAverage( - ExcelAddress address) - { - return (IExcelConditionalFormattingAverageGroup)AddRule( + /// <summary> + /// Add AboveAverage Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddAboveAverage(ExcelAddress address) { + return (IExcelConditionalFormattingAverageGroup)AddRule( eExcelConditionalFormattingRuleType.AboveAverage, address); - } + } - /// <summary> - /// Add AboveOrEqualAverage Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage( - ExcelAddress address) - { - return (IExcelConditionalFormattingAverageGroup)AddRule( + /// <summary> + /// Add AboveOrEqualAverage Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage(ExcelAddress address) { + return (IExcelConditionalFormattingAverageGroup)AddRule( eExcelConditionalFormattingRuleType.AboveOrEqualAverage, address); - } + } - /// <summary> - /// Add BelowAverage Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddBelowAverage( - ExcelAddress address) - { - return (IExcelConditionalFormattingAverageGroup)AddRule( + /// <summary> + /// Add BelowAverage Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddBelowAverage(ExcelAddress address) { + return (IExcelConditionalFormattingAverageGroup)AddRule( eExcelConditionalFormattingRuleType.BelowAverage, address); - } + } - /// <summary> - /// Add BelowOrEqualAverage Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage( - ExcelAddress address) - { - return (IExcelConditionalFormattingAverageGroup)AddRule( + /// <summary> + /// Add BelowOrEqualAverage Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage(ExcelAddress address) { + return (IExcelConditionalFormattingAverageGroup)AddRule( eExcelConditionalFormattingRuleType.BelowOrEqualAverage, address); - } + } - /// <summary> - /// Add AboveStdDev Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingStdDevGroup AddAboveStdDev( - ExcelAddress address) - { - return (IExcelConditionalFormattingStdDevGroup)AddRule( + /// <summary> + /// Add AboveStdDev Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingStdDevGroup AddAboveStdDev(ExcelAddress address) { + return (IExcelConditionalFormattingStdDevGroup)AddRule( eExcelConditionalFormattingRuleType.AboveStdDev, address); - } + } - /// <summary> - /// Add BelowStdDev Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingStdDevGroup AddBelowStdDev( - ExcelAddress address) - { - return (IExcelConditionalFormattingStdDevGroup)AddRule( + /// <summary> + /// Add BelowStdDev Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingStdDevGroup AddBelowStdDev(ExcelAddress address) { + return (IExcelConditionalFormattingStdDevGroup)AddRule( eExcelConditionalFormattingRuleType.BelowStdDev, address); - } + } - /// <summary> - /// Add Bottom Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddBottom( - ExcelAddress address) - { - return (IExcelConditionalFormattingTopBottomGroup)AddRule( + /// <summary> + /// Add Bottom Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddBottom(ExcelAddress address) { + return (IExcelConditionalFormattingTopBottomGroup)AddRule( eExcelConditionalFormattingRuleType.Bottom, address); - } + } - /// <summary> - /// Add BottomPercent Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddBottomPercent( - ExcelAddress address) - { - return (IExcelConditionalFormattingTopBottomGroup)AddRule( + /// <summary> + /// Add BottomPercent Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddBottomPercent(ExcelAddress address) { + return (IExcelConditionalFormattingTopBottomGroup)AddRule( eExcelConditionalFormattingRuleType.BottomPercent, address); - } + } - /// <summary> - /// Add Top Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddTop( - ExcelAddress address) - { - return (IExcelConditionalFormattingTopBottomGroup)AddRule( + /// <summary> + /// Add Top Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddTop(ExcelAddress address) { + return (IExcelConditionalFormattingTopBottomGroup)AddRule( eExcelConditionalFormattingRuleType.Top, address); - } + } - /// <summary> - /// Add TopPercent Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddTopPercent( - ExcelAddress address) - { - return (IExcelConditionalFormattingTopBottomGroup)AddRule( + /// <summary> + /// Add TopPercent Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddTopPercent(ExcelAddress address) { + return (IExcelConditionalFormattingTopBottomGroup)AddRule( eExcelConditionalFormattingRuleType.TopPercent, address); - } + } - /// <summary> - /// Add Last7Days Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddLast7Days( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add Last7Days Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddLast7Days(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.Last7Days, address); - } + } - /// <summary> - /// Add LastMonth Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddLastMonth( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add LastMonth Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddLastMonth(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.LastMonth, address); - } + } - /// <summary> - /// Add LastWeek Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddLastWeek( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add LastWeek Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddLastWeek(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.LastWeek, address); - } + } - /// <summary> - /// Add NextMonth Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddNextMonth( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add NextMonth Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddNextMonth(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.NextMonth, address); - } + } - /// <summary> - /// Add NextWeek Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddNextWeek( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add NextWeek Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddNextWeek(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.NextWeek, address); - } + } - /// <summary> - /// Add ThisMonth Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddThisMonth( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add ThisMonth Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddThisMonth(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.ThisMonth, address); - } + } - /// <summary> - /// Add ThisWeek Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddThisWeek( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add ThisWeek Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddThisWeek(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.ThisWeek, address); - } + } - /// <summary> - /// Add Today Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddToday( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add Today Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddToday(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.Today, address); - } + } - /// <summary> - /// Add Tomorrow Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddTomorrow( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add Tomorrow Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddTomorrow(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.Tomorrow, address); - } + } - /// <summary> - /// Add Yesterday Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddYesterday( - ExcelAddress address) - { - return (IExcelConditionalFormattingTimePeriodGroup)AddRule( + /// <summary> + /// Add Yesterday Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddYesterday(ExcelAddress address) { + return (IExcelConditionalFormattingTimePeriodGroup)AddRule( eExcelConditionalFormattingRuleType.Yesterday, address); - } + } - /// <summary> - /// Add BeginsWith Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingBeginsWith AddBeginsWith( - ExcelAddress address) - { - return (IExcelConditionalFormattingBeginsWith)AddRule( + /// <summary> + /// Add BeginsWith Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingBeginsWith AddBeginsWith(ExcelAddress address) { + return (IExcelConditionalFormattingBeginsWith)AddRule( eExcelConditionalFormattingRuleType.BeginsWith, address); - } + } - /// <summary> - /// Add Between Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingBetween AddBetween( - ExcelAddress address) - { - return (IExcelConditionalFormattingBetween)AddRule( + /// <summary> + /// Add Between Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingBetween AddBetween(ExcelAddress address) { + return (IExcelConditionalFormattingBetween)AddRule( eExcelConditionalFormattingRuleType.Between, address); - } + } - /// <summary> - /// Add ContainsBlanks Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingContainsBlanks AddContainsBlanks( - ExcelAddress address) - { - return (IExcelConditionalFormattingContainsBlanks)AddRule( + /// <summary> + /// Add ContainsBlanks Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingContainsBlanks AddContainsBlanks(ExcelAddress address) { + return (IExcelConditionalFormattingContainsBlanks)AddRule( eExcelConditionalFormattingRuleType.ContainsBlanks, address); - } + } - /// <summary> - /// Add ContainsErrors Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingContainsErrors AddContainsErrors( - ExcelAddress address) - { - return (IExcelConditionalFormattingContainsErrors)AddRule( + /// <summary> + /// Add ContainsErrors Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingContainsErrors AddContainsErrors(ExcelAddress address) { + return (IExcelConditionalFormattingContainsErrors)AddRule( eExcelConditionalFormattingRuleType.ContainsErrors, address); - } + } - /// <summary> - /// Add ContainsText Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingContainsText AddContainsText( - ExcelAddress address) - { - return (IExcelConditionalFormattingContainsText)AddRule( + /// <summary> + /// Add ContainsText Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingContainsText AddContainsText(ExcelAddress address) { + return (IExcelConditionalFormattingContainsText)AddRule( eExcelConditionalFormattingRuleType.ContainsText, address); - } + } - /// <summary> - /// Add DuplicateValues Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingDuplicateValues AddDuplicateValues( - ExcelAddress address) - { - return (IExcelConditionalFormattingDuplicateValues)AddRule( + /// <summary> + /// Add DuplicateValues Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingDuplicateValues AddDuplicateValues(ExcelAddress address) { + return (IExcelConditionalFormattingDuplicateValues)AddRule( eExcelConditionalFormattingRuleType.DuplicateValues, address); - } + } - /// <summary> - /// Add EndsWith Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingEndsWith AddEndsWith( - ExcelAddress address) - { - return (IExcelConditionalFormattingEndsWith)AddRule( + /// <summary> + /// Add EndsWith Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingEndsWith AddEndsWith(ExcelAddress address) { + return (IExcelConditionalFormattingEndsWith)AddRule( eExcelConditionalFormattingRuleType.EndsWith, address); - } + } - /// <summary> - /// Add Equal Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingEqual AddEqual( - ExcelAddress address) - { - return (IExcelConditionalFormattingEqual)AddRule( + /// <summary> + /// Add Equal Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingEqual AddEqual(ExcelAddress address) { + return (IExcelConditionalFormattingEqual)AddRule( eExcelConditionalFormattingRuleType.Equal, address); - } + } - /// <summary> - /// Add Expression Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingExpression AddExpression( - ExcelAddress address) - { - return (IExcelConditionalFormattingExpression)AddRule( + /// <summary> + /// Add Expression Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingExpression AddExpression(ExcelAddress address) { + return (IExcelConditionalFormattingExpression)AddRule( eExcelConditionalFormattingRuleType.Expression, address); - } + } - /// <summary> - /// Add GreaterThan Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingGreaterThan AddGreaterThan( - ExcelAddress address) - { - return (IExcelConditionalFormattingGreaterThan)AddRule( + /// <summary> + /// Add GreaterThan Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingGreaterThan AddGreaterThan(ExcelAddress address) { + return (IExcelConditionalFormattingGreaterThan)AddRule( eExcelConditionalFormattingRuleType.GreaterThan, address); - } + } - /// <summary> - /// Add GreaterThanOrEqual Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual( - ExcelAddress address) - { - return (IExcelConditionalFormattingGreaterThanOrEqual)AddRule( + /// <summary> + /// Add GreaterThanOrEqual Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual(ExcelAddress address) { + return (IExcelConditionalFormattingGreaterThanOrEqual)AddRule( eExcelConditionalFormattingRuleType.GreaterThanOrEqual, address); - } + } - /// <summary> - /// Add LessThan Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingLessThan AddLessThan( - ExcelAddress address) - { - return (IExcelConditionalFormattingLessThan)AddRule( + /// <summary> + /// Add LessThan Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingLessThan AddLessThan(ExcelAddress address) { + return (IExcelConditionalFormattingLessThan)AddRule( eExcelConditionalFormattingRuleType.LessThan, address); - } + } - /// <summary> - /// Add LessThanOrEqual Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual( - ExcelAddress address) - { - return (IExcelConditionalFormattingLessThanOrEqual)AddRule( + /// <summary> + /// Add LessThanOrEqual Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual(ExcelAddress address) { + return (IExcelConditionalFormattingLessThanOrEqual)AddRule( eExcelConditionalFormattingRuleType.LessThanOrEqual, address); - } + } - /// <summary> - /// Add NotBetween Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingNotBetween AddNotBetween( - ExcelAddress address) - { - return (IExcelConditionalFormattingNotBetween)AddRule( + /// <summary> + /// Add NotBetween Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingNotBetween AddNotBetween(ExcelAddress address) { + return (IExcelConditionalFormattingNotBetween)AddRule( eExcelConditionalFormattingRuleType.NotBetween, address); - } + } - /// <summary> - /// Add NotContainsBlanks Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks( - ExcelAddress address) - { - return (IExcelConditionalFormattingNotContainsBlanks)AddRule( + /// <summary> + /// Add NotContainsBlanks Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks(ExcelAddress address) { + return (IExcelConditionalFormattingNotContainsBlanks)AddRule( eExcelConditionalFormattingRuleType.NotContainsBlanks, address); - } + } - /// <summary> - /// Add NotContainsErrors Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors( - ExcelAddress address) - { - return (IExcelConditionalFormattingNotContainsErrors)AddRule( + /// <summary> + /// Add NotContainsErrors Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors(ExcelAddress address) { + return (IExcelConditionalFormattingNotContainsErrors)AddRule( eExcelConditionalFormattingRuleType.NotContainsErrors, address); - } + } - /// <summary> - /// Add NotContainsText Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingNotContainsText AddNotContainsText( - ExcelAddress address) - { - return (IExcelConditionalFormattingNotContainsText)AddRule( + /// <summary> + /// Add NotContainsText Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingNotContainsText AddNotContainsText(ExcelAddress address) { + return (IExcelConditionalFormattingNotContainsText)AddRule( eExcelConditionalFormattingRuleType.NotContainsText, address); - } + } - /// <summary> - /// Add NotEqual Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingNotEqual AddNotEqual( - ExcelAddress address) - { - return (IExcelConditionalFormattingNotEqual)AddRule( + /// <summary> + /// Add NotEqual Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingNotEqual AddNotEqual(ExcelAddress address) { + return (IExcelConditionalFormattingNotEqual)AddRule( eExcelConditionalFormattingRuleType.NotEqual, address); - } + } - /// <summary> - /// Add Unique Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingUniqueValues AddUniqueValues( - ExcelAddress address) - { - return (IExcelConditionalFormattingUniqueValues)AddRule( + /// <summary> + /// Add Unique Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingUniqueValues AddUniqueValues(ExcelAddress address) { + return (IExcelConditionalFormattingUniqueValues)AddRule( eExcelConditionalFormattingRuleType.UniqueValues, address); - } + } - /// <summary> - /// Add ThreeColorScale Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingThreeColorScale AddThreeColorScale( - ExcelAddress address) - { - return (IExcelConditionalFormattingThreeColorScale)AddRule( + /// <summary> + /// Add ThreeColorScale Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingThreeColorScale AddThreeColorScale(ExcelAddress address) { + return (IExcelConditionalFormattingThreeColorScale)AddRule( eExcelConditionalFormattingRuleType.ThreeColorScale, address); - } + } - /// <summary> - /// Add TwoColorScale Rule - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public IExcelConditionalFormattingTwoColorScale AddTwoColorScale( - ExcelAddress address) - { - return (IExcelConditionalFormattingTwoColorScale)AddRule( + /// <summary> + /// Add TwoColorScale Rule + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public IExcelConditionalFormattingTwoColorScale AddTwoColorScale(ExcelAddress address) { + return (IExcelConditionalFormattingTwoColorScale)AddRule( eExcelConditionalFormattingRuleType.TwoColorScale, address); - } - - /// <summary> - /// Add ThreeIconSet Rule - /// </summary> - /// <param name="Address">The address</param> - /// <param name="IconSet">Type of iconset</param> - /// <returns></returns> - public IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet(ExcelAddress Address, eExcelconditionalFormatting3IconsSetType IconSet) - { - var icon = (IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>)AddRule( - eExcelConditionalFormattingRuleType.ThreeIconSet, - Address); - icon.IconSet = IconSet; - return icon; - } - /// <summary> - /// Adds a FourIconSet rule - /// </summary> - /// <param name="Address"></param> - /// <param name="IconSet"></param> - /// <returns></returns> - public IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet(ExcelAddress Address, eExcelconditionalFormatting4IconsSetType IconSet) - { - var icon = (IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>)AddRule( - eExcelConditionalFormattingRuleType.FourIconSet, - Address); - icon.IconSet = IconSet; - return icon; - } - /// <summary> - /// Adds a FiveIconSet rule - /// </summary> - /// <param name="Address"></param> - /// <param name="IconSet"></param> - /// <returns></returns> - public IExcelConditionalFormattingFiveIconSet AddFiveIconSet(ExcelAddress Address, eExcelconditionalFormatting5IconsSetType IconSet) - { - var icon = (IExcelConditionalFormattingFiveIconSet)AddRule( - eExcelConditionalFormattingRuleType.FiveIconSet, - Address); - icon.IconSet = IconSet; - return icon; - } - /// <summary> - /// Adds a databar rule - /// </summary> - /// <param name="Address"></param> - /// <param name="color"></param> - /// <returns></returns> - public IExcelConditionalFormattingDataBarGroup AddDatabar(ExcelAddress Address, Color color) - { - var dataBar = (IExcelConditionalFormattingDataBarGroup)AddRule( - eExcelConditionalFormattingRuleType.DataBar, - Address); - dataBar.Color=color; - return dataBar; - } - #endregion Conditional Formatting Rules - } -} \ No newline at end of file + + /// <summary> + /// Add ThreeIconSet Rule + /// </summary> + /// <param name="address">The address</param> + /// <param name="iconSet">Type of iconset</param> + /// <returns></returns> + public IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet( + ExcelAddress address, + eExcelconditionalFormatting3IconsSetType iconSet) { + var icon = + (IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>) + AddRule(eExcelConditionalFormattingRuleType.ThreeIconSet, address); + icon.IconSet = iconSet; + return icon; + } + + /// <summary> + /// Adds a FourIconSet rule + /// </summary> + /// <param name="address"></param> + /// <param name="iconSet"></param> + /// <returns></returns> + public IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet( + ExcelAddress address, + eExcelconditionalFormatting4IconsSetType iconSet) { + var icon = + (IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>) + AddRule(eExcelConditionalFormattingRuleType.FourIconSet, address); + icon.IconSet = iconSet; + return icon; + } + + /// <summary> + /// Adds a FiveIconSet rule + /// </summary> + /// <param name="address"></param> + /// <param name="iconSet"></param> + /// <returns></returns> + public IExcelConditionalFormattingFiveIconSet AddFiveIconSet( + ExcelAddress address, + eExcelconditionalFormatting5IconsSetType iconSet) { + var icon = (IExcelConditionalFormattingFiveIconSet)AddRule( + eExcelConditionalFormattingRuleType.FiveIconSet, + address); + icon.IconSet = iconSet; + return icon; + } + + /// <summary> + /// Adds a databar rule + /// </summary> + /// <param name="address"></param> + /// <param name="color"></param> + /// <returns></returns> + public IExcelConditionalFormattingDataBarGroup AddDatabar(ExcelAddress address, Color color) { + var dataBar = (IExcelConditionalFormattingDataBarGroup)AddRule( + eExcelConditionalFormattingRuleType.DataBar, + address); + dataBar.Color = color; + return dataBar; + } +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs index ac1cdaf..3331b3e 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingColorScaleValue.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,499 +13,443 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Drawing; using System.Xml; using OfficeOpenXml.Utils; -using System.Text.RegularExpressions; -using System.Globalization; -using System.Security; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// 18.3.1.11 cfvo (Conditional Format Value Object) - /// Describes the values of the interpolation points in a gradient scale. - /// </summary> - public class ExcelConditionalFormattingColorScaleValue - : XmlHelper - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Private Properties - private eExcelConditionalFormattingValueObjectPosition _position; - private eExcelConditionalFormattingRuleType _ruleType; - private ExcelWorksheet _worksheet; - #endregion Private Properties +/// <summary> +/// 18.3.1.11 cfvo (Conditional Format Value Object) +/// Describes the values of the interpolation points in a gradient scale. +/// </summary> +public class ExcelConditionalFormattingColorScaleValue : XmlHelper { + /****************************************************************************************/ - /****************************************************************************************/ - #region Constructors - /// <summary> - /// Initialize the cfvo (§18.3.1.11) node - /// </summary> - /// <param name="position"></param> - /// <param name="type"></param> - /// <param name="color"></param> - /// <param name="value"></param> - /// <param name="formula"></param> - /// <param name="ruleType"></param> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following: - /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingColorScaleValue( - eExcelConditionalFormattingValueObjectPosition position, - eExcelConditionalFormattingValueObjectType type, - Color color, - double value, - string formula, - eExcelConditionalFormattingRuleType ruleType, + private eExcelConditionalFormattingValueObjectPosition _position; + private eExcelConditionalFormattingRuleType _ruleType; + private ExcelWorksheet _worksheet; + + /****************************************************************************************/ + + + /// <summary> + /// Initialize the cfvo (§18.3.1.11) node + /// </summary> + /// <param name="position"></param> + /// <param name="type"></param> + /// <param name="color"></param> + /// <param name="value"></param> + /// <param name="formula"></param> + /// <param name="ruleType"></param> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following: + /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingColorScaleValue( + eExcelConditionalFormattingValueObjectPosition position, + eExcelConditionalFormattingValueObjectType type, + Color color, + double value, + string formula, + eExcelConditionalFormattingRuleType ruleType, ExcelAddress address, int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode, - XmlNamespaceManager namespaceManager) - : base( - namespaceManager, - itemElementNode) - { - Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); - Require.Argument(address).IsNotNull("address"); - Require.Argument(worksheet).IsNotNull("worksheet"); + ExcelWorksheet worksheet, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(namespaceManager, itemElementNode) { + Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); + Require.Argument(address).IsNotNull("address"); + Require.Argument(worksheet).IsNotNull("worksheet"); - // Save the worksheet for private methods to use - _worksheet = worksheet; + // Save the worksheet for private methods to use + _worksheet = worksheet; - // Schema order list - SchemaNodeOrder = new string[] - { - ExcelConditionalFormattingConstants.Nodes.Cfvo, - ExcelConditionalFormattingConstants.Nodes.Color - }; + // Schema order list + SchemaNodeOrder = new[] { + ExcelConditionalFormattingConstants.Nodes._cfvo, + ExcelConditionalFormattingConstants.Nodes._color, + }; - // Check if the parent does not exists - if (itemElementNode == null) - { - // Get the parent node path by the rule type - string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType( - ruleType); + // Check if the parent does not exists + if (itemElementNode == null) { + // Get the parent node path by the rule type + string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType( + ruleType); - // Check for en error (rule type does not have <cfvo>) - if (parentNodePath == string.Empty) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode); - } + // Check for en error (rule type does not have <cfvo>) + if (parentNodePath == string.Empty) { + throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode); + } - // Point to the <cfvo> parent node - itemElementNode = _worksheet.WorksheetXml.SelectSingleNode( - string.Format( - "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}", - // {0} - ExcelConditionalFormattingConstants.Paths.ConditionalFormatting, - // {1} - ExcelConditionalFormattingConstants.Paths.SqrefAttribute, - // {2} - address.Address, - // {3} - ExcelConditionalFormattingConstants.Paths.CfRule, - // {4} - ExcelConditionalFormattingConstants.Paths.PriorityAttribute, - // {5} - priority, - // {6} - parentNodePath), - _worksheet.NameSpaceManager); + // Point to the <cfvo> parent node + itemElementNode = _worksheet.WorksheetXml.SelectSingleNode( + string.Format( + "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}", + // {0} + ExcelConditionalFormattingConstants.Paths._conditionalFormatting, + // {1} + ExcelConditionalFormattingConstants.Paths._sqrefAttribute, + // {2} + address.Address, + // {3} + ExcelConditionalFormattingConstants.Paths._cfRule, + // {4} + ExcelConditionalFormattingConstants.Paths._priorityAttribute, + // {5} + priority, + // {6} + parentNodePath), + _worksheet.NameSpaceManager); - // Check for en error (rule type does not have <cfvo>) - if (itemElementNode == null) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode); - } - } + // Check for en error (rule type does not have <cfvo>) + if (itemElementNode == null) { + throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode); + } + } - // Point to the <cfvo> parent node (<colorScale>, <dataBar> or <iconSet>) - // This is different than normal, as TopNode does not point to the node itself but to - // its PARENT. Later, in the CreateNodeByOrdem method the TopNode will be updated. - TopNode = itemElementNode; + // Point to the <cfvo> parent node (<colorScale>, <dataBar> or <iconSet>) + // This is different than normal, as TopNode does not point to the node itself but to + // its PARENT. Later, in the CreateNodeByOrdem method the TopNode will be updated. + TopNode = itemElementNode; - // Save the attributes - Position = position; - RuleType = ruleType; - Type = type; - Color = color; - Value = value; - Formula = formula; - } + // Save the attributes + Position = position; + RuleType = ruleType; + Type = type; + Color = color; + Value = value; + Formula = formula; + } - /// <summary> - /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> - /// </summary> - /// <param name="position"></param> - /// <param name="type"></param> - /// <param name="color"></param> - /// <param name="value"></param> - /// <param name="formula"></param> - /// <param name="ruleType"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingColorScaleValue( - eExcelConditionalFormattingValueObjectPosition position, - eExcelConditionalFormattingValueObjectType type, - Color color, - double value, - string formula, - eExcelConditionalFormattingRuleType ruleType, + /// <summary> + /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> + /// </summary> + /// <param name="position"></param> + /// <param name="type"></param> + /// <param name="color"></param> + /// <param name="value"></param> + /// <param name="formula"></param> + /// <param name="ruleType"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingColorScaleValue( + eExcelConditionalFormattingValueObjectPosition position, + eExcelConditionalFormattingValueObjectType type, + Color color, + double value, + string formula, + eExcelConditionalFormattingRuleType ruleType, ExcelAddress address, int priority, - ExcelWorksheet worksheet, - XmlNamespaceManager namespaceManager) - : this( - position, - type, - color, - value, - formula, - ruleType, - address, - priority, - worksheet, - null, - namespaceManager) - { - } + ExcelWorksheet worksheet, + XmlNamespaceManager namespaceManager) + : this( + position, + type, + color, + value, + formula, + ruleType, + address, + priority, + worksheet, + null, + namespaceManager) {} - /// <summary> - /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> - /// </summary> - /// <param name="position"></param> - /// <param name="type"></param> - /// <param name="color"></param> - /// <param name="ruleType"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingColorScaleValue( - eExcelConditionalFormattingValueObjectPosition position, - eExcelConditionalFormattingValueObjectType type, - Color color, - eExcelConditionalFormattingRuleType ruleType, + /// <summary> + /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> + /// </summary> + /// <param name="position"></param> + /// <param name="type"></param> + /// <param name="color"></param> + /// <param name="ruleType"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingColorScaleValue( + eExcelConditionalFormattingValueObjectPosition position, + eExcelConditionalFormattingValueObjectType type, + Color color, + eExcelConditionalFormattingRuleType ruleType, ExcelAddress address, int priority, - ExcelWorksheet worksheet, - XmlNamespaceManager namespaceManager) - : this( - position, - type, - color, - 0, - null, - ruleType, - address, - priority, - worksheet, - null, - namespaceManager) - { - } - #endregion Constructors + ExcelWorksheet worksheet, + XmlNamespaceManager namespaceManager) + : this( + position, + type, + color, + 0, + null, + ruleType, + address, + priority, + worksheet, + null, + namespaceManager) {} - /****************************************************************************************/ + /****************************************************************************************/ - #region Methods - /// <summary> - /// Get the node order (1, 2 ou 3) according to the Position (Low, Middle and High) - /// and the Rule Type (TwoColorScale ou ThreeColorScale). - /// </summary> - /// <returns></returns> - private int GetNodeOrder() - { - return ExcelConditionalFormattingValueObjectType.GetOrderByPosition( - Position, - RuleType); - } - /// <summary> - /// Create the 'cfvo'/'color' nodes in the right order. They should appear like this: - /// "cfvo" --> Low Value (value object) - /// "cfvo" --> Middle Value (value object) - /// "cfvo" --> High Value (value object) - /// "color" --> Low Value (color) - /// "color" --> Middle Value (color) - /// "color" --> High Value (color) - /// </summary> - /// <param name="nodeType"></param> - /// <param name="attributePath"></param> - /// <param name="attributeValue"></param> - private void CreateNodeByOrdem( - eExcelConditionalFormattingValueObjectNodeType nodeType, - string attributePath, - string attributeValue) - { - // Save the current TopNode - XmlNode currentTopNode = TopNode; + /// <summary> + /// Get the node order (1, 2 ou 3) according to the Position (Low, Middle and High) + /// and the Rule Type (TwoColorScale ou ThreeColorScale). + /// </summary> + /// <returns></returns> + private int GetNodeOrder() { + return ExcelConditionalFormattingValueObjectType.GetOrderByPosition(Position, RuleType); + } - string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType(nodeType); - int nodeOrder = GetNodeOrder(); - eNodeInsertOrder nodeInsertOrder = eNodeInsertOrder.SchemaOrder; - XmlNode referenceNode = null; + /// <summary> + /// Create the 'cfvo'/'color' nodes in the right order. They should appear like this: + /// "cfvo" --> Low Value (value object) + /// "cfvo" --> Middle Value (value object) + /// "cfvo" --> High Value (value object) + /// "color" --> Low Value (color) + /// "color" --> Middle Value (color) + /// "color" --> High Value (color) + /// </summary> + /// <param name="nodeType"></param> + /// <param name="attributePath"></param> + /// <param name="attributeValue"></param> + private void CreateNodeByOrdem( + eExcelConditionalFormattingValueObjectNodeType nodeType, + string attributePath, + string attributeValue) { + // Save the current TopNode + XmlNode currentTopNode = TopNode; - if (nodeOrder > 1) - { - // Find the node just before the one we need to include - referenceNode = TopNode.SelectSingleNode( - string.Format( - "{0}[position()={1}]", - // {0} - nodePath, - // {1} - nodeOrder - 1), - _worksheet.NameSpaceManager); + string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType(nodeType); + int nodeOrder = GetNodeOrder(); + eNodeInsertOrder nodeInsertOrder = eNodeInsertOrder.SchemaOrder; + XmlNode referenceNode = null; - // Only if the prepend node exists than insert after - if (referenceNode != null) - { - nodeInsertOrder = eNodeInsertOrder.After; - } - } + if (nodeOrder > 1) { + // Find the node just before the one we need to include + referenceNode = TopNode.SelectSingleNode( + string.Format( + "{0}[position()={1}]", + // {0} + nodePath, + // {1} + nodeOrder - 1), + _worksheet.NameSpaceManager); - // Create the node in the right order - var node = CreateComplexNode( - TopNode, - string.Format( - "{0}[position()={1}]", - // {0} - nodePath, - // {1} - nodeOrder), - nodeInsertOrder, - referenceNode); + // Only if the prepend node exists than insert after + if (referenceNode != null) { + nodeInsertOrder = eNodeInsertOrder.After; + } + } - // Point to the new node as the temporary TopNode (we need it for the XmlHelper functions) - TopNode = node; + // Create the node in the right order + var node = CreateComplexNode( + TopNode, + string.Format( + "{0}[position()={1}]", + // {0} + nodePath, + // {1} + nodeOrder), + nodeInsertOrder, + referenceNode); - // Add/Remove the attribute (if the attributeValue is empty then it will be removed) - SetXmlNodeString( - node, - attributePath, - attributeValue, - true); + // Point to the new node as the temporary TopNode (we need it for the XmlHelper functions) + TopNode = node; - // Point back to the <cfvo>/<color> parent node - TopNode = currentTopNode; - } - #endregion Methos + // Add/Remove the attribute (if the attributeValue is empty then it will be removed) + SetXmlNodeString(node, attributePath, attributeValue, true); - /****************************************************************************************/ + // Point back to the <cfvo>/<color> parent node + TopNode = currentTopNode; + } - #region Exposed Properties - /// <summary> - /// - /// </summary> - internal eExcelConditionalFormattingValueObjectPosition Position - { - get { return _position; } - set { _position = value; } - } + /****************************************************************************************/ - /// <summary> - /// - /// </summary> - internal eExcelConditionalFormattingRuleType RuleType - { - get { return _ruleType; } - set { _ruleType = value; } - } - /// <summary> - /// - /// </summary> - public eExcelConditionalFormattingValueObjectType Type - { - get - { - var typeAttribute = GetXmlNodeString( - string.Format( - "{0}[position()={1}]/{2}", - // {0} - ExcelConditionalFormattingConstants.Paths.Cfvo, - // {1} - GetNodeOrder(), - // {2} - ExcelConditionalFormattingConstants.Paths.TypeAttribute)); + /// <summary> + /// + /// </summary> + internal eExcelConditionalFormattingValueObjectPosition Position { + get => _position; + set => _position = value; + } - return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute); - } - set - { - CreateNodeByOrdem( - eExcelConditionalFormattingValueObjectNodeType.Cfvo, - ExcelConditionalFormattingConstants.Paths.TypeAttribute, - ExcelConditionalFormattingValueObjectType.GetAttributeByType(value)); + /// <summary> + /// + /// </summary> + internal eExcelConditionalFormattingRuleType RuleType { + get => _ruleType; + set => _ruleType = value; + } - bool removeValAttribute = false; + /// <summary> + /// + /// </summary> + public eExcelConditionalFormattingValueObjectType Type { + get { + var typeAttribute = GetXmlNodeString( + string.Format( + "{0}[position()={1}]/{2}", + // {0} + ExcelConditionalFormattingConstants.Paths._cfvo, + // {1} + GetNodeOrder(), + // {2} + ExcelConditionalFormattingConstants.Paths._typeAttribute)); - // Make sure unnecessary attributes are removed (occures when we change - // the value object type) - switch (Type) - { - case eExcelConditionalFormattingValueObjectType.Min: - case eExcelConditionalFormattingValueObjectType.Max: - removeValAttribute = true; - break; - } + return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute); + } + set { + CreateNodeByOrdem( + eExcelConditionalFormattingValueObjectNodeType.Cfvo, + ExcelConditionalFormattingConstants.Paths._typeAttribute, + ExcelConditionalFormattingValueObjectType.GetAttributeByType(value)); - // Check if we need to remove the @val attribute - if (removeValAttribute) - { - string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType( - eExcelConditionalFormattingValueObjectNodeType.Cfvo); - int nodeOrder = GetNodeOrder(); + bool removeValAttribute = false; - // Remove the attribute (removed when the value = '') - CreateComplexNode( - TopNode, - string.Format( - "{0}[position()={1}]/{2}=''", - // {0} - nodePath, - // {1} - nodeOrder, - // {2} - ExcelConditionalFormattingConstants.Paths.ValAttribute)); - } - } - } + // Make sure unnecessary attributes are removed (occures when we change + // the value object type) + switch (Type) { + case eExcelConditionalFormattingValueObjectType.Min: + case eExcelConditionalFormattingValueObjectType.Max: + removeValAttribute = true; + break; + } - /// <summary> - /// - /// </summary> - public Color Color - { - get - { - // Color Code like "FF5B34F2" - var colorCode = GetXmlNodeString( - string.Format( - "{0}[position()={1}]/{2}", - // {0} - ExcelConditionalFormattingConstants.Paths.Color, - // {1} - GetNodeOrder(), - // {2} - ExcelConditionalFormattingConstants.Paths.RgbAttribute)); + // Check if we need to remove the @val attribute + if (removeValAttribute) { + string nodePath = ExcelConditionalFormattingValueObjectType.GetNodePathByNodeType( + eExcelConditionalFormattingValueObjectNodeType.Cfvo); + int nodeOrder = GetNodeOrder(); - return ExcelConditionalFormattingHelper.ConvertFromColorCode(colorCode); - } - set - { - // Use the color code to store (Ex. "FF5B35F2") - CreateNodeByOrdem( - eExcelConditionalFormattingValueObjectNodeType.Color, - ExcelConditionalFormattingConstants.Paths.RgbAttribute, - value.ToArgb().ToString("x")); - } - } + // Remove the attribute (removed when the value = '') + CreateComplexNode( + TopNode, + string.Format( + "{0}[position()={1}]/{2}=''", + // {0} + nodePath, + // {1} + nodeOrder, + // {2} + ExcelConditionalFormattingConstants.Paths._valAttribute)); + } + } + } - /// <summary> - /// Get/Set the 'cfvo' node @val attribute - /// </summary> - public Double Value - { - get - { - return GetXmlNodeDouble( - string.Format( - "{0}[position()={1}]/{2}", - // {0} - ExcelConditionalFormattingConstants.Paths.Cfvo, - // {1} - GetNodeOrder(), - // {2} - ExcelConditionalFormattingConstants.Paths.ValAttribute)); - } - set - { - string valueToStore = string.Empty; + /// <summary> + /// + /// </summary> + public Color Color { + get { + // Color Code like "FF5B34F2" + var colorCode = GetXmlNodeString( + string.Format( + "{0}[position()={1}]/{2}", + // {0} + ExcelConditionalFormattingConstants.Paths._color, + // {1} + GetNodeOrder(), + // {2} + ExcelConditionalFormattingConstants.Paths._rgbAttribute)); - // Only some types use the @val attribute - if ((Type == eExcelConditionalFormattingValueObjectType.Num) - || (Type == eExcelConditionalFormattingValueObjectType.Percent) - || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) - { - valueToStore = value.ToString(); - } + return ExcelConditionalFormattingHelper.ConvertFromColorCode(colorCode); + } + set => + // Use the color code to store (Ex. "FF5B35F2") + CreateNodeByOrdem( + eExcelConditionalFormattingValueObjectNodeType.Color, + ExcelConditionalFormattingConstants.Paths._rgbAttribute, + value.ToArgb().ToString("x")); + } - CreateNodeByOrdem( - eExcelConditionalFormattingValueObjectNodeType.Cfvo, - ExcelConditionalFormattingConstants.Paths.ValAttribute, - valueToStore); - } - } + /// <summary> + /// Get/Set the 'cfvo' node @val attribute + /// </summary> + public Double Value { + get => + GetXmlNodeDouble( + string.Format( + "{0}[position()={1}]/{2}", + // {0} + ExcelConditionalFormattingConstants.Paths._cfvo, + // {1} + GetNodeOrder(), + // {2} + ExcelConditionalFormattingConstants.Paths._valAttribute)); + set { + string valueToStore = string.Empty; - /// <summary> - /// Get/Set the Formula of the Object Value (uses the same attribute as the Value) - /// </summary> - public string Formula - { - get - { - // Return empty if the Object Value type is not Formula - if (Type != eExcelConditionalFormattingValueObjectType.Formula) - { - return string.Empty; - } + // Only some types use the @val attribute + if ((Type == eExcelConditionalFormattingValueObjectType.Num) + || (Type == eExcelConditionalFormattingValueObjectType.Percent) + || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) { + valueToStore = value.ToString(); + } - // Excel stores the formula in the @val attribute - return GetXmlNodeString( - string.Format( - "{0}[position()={1}]/{2}", - // {0} - ExcelConditionalFormattingConstants.Paths.Cfvo, - // {1} - GetNodeOrder(), - // {2} - ExcelConditionalFormattingConstants.Paths.ValAttribute)); - } - set - { - // Only store the formula if the Object Value type is Formula - if (Type == eExcelConditionalFormattingValueObjectType.Formula) - { - CreateNodeByOrdem( - eExcelConditionalFormattingValueObjectNodeType.Cfvo, - ExcelConditionalFormattingConstants.Paths.ValAttribute, - (value == null) ? string.Empty : value.ToString()); - } - } - } - #endregion Exposed Properties + CreateNodeByOrdem( + eExcelConditionalFormattingValueObjectNodeType.Cfvo, + ExcelConditionalFormattingConstants.Paths._valAttribute, + valueToStore); + } + } - /****************************************************************************************/ - } -} \ No newline at end of file + /// <summary> + /// Get/Set the Formula of the Object Value (uses the same attribute as the Value) + /// </summary> + public string Formula { + get { + // Return empty if the Object Value type is not Formula + if (Type != eExcelConditionalFormattingValueObjectType.Formula) { + return string.Empty; + } + + // Excel stores the formula in the @val attribute + return GetXmlNodeString( + string.Format( + "{0}[position()={1}]/{2}", + // {0} + ExcelConditionalFormattingConstants.Paths._cfvo, + // {1} + GetNodeOrder(), + // {2} + ExcelConditionalFormattingConstants.Paths._valAttribute)); + } + set { + // Only store the formula if the Object Value type is Formula + if (Type == eExcelConditionalFormattingValueObjectType.Formula) { + CreateNodeByOrdem( + eExcelConditionalFormattingValueObjectNodeType.Cfvo, + ExcelConditionalFormattingConstants.Paths._valAttribute, + (value == null) ? string.Empty : value); + } + } + } + + /****************************************************************************************/ +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs index 6f8918c..938c6cd 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingConstants.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,271 +13,247 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// The conditional formatting constants - /// </summary> - internal static class ExcelConditionalFormattingConstants - { - #region Errors - internal class Errors - { - internal const string CommaSeparatedAddresses = @"Multiple addresses may not be commaseparated, use space instead"; - internal const string InvalidCfruleObject = @"The supplied item must inherit OfficeOpenXml.ConditionalFormatting.ExcelConditionalFormattingRule"; - internal const string InvalidConditionalFormattingObject = @"The supplied item must inherit OfficeOpenXml.ConditionalFormatting.ExcelConditionalFormatting"; - internal const string InvalidPriority = @"Invalid priority number. Must be bigger than zero"; - internal const string InvalidRemoveRuleOperation = @"Invalid remove rule operation"; - internal const string MissingCfvoNode = @"Missing 'cfvo' node in Conditional Formatting"; - internal const string MissingCfvoParentNode = @"Missing 'cfvo' parent node in Conditional Formatting"; - internal const string MissingConditionalFormattingNode = @"Missing 'conditionalFormatting' node in Conditional Formatting"; - internal const string MissingItemRuleList = @"Missing item with address '{0}' in Conditional Formatting Rule List"; - internal const string MissingPriorityAttribute = @"Missing 'priority' attribute in Conditional Formatting Rule"; - internal const string MissingRuleType = @"Missing eExcelConditionalFormattingRuleType Type in Conditional Formatting"; - internal const string MissingSqrefAttribute = @"Missing 'sqref' attribute in Conditional Formatting"; - internal const string MissingTypeAttribute = @"Missing 'type' attribute in Conditional Formatting Rule"; - internal const string MissingWorksheetNode = @"Missing 'worksheet' node"; - internal const string NonSupportedRuleType = @"Non supported conditionalFormattingType: {0}"; - internal const string UnexistentCfvoTypeAttribute = @"Unexistent eExcelConditionalFormattingValueObjectType attribute in Conditional Formatting"; - internal const string UnexistentOperatorTypeAttribute = @"Unexistent eExcelConditionalFormattingOperatorType attribute in Conditional Formatting"; - internal const string UnexistentTimePeriodTypeAttribute = @"Unexistent eExcelConditionalFormattingTimePeriodType attribute in Conditional Formatting"; - internal const string UnexpectedRuleTypeAttribute = @"Unexpected eExcelConditionalFormattingRuleType attribute in Conditional Formatting Rule"; - internal const string UnexpectedRuleTypeName = @"Unexpected eExcelConditionalFormattingRuleType TypeName in Conditional Formatting Rule"; - internal const string WrongNumberCfvoColorNodes = @"Wrong number of 'cfvo'/'color' nodes in Conditional Formatting Rule"; - } - #endregion Errors +namespace OfficeOpenXml.ConditionalFormatting; - #region Nodes - internal class Nodes - { - internal const string Worksheet = "worksheet"; - internal const string ConditionalFormatting = "conditionalFormatting"; - internal const string CfRule = "cfRule"; - internal const string ColorScale = "colorScale"; - internal const string Cfvo = "cfvo"; - internal const string Color = "color"; - internal const string DataBar = "dataBar"; - internal const string IconSet = "iconSet"; - internal const string Formula = "formula"; - } - #endregion Nodes - - #region Attributes - internal class Attributes - { - internal const string AboveAverage = "aboveAverage"; - internal const string Bottom = "bottom"; - internal const string DxfId = "dxfId"; - internal const string EqualAverage = "equalAverage"; - internal const string IconSet = "iconSet"; - internal const string Operator = "operator"; - internal const string Percent = "percent"; - internal const string Priority = "priority"; - internal const string Rank = "rank"; - internal const string Reverse = "reverse"; - internal const string Rgb = "rgb"; - internal const string ShowValue = "showValue"; - internal const string Sqref = "sqref"; - internal const string StdDev = "stdDev"; - internal const string StopIfTrue = "stopIfTrue"; - internal const string Text = "text"; - internal const string Theme = "theme"; - internal const string TimePeriod = "timePeriod"; - internal const string Tint = "tint"; - internal const string Type = "type"; - internal const string Val = "val"; - } - #endregion Attributes - - #region XML Paths - internal class Paths - { - // Main node and attributes - internal const string Worksheet = "d:" + Nodes.Worksheet; - - // <conditionalFormatting> §18.3.1.18 node - // can appear more than once in a worksheet - internal const string ConditionalFormatting = "d:" + Nodes.ConditionalFormatting; - - // <cfRule> §18.3.1.10 node - // can appear more than once in a <conditionalFormatting> - internal const string CfRule = "d:" + Nodes.CfRule; - - // <colorScale> §18.3.1.16 node - internal const string ColorScale = "d:" + Nodes.ColorScale; - - // <cfvo> §18.3.1.11 node - internal const string Cfvo = "d:" + Nodes.Cfvo; - - // <color> §18.3.1.15 node - internal const string Color = "d:" + Nodes.Color; - - // <dataBar> §18.3.1.28 node - internal const string DataBar = "d:" + Nodes.DataBar; - - // <iconSet> §18.3.1.49 node - internal const string IconSet = "d:" + Nodes.IconSet; - - // <formula> §18.3.1.43 node - internal const string Formula = "d:" + Nodes.Formula; - - // Attributes (for all the nodes) - internal const string AboveAverageAttribute = "@" + Attributes.AboveAverage; - internal const string BottomAttribute = "@" + Attributes.Bottom; - internal const string DxfIdAttribute = "@" + Attributes.DxfId; - internal const string EqualAverageAttribute = "@" + Attributes.EqualAverage; - internal const string IconSetAttribute = "@" + Attributes.IconSet; - internal const string OperatorAttribute = "@" + Attributes.Operator; - internal const string PercentAttribute = "@" + Attributes.Percent; - internal const string PriorityAttribute = "@" + Attributes.Priority; - internal const string RankAttribute = "@" + Attributes.Rank; - internal const string ReverseAttribute = "@" + Attributes.Reverse; - internal const string RgbAttribute = "@" + Attributes.Rgb; - internal const string ShowValueAttribute = "@" + Attributes.ShowValue; - internal const string SqrefAttribute = "@" + Attributes.Sqref; - internal const string StdDevAttribute = "@" + Attributes.StdDev; - internal const string StopIfTrueAttribute = "@" + Attributes.StopIfTrue; - internal const string TextAttribute = "@" + Attributes.Text; - internal const string ThemeAttribute = "@" + Attributes.Theme; - internal const string TimePeriodAttribute = "@" + Attributes.TimePeriod; - internal const string TintAttribute = "@" + Attributes.Tint; - internal const string TypeAttribute = "@" + Attributes.Type; - internal const string ValAttribute = "@" + Attributes.Val; - } - #endregion XML Paths - - #region Rule Type ST_CfType §18.18.12 (with small EPPlus changes) - internal class RuleType - { - internal const string AboveAverage = "aboveAverage"; - internal const string BeginsWith = "beginsWith"; - internal const string CellIs = "cellIs"; - internal const string ColorScale = "colorScale"; - internal const string ContainsBlanks = "containsBlanks"; - internal const string ContainsErrors = "containsErrors"; - internal const string ContainsText = "containsText"; - internal const string DataBar = "dataBar"; - internal const string DuplicateValues = "duplicateValues"; - internal const string EndsWith = "endsWith"; - internal const string Expression = "expression"; - internal const string IconSet = "iconSet"; - internal const string NotContainsBlanks = "notContainsBlanks"; - internal const string NotContainsErrors = "notContainsErrors"; - internal const string NotContainsText = "notContainsText"; - internal const string TimePeriod = "timePeriod"; - internal const string Top10 = "top10"; - internal const string UniqueValues = "uniqueValues"; - - // EPPlus Extended Types - internal const string AboveOrEqualAverage = "aboveOrEqualAverage"; - internal const string AboveStdDev = "aboveStdDev"; - internal const string BelowAverage = "belowAverage"; - internal const string BelowOrEqualAverage = "belowOrEqualAverage"; - internal const string BelowStdDev = "belowStdDev"; - internal const string Between = "between"; - internal const string Bottom = "bottom"; - internal const string BottomPercent = "bottomPercent"; - internal const string Equal = "equal"; - internal const string GreaterThan = "greaterThan"; - internal const string GreaterThanOrEqual = "greaterThanOrEqual"; - internal const string IconSet3 = "iconSet3"; - internal const string IconSet4 = "iconSet4"; - internal const string IconSet5 = "iconSet5"; - internal const string Last7Days = "last7Days"; - internal const string LastMonth = "lastMonth"; - internal const string LastWeek = "lastWeek"; - internal const string LessThan = "lessThan"; - internal const string LessThanOrEqual = "lessThanOrEqual"; - internal const string NextMonth = "nextMonth"; - internal const string NextWeek = "nextWeek"; - internal const string NotBetween = "notBetween"; - internal const string NotEqual = "notEqual"; - internal const string ThisMonth = "thisMonth"; - internal const string ThisWeek = "thisWeek"; - internal const string ThreeColorScale = "threeColorScale"; - internal const string Today = "today"; - internal const string Tomorrow = "tomorrow"; - internal const string Top = "top"; - internal const string TopPercent = "topPercent"; - internal const string TwoColorScale = "twoColorScale"; - internal const string Yesterday = "yesterday"; - } - #endregion Rule Type ST_CfType §18.18.12 (with small EPPlus changes) - - #region CFVO Type ST_CfvoType §18.18.13 - internal class CfvoType - { - internal const string Min = "min"; - internal const string Max = "max"; - internal const string Num = "num"; - internal const string Formula = "formula"; - internal const string Percent = "percent"; - internal const string Percentile = "percentile"; - } - #endregion CFVO Type ST_CfvoType §18.18.13 - - #region Operator Type ST_ConditionalFormattingOperator §18.18.15 - internal class Operators - { - internal const string BeginsWith = "beginsWith"; - internal const string Between = "between"; - internal const string ContainsText = "containsText"; - internal const string EndsWith = "endsWith"; - internal const string Equal = "equal"; - internal const string GreaterThan = "greaterThan"; - internal const string GreaterThanOrEqual = "greaterThanOrEqual"; - internal const string LessThan = "lessThan"; - internal const string LessThanOrEqual = "lessThanOrEqual"; - internal const string NotBetween = "notBetween"; - internal const string NotContains = "notContains"; - internal const string NotEqual = "notEqual"; - } - #endregion Operator Type ST_ConditionalFormattingOperator §18.18.15 - - #region Time Period Type ST_TimePeriod §18.18.82 - internal class TimePeriods - { - internal const string Last7Days = "last7Days"; - internal const string LastMonth = "lastMonth"; - internal const string LastWeek = "lastWeek"; - internal const string NextMonth = "nextMonth"; - internal const string NextWeek = "nextWeek"; - internal const string ThisMonth = "thisMonth"; - internal const string ThisWeek = "thisWeek"; - internal const string Today = "today"; - internal const string Tomorrow = "tomorrow"; - internal const string Yesterday = "yesterday"; - } - #endregion Time Period Type ST_TimePeriod §18.18.82 - - #region Colors - internal class Colors - { - internal const string CfvoLowValue = @"#FFF8696B"; - internal const string CfvoMiddleValue = @"#FFFFEB84"; - internal const string CfvoHighValue = @"#FF63BE7B"; - } - #endregion Colors +/// <summary> +/// The conditional formatting constants +/// </summary> +internal static class ExcelConditionalFormattingConstants { + internal class Errors { + internal const string _commaSeparatedAddresses = + "Multiple addresses may not be commaseparated, use space instead"; + internal const string _invalidPriority = "Invalid priority number. Must be bigger than zero"; + internal const string _invalidRemoveRuleOperation = "Invalid remove rule operation"; + internal const string _missingCfvoNode = "Missing 'cfvo' node in Conditional Formatting"; + internal const string _missingCfvoParentNode = + "Missing 'cfvo' parent node in Conditional Formatting"; + internal const string _missingConditionalFormattingNode = + "Missing 'conditionalFormatting' node in Conditional Formatting"; + internal const string _missingItemRuleList = + "Missing item with address '{0}' in Conditional Formatting Rule List"; + internal const string _missingPriorityAttribute = + "Missing 'priority' attribute in Conditional Formatting Rule"; + internal const string _missingRuleType = + "Missing eExcelConditionalFormattingRuleType Type in Conditional Formatting"; + internal const string _missingSqrefAttribute = + "Missing 'sqref' attribute in Conditional Formatting"; + internal const string _missingTypeAttribute = + "Missing 'type' attribute in Conditional Formatting Rule"; + internal const string _missingWorksheetNode = "Missing 'worksheet' node"; + internal const string _nonSupportedRuleType = "Non supported conditionalFormattingType: {0}"; + internal const string _unexistentCfvoTypeAttribute = + "Unexistent eExcelConditionalFormattingValueObjectType attribute in Conditional Formatting"; + internal const string _unexistentOperatorTypeAttribute = + "Unexistent eExcelConditionalFormattingOperatorType attribute in Conditional Formatting"; + internal const string _unexistentTimePeriodTypeAttribute = + "Unexistent eExcelConditionalFormattingTimePeriodType attribute in Conditional Formatting"; + internal const string _unexpectedRuleTypeAttribute = + "Unexpected eExcelConditionalFormattingRuleType attribute in Conditional Formatting Rule"; + internal const string _wrongNumberCfvoColorNodes = + "Wrong number of 'cfvo'/'color' nodes in Conditional Formatting Rule"; } -} \ No newline at end of file + + internal class Nodes { + internal const string _worksheet = "worksheet"; + internal const string _conditionalFormatting = "conditionalFormatting"; + internal const string _cfRule = "cfRule"; + internal const string _colorScale = "colorScale"; + internal const string _cfvo = "cfvo"; + internal const string _color = "color"; + internal const string _dataBar = "dataBar"; + internal const string _iconSet = "iconSet"; + internal const string _formula = "formula"; + } + + internal class Attributes { + internal const string _aboveAverage = "aboveAverage"; + internal const string _bottom = "bottom"; + internal const string _dxfId = "dxfId"; + internal const string _equalAverage = "equalAverage"; + internal const string _iconSet = "iconSet"; + internal const string _operator = "operator"; + internal const string _percent = "percent"; + internal const string _priority = "priority"; + internal const string _rank = "rank"; + internal const string _reverse = "reverse"; + internal const string _rgb = "rgb"; + internal const string _showValue = "showValue"; + internal const string _sqref = "sqref"; + internal const string _stdDev = "stdDev"; + internal const string _stopIfTrue = "stopIfTrue"; + internal const string _text = "text"; + internal const string _theme = "theme"; + internal const string _timePeriod = "timePeriod"; + internal const string _tint = "tint"; + internal const string _type = "type"; + internal const string _val = "val"; + } + + internal class Paths { + // Main node and attributes + internal const string _worksheet = "d:" + Nodes._worksheet; + + // <conditionalFormatting> §18.3.1.18 node + // can appear more than once in a worksheet + internal const string _conditionalFormatting = "d:" + Nodes._conditionalFormatting; + + // <cfRule> §18.3.1.10 node + // can appear more than once in a <conditionalFormatting> + internal const string _cfRule = "d:" + Nodes._cfRule; + + // <colorScale> §18.3.1.16 node + internal const string _colorScale = "d:" + Nodes._colorScale; + + // <cfvo> §18.3.1.11 node + internal const string _cfvo = "d:" + Nodes._cfvo; + + // <color> §18.3.1.15 node + internal const string _color = "d:" + Nodes._color; + + // <dataBar> §18.3.1.28 node + internal const string _dataBar = "d:" + Nodes._dataBar; + + // <iconSet> §18.3.1.49 node + internal const string _iconSet = "d:" + Nodes._iconSet; + + // <formula> §18.3.1.43 node + internal const string _formula = "d:" + Nodes._formula; + + // Attributes (for all the nodes) + internal const string _aboveAverageAttribute = "@" + Attributes._aboveAverage; + internal const string _bottomAttribute = "@" + Attributes._bottom; + internal const string _dxfIdAttribute = "@" + Attributes._dxfId; + internal const string _equalAverageAttribute = "@" + Attributes._equalAverage; + internal const string _iconSetAttribute = "@" + Attributes._iconSet; + internal const string _operatorAttribute = "@" + Attributes._operator; + internal const string _percentAttribute = "@" + Attributes._percent; + internal const string _priorityAttribute = "@" + Attributes._priority; + internal const string _rankAttribute = "@" + Attributes._rank; + internal const string _reverseAttribute = "@" + Attributes._reverse; + internal const string _rgbAttribute = "@" + Attributes._rgb; + internal const string _showValueAttribute = "@" + Attributes._showValue; + internal const string _sqrefAttribute = "@" + Attributes._sqref; + internal const string _stdDevAttribute = "@" + Attributes._stdDev; + internal const string _stopIfTrueAttribute = "@" + Attributes._stopIfTrue; + internal const string _textAttribute = "@" + Attributes._text; + internal const string _themeAttribute = "@" + Attributes._theme; + internal const string _timePeriodAttribute = "@" + Attributes._timePeriod; + internal const string _tintAttribute = "@" + Attributes._tint; + internal const string _typeAttribute = "@" + Attributes._type; + internal const string _valAttribute = "@" + Attributes._val; + } + + internal class RuleType { + internal const string _aboveAverage = "aboveAverage"; + internal const string _beginsWith = "beginsWith"; + internal const string _cellIs = "cellIs"; + internal const string _colorScale = "colorScale"; + internal const string _containsBlanks = "containsBlanks"; + internal const string _containsErrors = "containsErrors"; + internal const string _containsText = "containsText"; + internal const string _dataBar = "dataBar"; + internal const string _duplicateValues = "duplicateValues"; + internal const string _endsWith = "endsWith"; + internal const string _expression = "expression"; + internal const string _iconSet = "iconSet"; + internal const string _notContainsBlanks = "notContainsBlanks"; + internal const string _notContainsErrors = "notContainsErrors"; + internal const string _notContainsText = "notContainsText"; + internal const string _timePeriod = "timePeriod"; + internal const string _top10 = "top10"; + internal const string _uniqueValues = "uniqueValues"; + + // EPPlus Extended Types + internal const string _aboveOrEqualAverage = "aboveOrEqualAverage"; + internal const string _aboveStdDev = "aboveStdDev"; + internal const string _belowAverage = "belowAverage"; + internal const string _belowOrEqualAverage = "belowOrEqualAverage"; + internal const string _belowStdDev = "belowStdDev"; + internal const string _between = "between"; + internal const string _bottom = "bottom"; + internal const string _bottomPercent = "bottomPercent"; + internal const string _equal = "equal"; + internal const string _greaterThan = "greaterThan"; + internal const string _greaterThanOrEqual = "greaterThanOrEqual"; + internal const string _iconSet3 = "iconSet3"; + internal const string _iconSet4 = "iconSet4"; + internal const string _iconSet5 = "iconSet5"; + internal const string _last7Days = "last7Days"; + internal const string _lastMonth = "lastMonth"; + internal const string _lastWeek = "lastWeek"; + internal const string _lessThan = "lessThan"; + internal const string _lessThanOrEqual = "lessThanOrEqual"; + internal const string _nextMonth = "nextMonth"; + internal const string _nextWeek = "nextWeek"; + internal const string _notBetween = "notBetween"; + internal const string _notEqual = "notEqual"; + internal const string _thisMonth = "thisMonth"; + internal const string _thisWeek = "thisWeek"; + internal const string _threeColorScale = "threeColorScale"; + internal const string _today = "today"; + internal const string _tomorrow = "tomorrow"; + internal const string _top = "top"; + internal const string _topPercent = "topPercent"; + internal const string _twoColorScale = "twoColorScale"; + internal const string _yesterday = "yesterday"; + } + + internal class CfvoType { + internal const string _min = "min"; + internal const string _max = "max"; + internal const string _num = "num"; + internal const string _formula = "formula"; + internal const string _percent = "percent"; + internal const string _percentile = "percentile"; + } + + internal class Operators { + internal const string _beginsWith = "beginsWith"; + internal const string _between = "between"; + internal const string _containsText = "containsText"; + internal const string _endsWith = "endsWith"; + internal const string _equal = "equal"; + internal const string _greaterThan = "greaterThan"; + internal const string _greaterThanOrEqual = "greaterThanOrEqual"; + internal const string _lessThan = "lessThan"; + internal const string _lessThanOrEqual = "lessThanOrEqual"; + internal const string _notBetween = "notBetween"; + internal const string _notContains = "notContains"; + internal const string _notEqual = "notEqual"; + } + + internal class TimePeriods { + internal const string _last7Days = "last7Days"; + internal const string _lastMonth = "lastMonth"; + internal const string _lastWeek = "lastWeek"; + internal const string _nextMonth = "nextMonth"; + internal const string _nextWeek = "nextWeek"; + internal const string _thisMonth = "thisMonth"; + internal const string _thisWeek = "thisWeek"; + internal const string _today = "today"; + internal const string _tomorrow = "tomorrow"; + internal const string _yesterday = "yesterday"; + } + + internal class Colors { + internal const string _cfvoLowValue = "#FFF8696B"; + internal const string _cfvoMiddleValue = "#FFFFEB84"; + internal const string _cfvoHighValue = "#FF63BE7B"; + } +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs index bff9726..8885f5c 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingEnums.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,772 +13,741 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// Enum for Conditional Format Type ST_CfType §18.18.12. With some changes. +/// </summary> +public enum eExcelConditionalFormattingRuleType { /// <summary> - /// Enum for Conditional Format Type ST_CfType §18.18.12. With some changes. + /// This conditional formatting rule highlights cells that are above the average + /// for all values in the range. /// </summary> - public enum eExcelConditionalFormattingRuleType - { - #region Average - /// <summary> - /// This conditional formatting rule highlights cells that are above the average - /// for all values in the range. - /// </summary> - /// <remarks>AboveAverage Excel CF Rule Type</remarks> - AboveAverage, - - /// <summary> - /// This conditional formatting rule highlights cells that are above or equal - /// the average for all values in the range. - /// </summary> - /// <remarks>AboveAverage Excel CF Rule Type</remarks> - AboveOrEqualAverage, - - /// <summary> - /// This conditional formatting rule highlights cells that are below the average - /// for all values in the range. - /// </summary> - /// <remarks>AboveAverage Excel CF Rule Type</remarks> - BelowAverage, - - /// <summary> - /// This conditional formatting rule highlights cells that are below or equal - /// the average for all values in the range. - /// </summary> - /// <remarks>AboveAverage Excel CF Rule Type</remarks> - BelowOrEqualAverage, - #endregion - - #region StdDev - /// <summary> - /// This conditional formatting rule highlights cells that are above the standard - /// deviationa for all values in the range. - /// <remarks>AboveAverage Excel CF Rule Type</remarks> - /// </summary> - AboveStdDev, - - /// <summary> - /// This conditional formatting rule highlights cells that are below the standard - /// deviationa for all values in the range. - /// </summary> - /// <remarks>AboveAverage Excel CF Rule Type</remarks> - BelowStdDev, - #endregion - - #region TopBottom - /// <summary> - /// This conditional formatting rule highlights cells whose values fall in the - /// bottom N bracket as specified. - /// </summary> - /// <remarks>Top10 Excel CF Rule Type</remarks> - Bottom, - - /// <summary> - /// This conditional formatting rule highlights cells whose values fall in the - /// bottom N percent as specified. - /// </summary> - /// <remarks>Top10 Excel CF Rule Type</remarks> - BottomPercent, - - /// <summary> - /// This conditional formatting rule highlights cells whose values fall in the - /// top N bracket as specified. - /// </summary> - /// <remarks>Top10 Excel CF Rule Type</remarks> - Top, - - /// <summary> - /// This conditional formatting rule highlights cells whose values fall in the - /// top N percent as specified. - /// </summary> - /// <remarks>Top10 Excel CF Rule Type</remarks> - TopPercent, - #endregion - - #region TimePeriod - /// <summary> - /// This conditional formatting rule highlights cells containing dates in the - /// last 7 days. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - Last7Days, - - /// <summary> - /// This conditional formatting rule highlights cells containing dates in the - /// last month. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - LastMonth, - - /// <summary> - /// This conditional formatting rule highlights cells containing dates in the - /// last week. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - LastWeek, - - /// <summary> - /// This conditional formatting rule highlights cells containing dates in the - /// next month. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - NextMonth, - - /// <summary> - /// This conditional formatting rule highlights cells containing dates in the - /// next week. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - NextWeek, - - /// <summary> - /// This conditional formatting rule highlights cells containing dates in this - /// month. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - ThisMonth, - - /// <summary> - /// This conditional formatting rule highlights cells containing dates in this - /// week. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - ThisWeek, - - /// <summary> - /// This conditional formatting rule highlights cells containing today dates. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - Today, - - /// <summary> - /// This conditional formatting rule highlights cells containing tomorrow dates. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - Tomorrow, - - /// <summary> - /// This conditional formatting rule highlights cells containing yesterday dates. - /// </summary> - /// <remarks>TimePeriod Excel CF Rule Type</remarks> - Yesterday, - #endregion - - #region CellIs - /// <summary> - /// This conditional formatting rule highlights cells in the range that begin with - /// the given text. - /// </summary> - /// <remarks> - /// Equivalent to using the LEFT() sheet function and comparing values. - /// </remarks> - /// <remarks>BeginsWith Excel CF Rule Type</remarks> - BeginsWith, - - /// <summary> - /// This conditional formatting rule highlights cells in the range between the - /// given two formulas. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - Between, - - /// <summary> - /// This conditional formatting rule highlights cells that are completely blank. - /// </summary> - /// <remarks> - /// Equivalent of using LEN(TRIM()). This means that if the cell contains only - /// characters that TRIM() would remove, then it is considered blank. An empty cell - /// is also considered blank. - /// </remarks> - /// <remarks>ContainsBlanks Excel CF Rule Type</remarks> - ContainsBlanks, - - /// <summary> - /// This conditional formatting rule highlights cells with formula errors. - /// </summary> - /// <remarks> - /// Equivalent to using ISERROR() sheet function to determine if there is - /// a formula error. - /// </remarks> - /// <remarks>ContainsErrors Excel CF Rule Type</remarks> - ContainsErrors, - - /// <summary> - /// This conditional formatting rule highlights cells in the range that begin with - /// the given text. - /// </summary> - /// <remarks> - /// Equivalent to using the LEFT() sheet function and comparing values. - /// </remarks> - /// <remarks>ContainsText Excel CF Rule Type</remarks> - ContainsText, - - /// <summary> - /// This conditional formatting rule highlights duplicated values. - /// </summary> - /// <remarks>DuplicateValues Excel CF Rule Type</remarks> - DuplicateValues, - - /// <summary> - /// This conditional formatting rule highlights cells ending with given text. - /// </summary> - /// <remarks> - /// Equivalent to using the RIGHT() sheet function and comparing values. - /// </remarks> - /// <remarks>EndsWith Excel CF Rule Type</remarks> - EndsWith, - - /// <summary> - /// This conditional formatting rule highlights cells equals to with given formula. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - Equal, - - /// <summary> - /// This conditional formatting rule contains a formula to evaluate. When the - /// formula result is true, the cell is highlighted. - /// </summary> - /// <remarks>Expression Excel CF Rule Type</remarks> - Expression, - - /// <summary> - /// This conditional formatting rule highlights cells greater than the given formula. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - GreaterThan, - - /// <summary> - /// This conditional formatting rule highlights cells greater than or equal the - /// given formula. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - GreaterThanOrEqual, - - /// <summary> - /// This conditional formatting rule highlights cells less than the given formula. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - LessThan, - - /// <summary> - /// This conditional formatting rule highlights cells less than or equal the - /// given formula. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - LessThanOrEqual, - - /// <summary> - /// This conditional formatting rule highlights cells outside the range in - /// given two formulas. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - NotBetween, - - /// <summary> - /// This conditional formatting rule highlights cells that does not contains the - /// given formula. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - NotContains, - - /// <summary> - /// This conditional formatting rule highlights cells that are not blank. - /// </summary> - /// <remarks> - /// Equivalent of using LEN(TRIM()). This means that if the cell contains only - /// characters that TRIM() would remove, then it is considered blank. An empty cell - /// is also considered blank. - /// </remarks> - /// <remarks>NotContainsBlanks Excel CF Rule Type</remarks> - NotContainsBlanks, - - /// <summary> - /// This conditional formatting rule highlights cells without formula errors. - /// </summary> - /// <remarks> - /// Equivalent to using ISERROR() sheet function to determine if there is a - /// formula error. - /// </remarks> - /// <remarks>NotContainsErrors Excel CF Rule Type</remarks> - NotContainsErrors, - - /// <summary> - /// This conditional formatting rule highlights cells that do not contain - /// the given text. - /// </summary> - /// <remarks> - /// Equivalent to using the SEARCH() sheet function. - /// </remarks> - /// <remarks>NotContainsText Excel CF Rule Type</remarks> - NotContainsText, - - /// <summary> - /// This conditional formatting rule highlights cells not equals to with - /// given formula. - /// </summary> - /// <remarks>CellIs Excel CF Rule Type</remarks> - NotEqual, - - /// <summary> - /// This conditional formatting rule highlights unique values in the range. - /// </summary> - /// <remarks>UniqueValues Excel CF Rule Type</remarks> - UniqueValues, - #endregion - - #region ColorScale - /// <summary> - /// Three Color Scale (Low, Middle and High Color Scale) - /// </summary> - /// <remarks>ColorScale Excel CF Rule Type</remarks> - ThreeColorScale, - - /// <summary> - /// Two Color Scale (Low and High Color Scale) - /// </summary> - /// <remarks>ColorScale Excel CF Rule Type</remarks> - TwoColorScale, - #endregion - - #region IconSet - /// <summary> - /// This conditional formatting rule applies a 3 set icons to cells according - /// to their values. - /// </summary> - /// <remarks>IconSet Excel CF Rule Type</remarks> - ThreeIconSet, - - /// <summary> - /// This conditional formatting rule applies a 4 set icons to cells according - /// to their values. - /// </summary> - /// <remarks>IconSet Excel CF Rule Type</remarks> - FourIconSet, - - /// <summary> - /// This conditional formatting rule applies a 5 set icons to cells according - /// to their values. - /// </summary> - /// <remarks>IconSet Excel CF Rule Type</remarks> - FiveIconSet, - #endregion - - #region DataBar - /// <summary> - /// This conditional formatting rule displays a gradated data bar in the range of cells. - /// </summary> - /// <remarks>DataBar Excel CF Rule Type</remarks> - DataBar - #endregion - } + /// <remarks>AboveAverage Excel CF Rule Type</remarks> + AboveAverage, /// <summary> - /// Enum for Conditional Format Value Object Type ST_CfvoType §18.18.13 + /// This conditional formatting rule highlights cells that are above or equal + /// the average for all values in the range. /// </summary> - public enum eExcelConditionalFormattingValueObjectType - { - /// <summary> - /// Formula - /// </summary> - Formula, - - /// <summary> - /// Maximum Value - /// </summary> - Max, - - /// <summary> - /// Minimum Value - /// </summary> - Min, - - /// <summary> - /// Number Value - /// </summary> - Num, - - /// <summary> - /// Percent - /// </summary> - Percent, - - /// <summary> - /// Percentile - /// </summary> - Percentile - } + /// <remarks>AboveAverage Excel CF Rule Type</remarks> + AboveOrEqualAverage, /// <summary> - /// Enum for Conditional Formatting Value Object Position + /// This conditional formatting rule highlights cells that are below the average + /// for all values in the range. /// </summary> - public enum eExcelConditionalFormattingValueObjectPosition - { - /// <summary> - /// The lower position for both TwoColorScale and ThreeColorScale - /// </summary> - Low, - - /// <summary> - /// The middle position only for ThreeColorScale - /// </summary> - Middle, - - /// <summary> - /// The highest position for both TwoColorScale and ThreeColorScale - /// </summary> - High - } + /// <remarks>AboveAverage Excel CF Rule Type</remarks> + BelowAverage, /// <summary> - /// Enum for Conditional Formatting Value Object Node Type + /// This conditional formatting rule highlights cells that are below or equal + /// the average for all values in the range. /// </summary> - public enum eExcelConditionalFormattingValueObjectNodeType - { - /// <summary> - /// 'cfvo' node - /// </summary> - Cfvo, - - /// <summary> - /// 'color' node - /// </summary> - Color - } + /// <remarks>AboveAverage Excel CF Rule Type</remarks> + BelowOrEqualAverage, /// <summary> - /// Enum for Conditional Formatting Operartor Type ST_ConditionalFormattingOperator §18.18.15 + /// This conditional formatting rule highlights cells that are above the standard + /// deviationa for all values in the range. + /// <remarks>AboveAverage Excel CF Rule Type</remarks> /// </summary> - public enum eExcelConditionalFormattingOperatorType - { - /// <summary> - /// Begins With. 'Begins with' operator - /// </summary> - BeginsWith, - - /// <summary> - /// Between. 'Between' operator - /// </summary> - Between, - - /// <summary> - /// Contains. 'Contains' operator - /// </summary> - ContainsText, - - /// <summary> - /// Ends With. 'Ends with' operator - /// </summary> - EndsWith, - - /// <summary> - /// Equal. 'Equal to' operator - /// </summary> - Equal, - - /// <summary> - /// Greater Than. 'Greater than' operator - /// </summary> - GreaterThan, - - /// <summary> - /// Greater Than Or Equal. 'Greater than or equal to' operator - /// </summary> - GreaterThanOrEqual, - - /// <summary> - /// Less Than. 'Less than' operator - /// </summary> - LessThan, - - /// <summary> - /// Less Than Or Equal. 'Less than or equal to' operator - /// </summary> - LessThanOrEqual, - - /// <summary> - /// Not Between. 'Not between' operator - /// </summary> - NotBetween, - - /// <summary> - /// Does Not Contain. 'Does not contain' operator - /// </summary> - NotContains, - - /// <summary> - /// Not Equal. 'Not equal to' operator - /// </summary> - NotEqual - } + AboveStdDev, /// <summary> - /// Enum for Conditional Formatting Time Period Type ST_TimePeriod §18.18.82 + /// This conditional formatting rule highlights cells that are below the standard + /// deviationa for all values in the range. /// </summary> - public enum eExcelConditionalFormattingTimePeriodType - { - /// <summary> - /// Last 7 Days. A date in the last seven days. - /// </summary> - Last7Days, - - /// <summary> - /// Last Month. A date occuring in the last calendar month. - /// </summary> - LastMonth, - - /// <summary> - /// Last Week. A date occuring last week. - /// </summary> - LastWeek, - - /// <summary> - /// Next Month. A date occuring in the next calendar month. - /// </summary> - NextMonth, - - /// <summary> - /// Next Week. A date occuring next week. - /// </summary> - NextWeek, - - /// <summary> - /// This Month. A date occuring in this calendar month. - /// </summary> - ThisMonth, - - /// <summary> - /// This Week. A date occuring this week. - /// </summary> - ThisWeek, - - /// <summary> - /// Today. Today's date. - /// </summary> - Today, - - /// <summary> - /// Tomorrow. Tomorrow's date. - /// </summary> - Tomorrow, - - /// <summary> - /// Yesterday. Yesterday's date. - /// </summary> - Yesterday - } + /// <remarks>AboveAverage Excel CF Rule Type</remarks> + BelowStdDev, /// <summary> - /// 18.18.42 ST_IconSetType (Icon Set Type) - Only 3 icons + /// This conditional formatting rule highlights cells whose values fall in the + /// bottom N bracket as specified. /// </summary> - public enum eExcelconditionalFormatting3IconsSetType - { - /// <summary> - /// (3 Arrows) 3 arrows icon set. - /// </summary> - Arrows, - - /// <summary> - /// (3 Arrows (Gray)) 3 gray arrows icon set. - /// </summary> - ArrowsGray, - - /// <summary> - /// (3 Flags) 3 flags icon set. - /// </summary> - Flags, - - /// <summary> - /// (3 Signs) 3 signs icon set. - /// </summary> - Signs, - - /// <summary> - /// (3 Symbols Circled) 3 symbols icon set. - /// </summary> - Symbols, - - /// <summary> - /// (3 Symbols) 3 Symbols icon set. - /// </summary> - Symbols2, - - /// <summary> - /// (3 Traffic Lights) 3 traffic lights icon set (#1). - /// </summary> - TrafficLights1, - - /// <summary> - /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border. - /// </summary> - TrafficLights2 - } + /// <remarks>Top10 Excel CF Rule Type</remarks> + Bottom, /// <summary> - /// 18.18.42 ST_IconSetType (Icon Set Type) - Only 4 icons + /// This conditional formatting rule highlights cells whose values fall in the + /// bottom N percent as specified. /// </summary> - public enum eExcelconditionalFormatting4IconsSetType - { - /// <summary> - /// (4 Arrows) 4 arrows icon set. - /// </summary> - Arrows, - - /// <summary> - /// (4 Arrows (Gray)) 4 gray arrows icon set. - /// </summary> - ArrowsGray, - - /// <summary> - /// (4 Ratings) 4 ratings icon set. - /// </summary> - Rating, - - /// <summary> - /// (4 Red To Black) 4 'red to black' icon set. - /// </summary> - RedToBlack, - - /// <summary> - /// (4 Traffic Lights) 4 traffic lights icon set. - /// </summary> - TrafficLights - } + /// <remarks>Top10 Excel CF Rule Type</remarks> + BottomPercent, /// <summary> - /// 18.18.42 ST_IconSetType (Icon Set Type) - Only 5 icons + /// This conditional formatting rule highlights cells whose values fall in the + /// top N bracket as specified. /// </summary> - public enum eExcelconditionalFormatting5IconsSetType - { - /// <summary> - /// (5 Arrows) 5 arrows icon set. - /// </summary> - Arrows, + /// <remarks>Top10 Excel CF Rule Type</remarks> + Top, - /// <summary> - /// (5 Arrows (Gray)) 5 gray arrows icon set. - /// </summary> - ArrowsGray, - - /// <summary> - /// (5 Quarters) 5 quarters icon set. - /// </summary> - Quarters, - - /// <summary> - /// (5 Ratings Icon Set) 5 rating icon set. - /// </summary> - Rating - } /// <summary> - /// 18.18.42 ST_IconSetType (Icon Set Type) + /// This conditional formatting rule highlights cells whose values fall in the + /// top N percent as specified. /// </summary> - public enum eExcelconditionalFormattingIconsSetType - { - /// <summary> - /// (3 Arrows) 3 arrows icon set. - /// </summary> - ThreeArrows, + /// <remarks>Top10 Excel CF Rule Type</remarks> + TopPercent, - /// <summary> - /// (3 Arrows (Gray)) 3 gray arrows icon set. - /// </summary> - ThreeArrowsGray, + /// <summary> + /// This conditional formatting rule highlights cells containing dates in the + /// last 7 days. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + Last7Days, - /// <summary> - /// (3 Flags) 3 flags icon set. - /// </summary> - ThreeFlags, + /// <summary> + /// This conditional formatting rule highlights cells containing dates in the + /// last month. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + LastMonth, - /// <summary> - /// (3 Signs) 3 signs icon set. - /// </summary> - ThreeSigns, + /// <summary> + /// This conditional formatting rule highlights cells containing dates in the + /// last week. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + LastWeek, - /// <summary> - /// (3 Symbols Circled) 3 symbols icon set. - /// </summary> - ThreeSymbols, + /// <summary> + /// This conditional formatting rule highlights cells containing dates in the + /// next month. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + NextMonth, - /// <summary> - /// (3 Symbols) 3 Symbols icon set. - /// </summary> - ThreeSymbols2, + /// <summary> + /// This conditional formatting rule highlights cells containing dates in the + /// next week. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + NextWeek, - /// <summary> - /// (3 Traffic Lights) 3 traffic lights icon set (#1). - /// </summary> - ThreeTrafficLights1, + /// <summary> + /// This conditional formatting rule highlights cells containing dates in this + /// month. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + ThisMonth, - /// <summary> - /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border. - /// </summary> - ThreeTrafficLights2, - - /// <summary> - /// (4 Arrows) 4 arrows icon set. - /// </summary> - FourArrows, + /// <summary> + /// This conditional formatting rule highlights cells containing dates in this + /// week. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + ThisWeek, - /// <summary> - /// (4 Arrows (Gray)) 4 gray arrows icon set. - /// </summary> - FourArrowsGray, + /// <summary> + /// This conditional formatting rule highlights cells containing today dates. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + Today, - /// <summary> - /// (4 Ratings) 4 ratings icon set. - /// </summary> - FourRating, + /// <summary> + /// This conditional formatting rule highlights cells containing tomorrow dates. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + Tomorrow, - /// <summary> - /// (4 Red To Black) 4 'red to black' icon set. - /// </summary> - FourRedToBlack, + /// <summary> + /// This conditional formatting rule highlights cells containing yesterday dates. + /// </summary> + /// <remarks>TimePeriod Excel CF Rule Type</remarks> + Yesterday, - /// <summary> - /// (4 Traffic Lights) 4 traffic lights icon set. - /// </summary> - FourTrafficLights, + /// <summary> + /// This conditional formatting rule highlights cells in the range that begin with + /// the given text. + /// </summary> + /// <remarks> + /// Equivalent to using the LEFT() sheet function and comparing values. + /// </remarks> + /// <remarks>BeginsWith Excel CF Rule Type</remarks> + BeginsWith, - /// <summary> - /// (5 Arrows) 5 arrows icon set. - /// </summary> - FiveArrows, + /// <summary> + /// This conditional formatting rule highlights cells in the range between the + /// given two formulas. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + Between, - /// <summary> - /// (5 Arrows (Gray)) 5 gray arrows icon set. - /// </summary> - FiveArrowsGray, + /// <summary> + /// This conditional formatting rule highlights cells that are completely blank. + /// </summary> + /// <remarks> + /// Equivalent of using LEN(TRIM()). This means that if the cell contains only + /// characters that TRIM() would remove, then it is considered blank. An empty cell + /// is also considered blank. + /// </remarks> + /// <remarks>ContainsBlanks Excel CF Rule Type</remarks> + ContainsBlanks, - /// <summary> - /// (5 Quarters) 5 quarters icon set. - /// </summary> - FiveQuarters, + /// <summary> + /// This conditional formatting rule highlights cells with formula errors. + /// </summary> + /// <remarks> + /// Equivalent to using ISERROR() sheet function to determine if there is + /// a formula error. + /// </remarks> + /// <remarks>ContainsErrors Excel CF Rule Type</remarks> + ContainsErrors, - /// <summary> - /// (5 Ratings Icon Set) 5 rating icon set. - /// </summary> - FiveRating + /// <summary> + /// This conditional formatting rule highlights cells in the range that begin with + /// the given text. + /// </summary> + /// <remarks> + /// Equivalent to using the LEFT() sheet function and comparing values. + /// </remarks> + /// <remarks>ContainsText Excel CF Rule Type</remarks> + ContainsText, + + /// <summary> + /// This conditional formatting rule highlights duplicated values. + /// </summary> + /// <remarks>DuplicateValues Excel CF Rule Type</remarks> + DuplicateValues, + + /// <summary> + /// This conditional formatting rule highlights cells ending with given text. + /// </summary> + /// <remarks> + /// Equivalent to using the RIGHT() sheet function and comparing values. + /// </remarks> + /// <remarks>EndsWith Excel CF Rule Type</remarks> + EndsWith, + + /// <summary> + /// This conditional formatting rule highlights cells equals to with given formula. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + Equal, + + /// <summary> + /// This conditional formatting rule contains a formula to evaluate. When the + /// formula result is true, the cell is highlighted. + /// </summary> + /// <remarks>Expression Excel CF Rule Type</remarks> + Expression, + + /// <summary> + /// This conditional formatting rule highlights cells greater than the given formula. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + GreaterThan, + + /// <summary> + /// This conditional formatting rule highlights cells greater than or equal the + /// given formula. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + GreaterThanOrEqual, + + /// <summary> + /// This conditional formatting rule highlights cells less than the given formula. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + LessThan, + + /// <summary> + /// This conditional formatting rule highlights cells less than or equal the + /// given formula. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + LessThanOrEqual, + + /// <summary> + /// This conditional formatting rule highlights cells outside the range in + /// given two formulas. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + NotBetween, + + /// <summary> + /// This conditional formatting rule highlights cells that does not contains the + /// given formula. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + NotContains, + + /// <summary> + /// This conditional formatting rule highlights cells that are not blank. + /// </summary> + /// <remarks> + /// Equivalent of using LEN(TRIM()). This means that if the cell contains only + /// characters that TRIM() would remove, then it is considered blank. An empty cell + /// is also considered blank. + /// </remarks> + /// <remarks>NotContainsBlanks Excel CF Rule Type</remarks> + NotContainsBlanks, + + /// <summary> + /// This conditional formatting rule highlights cells without formula errors. + /// </summary> + /// <remarks> + /// Equivalent to using ISERROR() sheet function to determine if there is a + /// formula error. + /// </remarks> + /// <remarks>NotContainsErrors Excel CF Rule Type</remarks> + NotContainsErrors, + + /// <summary> + /// This conditional formatting rule highlights cells that do not contain + /// the given text. + /// </summary> + /// <remarks> + /// Equivalent to using the SEARCH() sheet function. + /// </remarks> + /// <remarks>NotContainsText Excel CF Rule Type</remarks> + NotContainsText, + + /// <summary> + /// This conditional formatting rule highlights cells not equals to with + /// given formula. + /// </summary> + /// <remarks>CellIs Excel CF Rule Type</remarks> + NotEqual, + + /// <summary> + /// This conditional formatting rule highlights unique values in the range. + /// </summary> + /// <remarks>UniqueValues Excel CF Rule Type</remarks> + UniqueValues, + + /// <summary> + /// Three Color Scale (Low, Middle and High Color Scale) + /// </summary> + /// <remarks>ColorScale Excel CF Rule Type</remarks> + ThreeColorScale, + + /// <summary> + /// Two Color Scale (Low and High Color Scale) + /// </summary> + /// <remarks>ColorScale Excel CF Rule Type</remarks> + TwoColorScale, + + /// <summary> + /// This conditional formatting rule applies a 3 set icons to cells according + /// to their values. + /// </summary> + /// <remarks>IconSet Excel CF Rule Type</remarks> + ThreeIconSet, + + /// <summary> + /// This conditional formatting rule applies a 4 set icons to cells according + /// to their values. + /// </summary> + /// <remarks>IconSet Excel CF Rule Type</remarks> + FourIconSet, + + /// <summary> + /// This conditional formatting rule applies a 5 set icons to cells according + /// to their values. + /// </summary> + /// <remarks>IconSet Excel CF Rule Type</remarks> + FiveIconSet, + + /// <summary> + /// This conditional formatting rule displays a gradated data bar in the range of cells. + /// </summary> + /// <remarks>DataBar Excel CF Rule Type</remarks> + DataBar, } -} \ No newline at end of file + +/// <summary> +/// Enum for Conditional Format Value Object Type ST_CfvoType §18.18.13 +/// </summary> +public enum eExcelConditionalFormattingValueObjectType { + /// <summary> + /// Formula + /// </summary> + Formula, + + /// <summary> + /// Maximum Value + /// </summary> + Max, + + /// <summary> + /// Minimum Value + /// </summary> + Min, + + /// <summary> + /// Number Value + /// </summary> + Num, + + /// <summary> + /// Percent + /// </summary> + Percent, + + /// <summary> + /// Percentile + /// </summary> + Percentile, +} + +/// <summary> +/// Enum for Conditional Formatting Value Object Position +/// </summary> +public enum eExcelConditionalFormattingValueObjectPosition { + /// <summary> + /// The lower position for both TwoColorScale and ThreeColorScale + /// </summary> + Low, + + /// <summary> + /// The middle position only for ThreeColorScale + /// </summary> + Middle, + + /// <summary> + /// The highest position for both TwoColorScale and ThreeColorScale + /// </summary> + High, +} + +/// <summary> +/// Enum for Conditional Formatting Value Object Node Type +/// </summary> +public enum eExcelConditionalFormattingValueObjectNodeType { + /// <summary> + /// 'cfvo' node + /// </summary> + Cfvo, + + /// <summary> + /// 'color' node + /// </summary> + Color, +} + +/// <summary> +/// Enum for Conditional Formatting Operartor Type ST_ConditionalFormattingOperator §18.18.15 +/// </summary> +public enum eExcelConditionalFormattingOperatorType { + /// <summary> + /// Begins With. 'Begins with' operator + /// </summary> + BeginsWith, + + /// <summary> + /// Between. 'Between' operator + /// </summary> + Between, + + /// <summary> + /// Contains. 'Contains' operator + /// </summary> + ContainsText, + + /// <summary> + /// Ends With. 'Ends with' operator + /// </summary> + EndsWith, + + /// <summary> + /// Equal. 'Equal to' operator + /// </summary> + Equal, + + /// <summary> + /// Greater Than. 'Greater than' operator + /// </summary> + GreaterThan, + + /// <summary> + /// Greater Than Or Equal. 'Greater than or equal to' operator + /// </summary> + GreaterThanOrEqual, + + /// <summary> + /// Less Than. 'Less than' operator + /// </summary> + LessThan, + + /// <summary> + /// Less Than Or Equal. 'Less than or equal to' operator + /// </summary> + LessThanOrEqual, + + /// <summary> + /// Not Between. 'Not between' operator + /// </summary> + NotBetween, + + /// <summary> + /// Does Not Contain. 'Does not contain' operator + /// </summary> + NotContains, + + /// <summary> + /// Not Equal. 'Not equal to' operator + /// </summary> + NotEqual, +} + +/// <summary> +/// Enum for Conditional Formatting Time Period Type ST_TimePeriod §18.18.82 +/// </summary> +public enum eExcelConditionalFormattingTimePeriodType { + /// <summary> + /// Last 7 Days. A date in the last seven days. + /// </summary> + Last7Days, + + /// <summary> + /// Last Month. A date occuring in the last calendar month. + /// </summary> + LastMonth, + + /// <summary> + /// Last Week. A date occuring last week. + /// </summary> + LastWeek, + + /// <summary> + /// Next Month. A date occuring in the next calendar month. + /// </summary> + NextMonth, + + /// <summary> + /// Next Week. A date occuring next week. + /// </summary> + NextWeek, + + /// <summary> + /// This Month. A date occuring in this calendar month. + /// </summary> + ThisMonth, + + /// <summary> + /// This Week. A date occuring this week. + /// </summary> + ThisWeek, + + /// <summary> + /// Today. Today's date. + /// </summary> + Today, + + /// <summary> + /// Tomorrow. Tomorrow's date. + /// </summary> + Tomorrow, + + /// <summary> + /// Yesterday. Yesterday's date. + /// </summary> + Yesterday, +} + +/// <summary> +/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 3 icons +/// </summary> +public enum eExcelconditionalFormatting3IconsSetType { + /// <summary> + /// (3 Arrows) 3 arrows icon set. + /// </summary> + Arrows, + + /// <summary> + /// (3 Arrows (Gray)) 3 gray arrows icon set. + /// </summary> + ArrowsGray, + + /// <summary> + /// (3 Flags) 3 flags icon set. + /// </summary> + Flags, + + /// <summary> + /// (3 Signs) 3 signs icon set. + /// </summary> + Signs, + + /// <summary> + /// (3 Symbols Circled) 3 symbols icon set. + /// </summary> + Symbols, + + /// <summary> + /// (3 Symbols) 3 Symbols icon set. + /// </summary> + Symbols2, + + /// <summary> + /// (3 Traffic Lights) 3 traffic lights icon set (#1). + /// </summary> + TrafficLights1, + + /// <summary> + /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border. + /// </summary> + TrafficLights2, +} + +/// <summary> +/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 4 icons +/// </summary> +public enum eExcelconditionalFormatting4IconsSetType { + /// <summary> + /// (4 Arrows) 4 arrows icon set. + /// </summary> + Arrows, + + /// <summary> + /// (4 Arrows (Gray)) 4 gray arrows icon set. + /// </summary> + ArrowsGray, + + /// <summary> + /// (4 Ratings) 4 ratings icon set. + /// </summary> + Rating, + + /// <summary> + /// (4 Red To Black) 4 'red to black' icon set. + /// </summary> + RedToBlack, + + /// <summary> + /// (4 Traffic Lights) 4 traffic lights icon set. + /// </summary> + TrafficLights, +} + +/// <summary> +/// 18.18.42 ST_IconSetType (Icon Set Type) - Only 5 icons +/// </summary> +public enum eExcelconditionalFormatting5IconsSetType { + /// <summary> + /// (5 Arrows) 5 arrows icon set. + /// </summary> + Arrows, + + /// <summary> + /// (5 Arrows (Gray)) 5 gray arrows icon set. + /// </summary> + ArrowsGray, + + /// <summary> + /// (5 Quarters) 5 quarters icon set. + /// </summary> + Quarters, + + /// <summary> + /// (5 Ratings Icon Set) 5 rating icon set. + /// </summary> + Rating, +} + +/// <summary> +/// 18.18.42 ST_IconSetType (Icon Set Type) +/// </summary> +public enum eExcelconditionalFormattingIconsSetType { + /// <summary> + /// (3 Arrows) 3 arrows icon set. + /// </summary> + ThreeArrows, + + /// <summary> + /// (3 Arrows (Gray)) 3 gray arrows icon set. + /// </summary> + ThreeArrowsGray, + + /// <summary> + /// (3 Flags) 3 flags icon set. + /// </summary> + ThreeFlags, + + /// <summary> + /// (3 Signs) 3 signs icon set. + /// </summary> + ThreeSigns, + + /// <summary> + /// (3 Symbols Circled) 3 symbols icon set. + /// </summary> + ThreeSymbols, + + /// <summary> + /// (3 Symbols) 3 Symbols icon set. + /// </summary> + ThreeSymbols2, + + /// <summary> + /// (3 Traffic Lights) 3 traffic lights icon set (#1). + /// </summary> + ThreeTrafficLights1, + + /// <summary> + /// (3 Traffic Lights Black) 3 traffic lights icon set with thick black border. + /// </summary> + ThreeTrafficLights2, + + /// <summary> + /// (4 Arrows) 4 arrows icon set. + /// </summary> + FourArrows, + + /// <summary> + /// (4 Arrows (Gray)) 4 gray arrows icon set. + /// </summary> + FourArrowsGray, + + /// <summary> + /// (4 Ratings) 4 ratings icon set. + /// </summary> + FourRating, + + /// <summary> + /// (4 Red To Black) 4 'red to black' icon set. + /// </summary> + FourRedToBlack, + + /// <summary> + /// (4 Traffic Lights) 4 traffic lights icon set. + /// </summary> + FourTrafficLights, + + /// <summary> + /// (5 Arrows) 5 arrows icon set. + /// </summary> + FiveArrows, + + /// <summary> + /// (5 Arrows (Gray)) 5 gray arrows icon set. + /// </summary> + FiveArrowsGray, + + /// <summary> + /// (5 Quarters) 5 quarters icon set. + /// </summary> + FiveQuarters, + + /// <summary> + /// (5 Ratings Icon Set) 5 rating icon set. + /// </summary> + FiveRating, +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs index 4e86a65..41fbe30 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingHelper.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,262 +13,207 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using OfficeOpenXml.Utils; using System.Drawing; using System.Globalization; +using System.Text.RegularExpressions; using System.Xml; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// Conditional formatting helper +/// </summary> +internal static class ExcelConditionalFormattingHelper { /// <summary> - /// Conditional formatting helper + /// Check and fix an address (string address) /// </summary> - internal static class ExcelConditionalFormattingHelper - { - /// <summary> - /// Check and fix an address (string address) - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public static string CheckAndFixRangeAddress( - string address) - { - if (address.Contains(',')) - { - throw new FormatException( - ExcelConditionalFormattingConstants.Errors.CommaSeparatedAddresses); - } - - address = address.ToUpper(CultureInfo.InvariantCulture); - - if (Regex.IsMatch(address, @"[A-Z]+:[A-Z]+")) - { - address = AddressUtility.ParseEntireColumnSelections(address); - } - - return address; + /// <param name="address"></param> + /// <returns></returns> + public static string CheckAndFixRangeAddress(string address) { + if (address.Contains(',')) { + throw new FormatException( + ExcelConditionalFormattingConstants.Errors._commaSeparatedAddresses); } - /// <summary> - /// Convert a color code to Color Object - /// </summary> - /// <param name="colorCode">Color Code (Ex. "#FFB43C53" or "FFB43C53")</param> - /// <returns></returns> - public static Color ConvertFromColorCode( - string colorCode) - { - try - { - return Color.FromArgb(Int32.Parse(colorCode.Replace("#", ""), NumberStyles.HexNumber)); - } - catch - { - // Assume white is the default color (instead of giving an error) - return Color.White; - } + address = address.ToUpper(CultureInfo.InvariantCulture); + + if (Regex.IsMatch(address, "[A-Z]+:[A-Z]+")) { + address = AddressUtility.ParseEntireColumnSelections(address); } - /// <summary> - /// - /// </summary> - /// <param name="node"></param> - /// <param name="attribute"></param> - /// <returns></returns> - public static string GetAttributeString( - XmlNode node, - string attribute) - { - try - { - var value = node.Attributes[attribute].Value; - return (value == null) ? string.Empty : value; - } - catch - { - return string.Empty; - } - } + return address; + } - /// <summary> - /// - /// </summary> - /// <param name="node"></param> - /// <param name="attribute"></param> - /// <returns></returns> - public static int GetAttributeInt( - XmlNode node, - string attribute) - { - try - { - var value = node.Attributes[attribute].Value; - return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); - } - catch - { - return int.MinValue; - } - } - - /// <summary> - /// - /// </summary> - /// <param name="node"></param> - /// <param name="attribute"></param> - /// <returns></returns> - public static int? GetAttributeIntNullable( - XmlNode node, - string attribute) - { - try - { - if (node.Attributes[attribute] == null) - { - return null; - } - else - { - var value = node.Attributes[attribute].Value; - return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); - } - } - catch - { - return null; - } - } - - /// <summary> - /// - /// </summary> - /// <param name="node"></param> - /// <param name="attribute"></param> - /// <returns></returns> - public static bool GetAttributeBool( - XmlNode node, - string attribute) - { - try - { - var value = node.Attributes[attribute].Value; - return (value == "1" || value == "-1" || value.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase)); - } - catch - { - return false; - } - } - - /// <summary> - /// - /// </summary> - /// <param name="node"></param> - /// <param name="attribute"></param> - /// <returns></returns> - public static bool? GetAttributeBoolNullable( - XmlNode node, - string attribute) - { - try - { - if (node.Attributes[attribute] == null) - { - return null; - } - else - { - var value = node.Attributes[attribute].Value; - return (value == "1" || value == "-1" || value.Equals("TRUE",StringComparison.InvariantCultureIgnoreCase)); - } - } - catch - { - return null; - } - } - - /// <summary> - /// - /// </summary> - /// <param name="node"></param> - /// <param name="attribute"></param> - /// <returns></returns> - public static double GetAttributeDouble( - XmlNode node, - string attribute) - { - try - { - var value = node.Attributes[attribute].Value; - return double.Parse(value, NumberStyles.Number, CultureInfo.InvariantCulture); - } - catch - { - return double.NaN; - } - } - - /// <summary> - /// - /// </summary> - /// <param name="node"></param> - /// <param name="attribute"></param> - /// <returns></returns> - public static decimal GetAttributeDecimal( - XmlNode node, - string attribute) - { - try - { - var value = node.Attributes[attribute].Value; - return decimal.Parse(value, NumberStyles.Any, CultureInfo.InvariantCulture); - } - catch - { - return decimal.MinValue; - } - } - - /// <summary> - /// Encode to XML (special characteres: ' " > < &) - /// </summary> - /// <param name="s"></param> - /// <returns></returns> - public static string EncodeXML( - this string s) - { - return s.Replace("&", "&").Replace("<", "<").Replace(">", ">").Replace("\"", """).Replace("'", "'"); - } - - /// <summary> - /// Decode from XML (special characteres: ' " > < &) - /// </summary> - /// <param name="s"></param> - /// <returns></returns> - public static string DecodeXML( - this string s) - { - return s.Replace("'", "'").Replace("\"", """).Replace(">", ">").Replace("<", "<").Replace("&", "&"); + /// <summary> + /// Convert a color code to Color Object + /// </summary> + /// <param name="colorCode">Color Code (Ex. "#FFB43C53" or "FFB43C53")</param> + /// <returns></returns> + public static Color ConvertFromColorCode(string colorCode) { + try { + return Color.FromArgb(Int32.Parse(colorCode.Replace("#", ""), NumberStyles.HexNumber)); + } catch { + // Assume white is the default color (instead of giving an error) + return Color.White; } } -} \ No newline at end of file + + /// <summary> + /// + /// </summary> + /// <param name="node"></param> + /// <param name="attribute"></param> + /// <returns></returns> + public static string GetAttributeString(XmlNode node, string attribute) { + try { + var value = node.Attributes[attribute].Value; + return (value == null) ? string.Empty : value; + } catch { + return string.Empty; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="node"></param> + /// <param name="attribute"></param> + /// <returns></returns> + public static int GetAttributeInt(XmlNode node, string attribute) { + try { + var value = node.Attributes[attribute].Value; + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } catch { + return int.MinValue; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="node"></param> + /// <param name="attribute"></param> + /// <returns></returns> + public static int? GetAttributeIntNullable(XmlNode node, string attribute) { + try { + if (node.Attributes[attribute] == null) { + return null; + } + var value = node.Attributes[attribute].Value; + return int.Parse(value, NumberStyles.Integer, CultureInfo.InvariantCulture); + } catch { + return null; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="node"></param> + /// <param name="attribute"></param> + /// <returns></returns> + public static bool GetAttributeBool(XmlNode node, string attribute) { + try { + var value = node.Attributes[attribute].Value; + return (value == "1" + || value == "-1" + || value.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase)); + } catch { + return false; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="node"></param> + /// <param name="attribute"></param> + /// <returns></returns> + public static bool? GetAttributeBoolNullable(XmlNode node, string attribute) { + try { + if (node.Attributes[attribute] == null) { + return null; + } + var value = node.Attributes[attribute].Value; + return (value == "1" + || value == "-1" + || value.Equals("TRUE", StringComparison.InvariantCultureIgnoreCase)); + } catch { + return null; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="node"></param> + /// <param name="attribute"></param> + /// <returns></returns> + public static double GetAttributeDouble(XmlNode node, string attribute) { + try { + var value = node.Attributes[attribute].Value; + return double.Parse(value, NumberStyles.Number, CultureInfo.InvariantCulture); + } catch { + return double.NaN; + } + } + + /// <summary> + /// + /// </summary> + /// <param name="node"></param> + /// <param name="attribute"></param> + /// <returns></returns> + public static decimal GetAttributeDecimal(XmlNode node, string attribute) { + try { + var value = node.Attributes[attribute].Value; + return decimal.Parse(value, NumberStyles.Any, CultureInfo.InvariantCulture); + } catch { + return decimal.MinValue; + } + } + + /// <summary> + /// Encode to XML (special characteres: ' " > < &) + /// </summary> + /// <param name="s"></param> + /// <returns></returns> + public static string EncodeXml(this string s) { + return s.Replace("&", "&") + .Replace("<", "<") + .Replace(">", ">") + .Replace("\"", """) + .Replace("'", "'"); + } + + /// <summary> + /// Decode from XML (special characteres: ' " > < &) + /// </summary> + /// <param name="s"></param> + /// <returns></returns> + public static string DecodeXml(this string s) { + return s.Replace("'", "'") + .Replace("\"", """) + .Replace(">", ">") + .Replace("<", "<") + .Replace("&", "&"); + } +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs index e190cf5..3c7a98b 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingIconDatabarValue.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,346 +13,289 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Drawing; +using System.Globalization; using System.Xml; using OfficeOpenXml.Utils; -using System.Text.RegularExpressions; -using System.Globalization; -using System.Security; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// 18.3.1.11 cfvo (Conditional Format Value Object) - /// Describes the values of the interpolation points in a gradient scale. - /// </summary> - public class ExcelConditionalFormattingIconDataBarValue - : XmlHelper - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Private Properties - private eExcelConditionalFormattingRuleType _ruleType; - private ExcelWorksheet _worksheet; - #endregion Private Properties +/// <summary> +/// 18.3.1.11 cfvo (Conditional Format Value Object) +/// Describes the values of the interpolation points in a gradient scale. +/// </summary> +public class ExcelConditionalFormattingIconDataBarValue : XmlHelper { + /****************************************************************************************/ - /****************************************************************************************/ - #region Constructors - /// <summary> - /// Initialize the cfvo (§18.3.1.11) node - /// </summary> - /// <param name="type"></param> - /// <param name="value"></param> - /// <param name="formula"></param> - /// <param name="ruleType"></param> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following: - /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingIconDataBarValue( - eExcelConditionalFormattingValueObjectType type, - double value, - string formula, - eExcelConditionalFormattingRuleType ruleType, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode, - XmlNamespaceManager namespaceManager) - : this( - ruleType, - address, - worksheet, - itemElementNode, - namespaceManager) - { - Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); + private eExcelConditionalFormattingRuleType _ruleType; + private ExcelWorksheet _worksheet; - // Check if the parent does not exists - if (itemElementNode == null) - { - // Get the parent node path by the rule type - string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType( - ruleType); + /****************************************************************************************/ - // Check for en error (rule type does not have <cfvo>) - if (parentNodePath == string.Empty) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode); - } - // Point to the <cfvo> parent node - itemElementNode = _worksheet.WorksheetXml.SelectSingleNode( - string.Format( - "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}", - // {0} - ExcelConditionalFormattingConstants.Paths.ConditionalFormatting, - // {1} - ExcelConditionalFormattingConstants.Paths.SqrefAttribute, - // {2} - address.Address, - // {3} - ExcelConditionalFormattingConstants.Paths.CfRule, - // {4} - ExcelConditionalFormattingConstants.Paths.PriorityAttribute, - // {5} - priority, - // {6} - parentNodePath), - _worksheet.NameSpaceManager); + /// <summary> + /// Initialize the cfvo (§18.3.1.11) node + /// </summary> + /// <param name="type"></param> + /// <param name="value"></param> + /// <param name="formula"></param> + /// <param name="ruleType"></param> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following: + /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingIconDataBarValue( + eExcelConditionalFormattingValueObjectType type, + double value, + string formula, + eExcelConditionalFormattingRuleType ruleType, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : this(ruleType, address, worksheet, itemElementNode, namespaceManager) { + Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); - // Check for en error (rule type does not have <cfvo>) - if (itemElementNode == null) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode); - } - } + // Check if the parent does not exists + if (itemElementNode == null) { + // Get the parent node path by the rule type + string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType( + ruleType); - TopNode = itemElementNode; + // Check for en error (rule type does not have <cfvo>) + if (parentNodePath == string.Empty) { + throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode); + } - // Save the attributes - RuleType = ruleType; - Type = type; - Value = value; - Formula = formula; - } - /// <summary> - /// Initialize the cfvo (§18.3.1.11) node - /// </summary> - /// <param name="ruleType"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following: - /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingIconDataBarValue( - eExcelConditionalFormattingRuleType ruleType, - ExcelAddress address, - ExcelWorksheet worksheet, - XmlNode itemElementNode, - XmlNamespaceManager namespaceManager) - : base( - namespaceManager, - itemElementNode) - { - Require.Argument(address).IsNotNull("address"); - Require.Argument(worksheet).IsNotNull("worksheet"); + // Point to the <cfvo> parent node + itemElementNode = _worksheet.WorksheetXml.SelectSingleNode( + string.Format( + "//{0}[{1}='{2}']/{3}[{4}='{5}']/{6}", + // {0} + ExcelConditionalFormattingConstants.Paths._conditionalFormatting, + // {1} + ExcelConditionalFormattingConstants.Paths._sqrefAttribute, + // {2} + address.Address, + // {3} + ExcelConditionalFormattingConstants.Paths._cfRule, + // {4} + ExcelConditionalFormattingConstants.Paths._priorityAttribute, + // {5} + priority, + // {6} + parentNodePath), + _worksheet.NameSpaceManager); - // Save the worksheet for private methods to use - _worksheet = worksheet; + // Check for en error (rule type does not have <cfvo>) + if (itemElementNode == null) { + throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode); + } + } - // Schema order list - SchemaNodeOrder = new string[] - { - ExcelConditionalFormattingConstants.Nodes.Cfvo, - }; + TopNode = itemElementNode; - //Check if the parent does not exists - if (itemElementNode == null) - { - // Get the parent node path by the rule type - string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType( - ruleType); + // Save the attributes + RuleType = ruleType; + Type = type; + Value = value; + Formula = formula; + } - // Check for en error (rule type does not have <cfvo>) - if (parentNodePath == string.Empty) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingCfvoParentNode); - } - } - RuleType = ruleType; - } - /// <summary> - /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> - /// </summary> - /// <param name="type"></param> - /// <param name="value"></param> - /// <param name="formula"></param> - /// <param name="ruleType"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingIconDataBarValue( - eExcelConditionalFormattingValueObjectType type, - double value, - string formula, - eExcelConditionalFormattingRuleType ruleType, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNamespaceManager namespaceManager) - : this( - type, - value, - formula, - ruleType, - address, - priority, - worksheet, - null, - namespaceManager) - { - - } - /// <summary> - /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> - /// </summary> - /// <param name="type"></param> - /// <param name="color"></param> - /// <param name="ruleType"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingIconDataBarValue( - eExcelConditionalFormattingValueObjectType type, - Color color, - eExcelConditionalFormattingRuleType ruleType, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNamespaceManager namespaceManager) - : this( - type, - 0, - null, - ruleType, - address, - priority, - worksheet, - null, - namespaceManager) - { - } - #endregion Constructors + /// <summary> + /// Initialize the cfvo (§18.3.1.11) node + /// </summary> + /// <param name="ruleType"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode">The cfvo (§18.3.1.11) node parent. Can be any of the following: + /// colorScale (§18.3.1.16); dataBar (§18.3.1.28); iconSet (§18.3.1.49)</param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingIconDataBarValue( + eExcelConditionalFormattingRuleType ruleType, + ExcelAddress address, + ExcelWorksheet worksheet, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(namespaceManager, itemElementNode) { + Require.Argument(address).IsNotNull("address"); + Require.Argument(worksheet).IsNotNull("worksheet"); - /****************************************************************************************/ + // Save the worksheet for private methods to use + _worksheet = worksheet; - #region Methods - #endregion + // Schema order list + SchemaNodeOrder = new[] { ExcelConditionalFormattingConstants.Nodes._cfvo }; - /****************************************************************************************/ + //Check if the parent does not exists + if (itemElementNode == null) { + // Get the parent node path by the rule type + string parentNodePath = ExcelConditionalFormattingValueObjectType.GetParentPathByRuleType( + ruleType); - #region Exposed Properties + // Check for en error (rule type does not have <cfvo>) + if (parentNodePath == string.Empty) { + throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoParentNode); + } + } + RuleType = ruleType; + } - /// <summary> - /// - /// </summary> - internal eExcelConditionalFormattingRuleType RuleType - { - get { return _ruleType; } - set { _ruleType = value; } - } + /// <summary> + /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> + /// </summary> + /// <param name="type"></param> + /// <param name="value"></param> + /// <param name="formula"></param> + /// <param name="ruleType"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingIconDataBarValue( + eExcelConditionalFormattingValueObjectType type, + double value, + string formula, + eExcelConditionalFormattingRuleType ruleType, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNamespaceManager namespaceManager) + : this( + type, + value, + formula, + ruleType, + address, + priority, + worksheet, + null, + namespaceManager) {} - /// <summary> - /// - /// </summary> - public eExcelConditionalFormattingValueObjectType Type - { - get - { - var typeAttribute = GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TypeAttribute); + /// <summary> + /// Initialize the <see cref="ExcelConditionalFormattingColorScaleValue"/> + /// </summary> + /// <param name="type"></param> + /// <param name="color"></param> + /// <param name="ruleType"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingIconDataBarValue( + eExcelConditionalFormattingValueObjectType type, + Color color, + eExcelConditionalFormattingRuleType ruleType, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNamespaceManager namespaceManager) + : this(type, 0, null, ruleType, address, priority, worksheet, null, namespaceManager) {} - return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute); - } - set - { - if ((_ruleType==eExcelConditionalFormattingRuleType.ThreeIconSet || _ruleType==eExcelConditionalFormattingRuleType.FourIconSet || _ruleType==eExcelConditionalFormattingRuleType.FiveIconSet) && - (value == eExcelConditionalFormattingValueObjectType.Min || value == eExcelConditionalFormattingValueObjectType.Max)) - { - throw(new ArgumentException("Value type can't be Min or Max for icon sets")); - } - SetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TypeAttribute, value.ToString().ToLower(CultureInfo.InvariantCulture)); - } - } + /****************************************************************************************/ - /// <summary> - /// Get/Set the 'cfvo' node @val attribute - /// </summary> - public Double Value - { - get - { - if ((Type == eExcelConditionalFormattingValueObjectType.Num) - || (Type == eExcelConditionalFormattingValueObjectType.Percent) - || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) - { - return GetXmlNodeDouble(ExcelConditionalFormattingConstants.Paths.ValAttribute); - } - else - { - return 0; - } - } - set - { - string valueToStore = string.Empty; + /****************************************************************************************/ - // Only some types use the @val attribute - if ((Type == eExcelConditionalFormattingValueObjectType.Num) - || (Type == eExcelConditionalFormattingValueObjectType.Percent) - || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) - { - valueToStore = value.ToString(CultureInfo.InvariantCulture); - } - SetXmlNodeString(ExcelConditionalFormattingConstants.Paths.ValAttribute, valueToStore); - } - } + /// <summary> + /// + /// </summary> + internal eExcelConditionalFormattingRuleType RuleType { + get => _ruleType; + set => _ruleType = value; + } - /// <summary> - /// Get/Set the Formula of the Object Value (uses the same attribute as the Value) - /// </summary> - public string Formula - { - get - { - // Return empty if the Object Value type is not Formula - if (Type != eExcelConditionalFormattingValueObjectType.Formula) - { - return string.Empty; - } + /// <summary> + /// + /// </summary> + public eExcelConditionalFormattingValueObjectType Type { + get { + var typeAttribute = GetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._typeAttribute); - // Excel stores the formula in the @val attribute - return GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.ValAttribute); - } - set - { - // Only store the formula if the Object Value type is Formula - if (Type == eExcelConditionalFormattingValueObjectType.Formula) - { - SetXmlNodeString(ExcelConditionalFormattingConstants.Paths.ValAttribute, value); - } - } - } - #endregion Exposed Properties + return ExcelConditionalFormattingValueObjectType.GetTypeByAttrbiute(typeAttribute); + } + set { + if ((_ruleType == eExcelConditionalFormattingRuleType.ThreeIconSet + || _ruleType == eExcelConditionalFormattingRuleType.FourIconSet + || _ruleType == eExcelConditionalFormattingRuleType.FiveIconSet) + && (value == eExcelConditionalFormattingValueObjectType.Min + || value == eExcelConditionalFormattingValueObjectType.Max)) { + throw (new ArgumentException("Value type can't be Min or Max for icon sets")); + } + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._typeAttribute, + value.ToString().ToLower(CultureInfo.InvariantCulture)); + } + } - /****************************************************************************************/ - } -} \ No newline at end of file + /// <summary> + /// Get/Set the 'cfvo' node @val attribute + /// </summary> + public Double Value { + get { + if ((Type == eExcelConditionalFormattingValueObjectType.Num) + || (Type == eExcelConditionalFormattingValueObjectType.Percent) + || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) { + return GetXmlNodeDouble(ExcelConditionalFormattingConstants.Paths._valAttribute); + } + return 0; + } + set { + string valueToStore = string.Empty; + + // Only some types use the @val attribute + if ((Type == eExcelConditionalFormattingValueObjectType.Num) + || (Type == eExcelConditionalFormattingValueObjectType.Percent) + || (Type == eExcelConditionalFormattingValueObjectType.Percentile)) { + valueToStore = value.ToString(CultureInfo.InvariantCulture); + } + + SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute, valueToStore); + } + } + + /// <summary> + /// Get/Set the Formula of the Object Value (uses the same attribute as the Value) + /// </summary> + public string Formula { + get { + // Return empty if the Object Value type is not Formula + if (Type != eExcelConditionalFormattingValueObjectType.Formula) { + return string.Empty; + } + + // Excel stores the formula in the @val attribute + return GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute); + } + set { + // Only store the formula if the Object Value type is Formula + if (Type == eExcelConditionalFormattingValueObjectType.Formula) { + SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._valAttribute, value); + } + } + } + + /****************************************************************************************/ +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs index 06e2374..cf0fae8 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingOperatorType.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,133 +13,121 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-17 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// Functions related to the <see cref="ExcelConditionalFormattingOperatorType"/> - /// </summary> - internal static class ExcelConditionalFormattingOperatorType - { - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <returns></returns> - internal static string GetAttributeByType( - eExcelConditionalFormattingOperatorType type) - { - switch (type) - { - case eExcelConditionalFormattingOperatorType.BeginsWith: - return ExcelConditionalFormattingConstants.Operators.BeginsWith; +namespace OfficeOpenXml.ConditionalFormatting; - case eExcelConditionalFormattingOperatorType.Between: - return ExcelConditionalFormattingConstants.Operators.Between; +/// <summary> +/// Functions related to the <see cref="ExcelConditionalFormattingOperatorType"/> +/// </summary> +internal static class ExcelConditionalFormattingOperatorType { + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <returns></returns> + internal static string GetAttributeByType(eExcelConditionalFormattingOperatorType type) { + switch (type) { + case eExcelConditionalFormattingOperatorType.BeginsWith: + return ExcelConditionalFormattingConstants.Operators._beginsWith; - case eExcelConditionalFormattingOperatorType.ContainsText: - return ExcelConditionalFormattingConstants.Operators.ContainsText; + case eExcelConditionalFormattingOperatorType.Between: + return ExcelConditionalFormattingConstants.Operators._between; - case eExcelConditionalFormattingOperatorType.EndsWith: - return ExcelConditionalFormattingConstants.Operators.EndsWith; + case eExcelConditionalFormattingOperatorType.ContainsText: + return ExcelConditionalFormattingConstants.Operators._containsText; - case eExcelConditionalFormattingOperatorType.Equal: - return ExcelConditionalFormattingConstants.Operators.Equal; + case eExcelConditionalFormattingOperatorType.EndsWith: + return ExcelConditionalFormattingConstants.Operators._endsWith; - case eExcelConditionalFormattingOperatorType.GreaterThan: - return ExcelConditionalFormattingConstants.Operators.GreaterThan; + case eExcelConditionalFormattingOperatorType.Equal: + return ExcelConditionalFormattingConstants.Operators._equal; - case eExcelConditionalFormattingOperatorType.GreaterThanOrEqual: - return ExcelConditionalFormattingConstants.Operators.GreaterThanOrEqual; + case eExcelConditionalFormattingOperatorType.GreaterThan: + return ExcelConditionalFormattingConstants.Operators._greaterThan; - case eExcelConditionalFormattingOperatorType.LessThan: - return ExcelConditionalFormattingConstants.Operators.LessThan; + case eExcelConditionalFormattingOperatorType.GreaterThanOrEqual: + return ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual; - case eExcelConditionalFormattingOperatorType.LessThanOrEqual: - return ExcelConditionalFormattingConstants.Operators.LessThanOrEqual; + case eExcelConditionalFormattingOperatorType.LessThan: + return ExcelConditionalFormattingConstants.Operators._lessThan; - case eExcelConditionalFormattingOperatorType.NotBetween: - return ExcelConditionalFormattingConstants.Operators.NotBetween; + case eExcelConditionalFormattingOperatorType.LessThanOrEqual: + return ExcelConditionalFormattingConstants.Operators._lessThanOrEqual; - case eExcelConditionalFormattingOperatorType.NotContains: - return ExcelConditionalFormattingConstants.Operators.NotContains; + case eExcelConditionalFormattingOperatorType.NotBetween: + return ExcelConditionalFormattingConstants.Operators._notBetween; - case eExcelConditionalFormattingOperatorType.NotEqual: - return ExcelConditionalFormattingConstants.Operators.NotEqual; - } + case eExcelConditionalFormattingOperatorType.NotContains: + return ExcelConditionalFormattingConstants.Operators._notContains; - return string.Empty; - } - - /// <summary> - /// - /// </summary> - /// param name="attribute" - /// <returns></returns> - internal static eExcelConditionalFormattingOperatorType GetTypeByAttribute( - string attribute) - { - switch (attribute) - { - case ExcelConditionalFormattingConstants.Operators.BeginsWith: - return eExcelConditionalFormattingOperatorType.BeginsWith; - - case ExcelConditionalFormattingConstants.Operators.Between: - return eExcelConditionalFormattingOperatorType.Between; - - case ExcelConditionalFormattingConstants.Operators.ContainsText: - return eExcelConditionalFormattingOperatorType.ContainsText; - - case ExcelConditionalFormattingConstants.Operators.EndsWith: - return eExcelConditionalFormattingOperatorType.EndsWith; - - case ExcelConditionalFormattingConstants.Operators.Equal: - return eExcelConditionalFormattingOperatorType.Equal; - - case ExcelConditionalFormattingConstants.Operators.GreaterThan: - return eExcelConditionalFormattingOperatorType.GreaterThan; - - case ExcelConditionalFormattingConstants.Operators.GreaterThanOrEqual: - return eExcelConditionalFormattingOperatorType.GreaterThanOrEqual; - - case ExcelConditionalFormattingConstants.Operators.LessThan: - return eExcelConditionalFormattingOperatorType.LessThan; - - case ExcelConditionalFormattingConstants.Operators.LessThanOrEqual: - return eExcelConditionalFormattingOperatorType.LessThanOrEqual; - - case ExcelConditionalFormattingConstants.Operators.NotBetween: - return eExcelConditionalFormattingOperatorType.NotBetween; - - case ExcelConditionalFormattingConstants.Operators.NotContains: - return eExcelConditionalFormattingOperatorType.NotContains; - - case ExcelConditionalFormattingConstants.Operators.NotEqual: - return eExcelConditionalFormattingOperatorType.NotEqual; - } - - throw new Exception( - ExcelConditionalFormattingConstants.Errors.UnexistentOperatorTypeAttribute); + case eExcelConditionalFormattingOperatorType.NotEqual: + return ExcelConditionalFormattingConstants.Operators._notEqual; } + + return string.Empty; } -} \ No newline at end of file + + /// <summary> + /// + /// </summary> + /// param name="attribute" + /// <returns></returns> + internal static eExcelConditionalFormattingOperatorType GetTypeByAttribute(string attribute) { + switch (attribute) { + case ExcelConditionalFormattingConstants.Operators._beginsWith: + return eExcelConditionalFormattingOperatorType.BeginsWith; + + case ExcelConditionalFormattingConstants.Operators._between: + return eExcelConditionalFormattingOperatorType.Between; + + case ExcelConditionalFormattingConstants.Operators._containsText: + return eExcelConditionalFormattingOperatorType.ContainsText; + + case ExcelConditionalFormattingConstants.Operators._endsWith: + return eExcelConditionalFormattingOperatorType.EndsWith; + + case ExcelConditionalFormattingConstants.Operators._equal: + return eExcelConditionalFormattingOperatorType.Equal; + + case ExcelConditionalFormattingConstants.Operators._greaterThan: + return eExcelConditionalFormattingOperatorType.GreaterThan; + + case ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual: + return eExcelConditionalFormattingOperatorType.GreaterThanOrEqual; + + case ExcelConditionalFormattingConstants.Operators._lessThan: + return eExcelConditionalFormattingOperatorType.LessThan; + + case ExcelConditionalFormattingConstants.Operators._lessThanOrEqual: + return eExcelConditionalFormattingOperatorType.LessThanOrEqual; + + case ExcelConditionalFormattingConstants.Operators._notBetween: + return eExcelConditionalFormattingOperatorType.NotBetween; + + case ExcelConditionalFormattingConstants.Operators._notContains: + return eExcelConditionalFormattingOperatorType.NotContains; + + case ExcelConditionalFormattingConstants.Operators._notEqual: + return eExcelConditionalFormattingOperatorType.NotEqual; + } + + throw new(ExcelConditionalFormattingConstants.Errors._unexistentOperatorTypeAttribute); + } +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs index 088798d..6bc7563 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleFactory.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,361 +13,334 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml; using OfficeOpenXml.Utils; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// Factory class for ExcelConditionalFormatting. - /// </summary> - internal static class ExcelConditionalFormattingRuleFactory - { - public static ExcelConditionalFormattingRule Create( - eExcelConditionalFormattingRuleType type, +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// Factory class for ExcelConditionalFormatting. +/// </summary> +internal static class ExcelConditionalFormattingRuleFactory { + public static ExcelConditionalFormattingRule Create( + eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode) - { - Require.Argument(type); - Require.Argument(address).IsNotNull("address"); - Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); - Require.Argument(worksheet).IsNotNull("worksheet"); - - // According the conditional formatting rule type - switch (type) - { - case eExcelConditionalFormattingRuleType.AboveAverage: - return new ExcelConditionalFormattingAboveAverage( + ExcelWorksheet worksheet, + XmlNode itemElementNode) { + Require.Argument(type); + Require.Argument(address).IsNotNull("address"); + Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); + Require.Argument(worksheet).IsNotNull("worksheet"); + + // According the conditional formatting rule type + switch (type) { + case eExcelConditionalFormattingRuleType.AboveAverage: + return new ExcelConditionalFormattingAboveAverage( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.AboveOrEqualAverage: - return new ExcelConditionalFormattingAboveOrEqualAverage( + case eExcelConditionalFormattingRuleType.AboveOrEqualAverage: + return new ExcelConditionalFormattingAboveOrEqualAverage( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.BelowAverage: - return new ExcelConditionalFormattingBelowAverage( + case eExcelConditionalFormattingRuleType.BelowAverage: + return new ExcelConditionalFormattingBelowAverage( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.BelowOrEqualAverage: - return new ExcelConditionalFormattingBelowOrEqualAverage( + case eExcelConditionalFormattingRuleType.BelowOrEqualAverage: + return new ExcelConditionalFormattingBelowOrEqualAverage( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.AboveStdDev: - return new ExcelConditionalFormattingAboveStdDev( + case eExcelConditionalFormattingRuleType.AboveStdDev: + return new ExcelConditionalFormattingAboveStdDev( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.BelowStdDev: - return new ExcelConditionalFormattingBelowStdDev( + case eExcelConditionalFormattingRuleType.BelowStdDev: + return new ExcelConditionalFormattingBelowStdDev( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Bottom: - return new ExcelConditionalFormattingBottom( + case eExcelConditionalFormattingRuleType.Bottom: + return new ExcelConditionalFormattingBottom(address, priority, worksheet, itemElementNode); + + case eExcelConditionalFormattingRuleType.BottomPercent: + return new ExcelConditionalFormattingBottomPercent( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.BottomPercent: - return new ExcelConditionalFormattingBottomPercent( + case eExcelConditionalFormattingRuleType.Top: + return new ExcelConditionalFormattingTop(address, priority, worksheet, itemElementNode); + + case eExcelConditionalFormattingRuleType.TopPercent: + return new ExcelConditionalFormattingTopPercent( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Top: - return new ExcelConditionalFormattingTop( + case eExcelConditionalFormattingRuleType.Last7Days: + return new ExcelConditionalFormattingLast7Days( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.TopPercent: - return new ExcelConditionalFormattingTopPercent( + case eExcelConditionalFormattingRuleType.LastMonth: + return new ExcelConditionalFormattingLastMonth( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Last7Days: - return new ExcelConditionalFormattingLast7Days( + case eExcelConditionalFormattingRuleType.LastWeek: + return new ExcelConditionalFormattingLastWeek( address, priority, worksheet, itemElementNode); - - case eExcelConditionalFormattingRuleType.LastMonth: - return new ExcelConditionalFormattingLastMonth( + case eExcelConditionalFormattingRuleType.NextMonth: + return new ExcelConditionalFormattingNextMonth( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.LastWeek: - return new ExcelConditionalFormattingLastWeek( + case eExcelConditionalFormattingRuleType.NextWeek: + return new ExcelConditionalFormattingNextWeek( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.NextMonth: - return new ExcelConditionalFormattingNextMonth( + case eExcelConditionalFormattingRuleType.ThisMonth: + return new ExcelConditionalFormattingThisMonth( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.NextWeek: - return new ExcelConditionalFormattingNextWeek( + case eExcelConditionalFormattingRuleType.ThisWeek: + return new ExcelConditionalFormattingThisWeek( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.ThisMonth: - return new ExcelConditionalFormattingThisMonth( + case eExcelConditionalFormattingRuleType.Today: + return new ExcelConditionalFormattingToday(address, priority, worksheet, itemElementNode); + + case eExcelConditionalFormattingRuleType.Tomorrow: + return new ExcelConditionalFormattingTomorrow( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.ThisWeek: - return new ExcelConditionalFormattingThisWeek( + case eExcelConditionalFormattingRuleType.Yesterday: + return new ExcelConditionalFormattingYesterday( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Today: - return new ExcelConditionalFormattingToday( + case eExcelConditionalFormattingRuleType.BeginsWith: + return new ExcelConditionalFormattingBeginsWith( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Tomorrow: - return new ExcelConditionalFormattingTomorrow( + case eExcelConditionalFormattingRuleType.Between: + return new ExcelConditionalFormattingBetween(address, priority, worksheet, itemElementNode); + + case eExcelConditionalFormattingRuleType.ContainsBlanks: + return new ExcelConditionalFormattingContainsBlanks( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Yesterday: - return new ExcelConditionalFormattingYesterday( + case eExcelConditionalFormattingRuleType.ContainsErrors: + return new ExcelConditionalFormattingContainsErrors( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.BeginsWith: - return new ExcelConditionalFormattingBeginsWith( + case eExcelConditionalFormattingRuleType.ContainsText: + return new ExcelConditionalFormattingContainsText( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Between: - return new ExcelConditionalFormattingBetween( + case eExcelConditionalFormattingRuleType.DuplicateValues: + return new ExcelConditionalFormattingDuplicateValues( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.ContainsBlanks: - return new ExcelConditionalFormattingContainsBlanks( + case eExcelConditionalFormattingRuleType.EndsWith: + return new ExcelConditionalFormattingEndsWith( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.ContainsErrors: - return new ExcelConditionalFormattingContainsErrors( + case eExcelConditionalFormattingRuleType.Equal: + return new ExcelConditionalFormattingEqual(address, priority, worksheet, itemElementNode); + + case eExcelConditionalFormattingRuleType.Expression: + return new ExcelConditionalFormattingExpression( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.ContainsText: - return new ExcelConditionalFormattingContainsText( + case eExcelConditionalFormattingRuleType.GreaterThan: + return new ExcelConditionalFormattingGreaterThan( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.DuplicateValues: - return new ExcelConditionalFormattingDuplicateValues( + case eExcelConditionalFormattingRuleType.GreaterThanOrEqual: + return new ExcelConditionalFormattingGreaterThanOrEqual( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.EndsWith: - return new ExcelConditionalFormattingEndsWith( + case eExcelConditionalFormattingRuleType.LessThan: + return new ExcelConditionalFormattingLessThan( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Equal: - return new ExcelConditionalFormattingEqual( + case eExcelConditionalFormattingRuleType.LessThanOrEqual: + return new ExcelConditionalFormattingLessThanOrEqual( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.Expression: - return new ExcelConditionalFormattingExpression( + case eExcelConditionalFormattingRuleType.NotBetween: + return new ExcelConditionalFormattingNotBetween( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.GreaterThan: - return new ExcelConditionalFormattingGreaterThan( + case eExcelConditionalFormattingRuleType.NotContainsBlanks: + return new ExcelConditionalFormattingNotContainsBlanks( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.GreaterThanOrEqual: - return new ExcelConditionalFormattingGreaterThanOrEqual( + case eExcelConditionalFormattingRuleType.NotContainsErrors: + return new ExcelConditionalFormattingNotContainsErrors( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.LessThan: - return new ExcelConditionalFormattingLessThan( + case eExcelConditionalFormattingRuleType.NotContainsText: + return new ExcelConditionalFormattingNotContainsText( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.LessThanOrEqual: - return new ExcelConditionalFormattingLessThanOrEqual( + case eExcelConditionalFormattingRuleType.NotEqual: + return new ExcelConditionalFormattingNotEqual( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.NotBetween: - return new ExcelConditionalFormattingNotBetween( + case eExcelConditionalFormattingRuleType.UniqueValues: + return new ExcelConditionalFormattingUniqueValues( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.NotContainsBlanks: - return new ExcelConditionalFormattingNotContainsBlanks( + case eExcelConditionalFormattingRuleType.ThreeColorScale: + return new ExcelConditionalFormattingThreeColorScale( address, priority, worksheet, itemElementNode); - case eExcelConditionalFormattingRuleType.NotContainsErrors: - return new ExcelConditionalFormattingNotContainsErrors( + case eExcelConditionalFormattingRuleType.TwoColorScale: + return new ExcelConditionalFormattingTwoColorScale( address, priority, worksheet, itemElementNode); - - case eExcelConditionalFormattingRuleType.NotContainsText: - return new ExcelConditionalFormattingNotContainsText( - address, - priority, - worksheet, - itemElementNode); - - case eExcelConditionalFormattingRuleType.NotEqual: - return new ExcelConditionalFormattingNotEqual( - address, - priority, - worksheet, - itemElementNode); - - case eExcelConditionalFormattingRuleType.UniqueValues: - return new ExcelConditionalFormattingUniqueValues( - address, - priority, - worksheet, - itemElementNode); - - case eExcelConditionalFormattingRuleType.ThreeColorScale: - return new ExcelConditionalFormattingThreeColorScale( - address, - priority, - worksheet, - itemElementNode); - - case eExcelConditionalFormattingRuleType.TwoColorScale: - return new ExcelConditionalFormattingTwoColorScale( - address, - priority, - worksheet, - itemElementNode); - case eExcelConditionalFormattingRuleType.ThreeIconSet: - return new ExcelConditionalFormattingThreeIconSet( + case eExcelConditionalFormattingRuleType.ThreeIconSet: + return new ExcelConditionalFormattingThreeIconSet( address, priority, worksheet, itemElementNode, null); - case eExcelConditionalFormattingRuleType.FourIconSet: - return new ExcelConditionalFormattingFourIconSet( + case eExcelConditionalFormattingRuleType.FourIconSet: + return new ExcelConditionalFormattingFourIconSet( address, priority, worksheet, itemElementNode, null); - case eExcelConditionalFormattingRuleType.FiveIconSet: - return new ExcelConditionalFormattingFiveIconSet( + case eExcelConditionalFormattingRuleType.FiveIconSet: + return new ExcelConditionalFormattingFiveIconSet( address, priority, worksheet, itemElementNode, null); - case eExcelConditionalFormattingRuleType.DataBar: - return new ExcelConditionalFormattingDataBar( + case eExcelConditionalFormattingRuleType.DataBar: + return new ExcelConditionalFormattingDataBar( eExcelConditionalFormattingRuleType.DataBar, address, priority, @@ -375,14 +348,12 @@ itemElementNode, null); + //TODO: Add DataBar + } - //TODO: Add DataBar - } - - throw new InvalidOperationException( + throw new InvalidOperationException( string.Format( - ExcelConditionalFormattingConstants.Errors.NonSupportedRuleType, - type.ToString())); - } - } -} \ No newline at end of file + ExcelConditionalFormattingConstants.Errors._nonSupportedRuleType, + type.ToString())); + } +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs index 488dafa..b1c6b32 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingRuleType.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,527 +13,483 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// Functions related to the ExcelConditionalFormattingRule +/// </summary> +internal static class ExcelConditionalFormattingRuleType { /// <summary> - /// Functions related to the ExcelConditionalFormattingRule + /// /// </summary> - internal static class ExcelConditionalFormattingRuleType - { - /// <summary> - /// - /// </summary> - /// <param name="attribute"></param> - /// <param name="topNode"></param> - /// <param name="nameSpaceManager"></param> - /// <returns></returns> - internal static eExcelConditionalFormattingRuleType GetTypeByAttrbiute( + /// <param name="attribute"></param> + /// <param name="topNode"></param> + /// <param name="nameSpaceManager"></param> + /// <returns></returns> + internal static eExcelConditionalFormattingRuleType GetTypeByAttrbiute( string attribute, XmlNode topNode, - XmlNamespaceManager nameSpaceManager) - { - switch (attribute) - { - case ExcelConditionalFormattingConstants.RuleType.AboveAverage: - return GetAboveAverageType( - topNode, - nameSpaceManager); + XmlNamespaceManager nameSpaceManager) { + switch (attribute) { + case ExcelConditionalFormattingConstants.RuleType._aboveAverage: + return GetAboveAverageType(topNode, nameSpaceManager); - case ExcelConditionalFormattingConstants.RuleType.Top10: - return GetTop10Type( - topNode, - nameSpaceManager); + case ExcelConditionalFormattingConstants.RuleType._top10: + return GetTop10Type(topNode, nameSpaceManager); - case ExcelConditionalFormattingConstants.RuleType.TimePeriod: - return GetTimePeriodType( - topNode, - nameSpaceManager); - case ExcelConditionalFormattingConstants.RuleType.CellIs: - return GetCellIs((XmlElement)topNode); - case ExcelConditionalFormattingConstants.RuleType.BeginsWith: - return eExcelConditionalFormattingRuleType.BeginsWith; + case ExcelConditionalFormattingConstants.RuleType._timePeriod: + return GetTimePeriodType(topNode, nameSpaceManager); + case ExcelConditionalFormattingConstants.RuleType._cellIs: + return GetCellIs((XmlElement)topNode); + case ExcelConditionalFormattingConstants.RuleType._beginsWith: + return eExcelConditionalFormattingRuleType.BeginsWith; - //case ExcelConditionalFormattingConstants.RuleType.Between: - // return eExcelConditionalFormattingRuleType.Between; + //case ExcelConditionalFormattingConstants.RuleType.Between: + // return eExcelConditionalFormattingRuleType.Between; - case ExcelConditionalFormattingConstants.RuleType.ContainsBlanks: - return eExcelConditionalFormattingRuleType.ContainsBlanks; + case ExcelConditionalFormattingConstants.RuleType._containsBlanks: + return eExcelConditionalFormattingRuleType.ContainsBlanks; - case ExcelConditionalFormattingConstants.RuleType.ContainsErrors: - return eExcelConditionalFormattingRuleType.ContainsErrors; + case ExcelConditionalFormattingConstants.RuleType._containsErrors: + return eExcelConditionalFormattingRuleType.ContainsErrors; - case ExcelConditionalFormattingConstants.RuleType.ContainsText: - return eExcelConditionalFormattingRuleType.ContainsText; + case ExcelConditionalFormattingConstants.RuleType._containsText: + return eExcelConditionalFormattingRuleType.ContainsText; - case ExcelConditionalFormattingConstants.RuleType.DuplicateValues: - return eExcelConditionalFormattingRuleType.DuplicateValues; + case ExcelConditionalFormattingConstants.RuleType._duplicateValues: + return eExcelConditionalFormattingRuleType.DuplicateValues; - case ExcelConditionalFormattingConstants.RuleType.EndsWith: - return eExcelConditionalFormattingRuleType.EndsWith; + case ExcelConditionalFormattingConstants.RuleType._endsWith: + return eExcelConditionalFormattingRuleType.EndsWith; - //case ExcelConditionalFormattingConstants.RuleType.Equal: - // return eExcelConditionalFormattingRuleType.Equal; + //case ExcelConditionalFormattingConstants.RuleType.Equal: + // return eExcelConditionalFormattingRuleType.Equal; - case ExcelConditionalFormattingConstants.RuleType.Expression: - return eExcelConditionalFormattingRuleType.Expression; + case ExcelConditionalFormattingConstants.RuleType._expression: + return eExcelConditionalFormattingRuleType.Expression; - //case ExcelConditionalFormattingConstants.RuleType.GreaterThan: - // return eExcelConditionalFormattingRuleType.GreaterThan; + //case ExcelConditionalFormattingConstants.RuleType.GreaterThan: + // return eExcelConditionalFormattingRuleType.GreaterThan; - //case ExcelConditionalFormattingConstants.RuleType.GreaterThanOrEqual: - // return eExcelConditionalFormattingRuleType.GreaterThanOrEqual; + //case ExcelConditionalFormattingConstants.RuleType.GreaterThanOrEqual: + // return eExcelConditionalFormattingRuleType.GreaterThanOrEqual; - //case ExcelConditionalFormattingConstants.RuleType.LessThan: - // return eExcelConditionalFormattingRuleType.LessThan; + //case ExcelConditionalFormattingConstants.RuleType.LessThan: + // return eExcelConditionalFormattingRuleType.LessThan; - //case ExcelConditionalFormattingConstants.RuleType.LessThanOrEqual: - // return eExcelConditionalFormattingRuleType.LessThanOrEqual; + //case ExcelConditionalFormattingConstants.RuleType.LessThanOrEqual: + // return eExcelConditionalFormattingRuleType.LessThanOrEqual; - //case ExcelConditionalFormattingConstants.RuleType.NotBetween: - // return eExcelConditionalFormattingRuleType.NotBetween; + //case ExcelConditionalFormattingConstants.RuleType.NotBetween: + // return eExcelConditionalFormattingRuleType.NotBetween; - case ExcelConditionalFormattingConstants.RuleType.NotContainsBlanks: - return eExcelConditionalFormattingRuleType.NotContainsBlanks; + case ExcelConditionalFormattingConstants.RuleType._notContainsBlanks: + return eExcelConditionalFormattingRuleType.NotContainsBlanks; - case ExcelConditionalFormattingConstants.RuleType.NotContainsErrors: - return eExcelConditionalFormattingRuleType.NotContainsErrors; + case ExcelConditionalFormattingConstants.RuleType._notContainsErrors: + return eExcelConditionalFormattingRuleType.NotContainsErrors; - case ExcelConditionalFormattingConstants.RuleType.NotContainsText: - return eExcelConditionalFormattingRuleType.NotContainsText; + case ExcelConditionalFormattingConstants.RuleType._notContainsText: + return eExcelConditionalFormattingRuleType.NotContainsText; - //case ExcelConditionalFormattingConstants.RuleType.NotEqual: - // return eExcelConditionalFormattingRuleType.NotEqual; + //case ExcelConditionalFormattingConstants.RuleType.NotEqual: + // return eExcelConditionalFormattingRuleType.NotEqual; - case ExcelConditionalFormattingConstants.RuleType.UniqueValues: - return eExcelConditionalFormattingRuleType.UniqueValues; + case ExcelConditionalFormattingConstants.RuleType._uniqueValues: + return eExcelConditionalFormattingRuleType.UniqueValues; - case ExcelConditionalFormattingConstants.RuleType.ColorScale: - return GetColorScaleType( - topNode, - nameSpaceManager); - case ExcelConditionalFormattingConstants.RuleType.IconSet: - return GetIconSetType(topNode, nameSpaceManager); - case ExcelConditionalFormattingConstants.RuleType.DataBar: - return eExcelConditionalFormattingRuleType.DataBar; - } - - throw new Exception( - ExcelConditionalFormattingConstants.Errors.UnexpectedRuleTypeAttribute); + case ExcelConditionalFormattingConstants.RuleType._colorScale: + return GetColorScaleType(topNode, nameSpaceManager); + case ExcelConditionalFormattingConstants.RuleType._iconSet: + return GetIconSetType(topNode, nameSpaceManager); + case ExcelConditionalFormattingConstants.RuleType._dataBar: + return eExcelConditionalFormattingRuleType.DataBar; } - private static eExcelConditionalFormattingRuleType GetCellIs(XmlElement node) - { - switch(node.GetAttribute("operator")) - { - case ExcelConditionalFormattingConstants.Operators.BeginsWith: - return eExcelConditionalFormattingRuleType.BeginsWith; - case ExcelConditionalFormattingConstants.Operators.Between: - return eExcelConditionalFormattingRuleType.Between; + throw new(ExcelConditionalFormattingConstants.Errors._unexpectedRuleTypeAttribute); + } - case ExcelConditionalFormattingConstants.Operators.ContainsText: - return eExcelConditionalFormattingRuleType.ContainsText; + private static eExcelConditionalFormattingRuleType GetCellIs(XmlElement node) { + switch (node.GetAttribute("operator")) { + case ExcelConditionalFormattingConstants.Operators._beginsWith: + return eExcelConditionalFormattingRuleType.BeginsWith; + case ExcelConditionalFormattingConstants.Operators._between: + return eExcelConditionalFormattingRuleType.Between; - case ExcelConditionalFormattingConstants.Operators.EndsWith: - return eExcelConditionalFormattingRuleType.EndsWith; + case ExcelConditionalFormattingConstants.Operators._containsText: + return eExcelConditionalFormattingRuleType.ContainsText; - case ExcelConditionalFormattingConstants.Operators.Equal: - return eExcelConditionalFormattingRuleType.Equal; + case ExcelConditionalFormattingConstants.Operators._endsWith: + return eExcelConditionalFormattingRuleType.EndsWith; - case ExcelConditionalFormattingConstants.Operators.GreaterThan: - return eExcelConditionalFormattingRuleType.GreaterThan; + case ExcelConditionalFormattingConstants.Operators._equal: + return eExcelConditionalFormattingRuleType.Equal; - case ExcelConditionalFormattingConstants.Operators.GreaterThanOrEqual: - return eExcelConditionalFormattingRuleType.GreaterThanOrEqual; + case ExcelConditionalFormattingConstants.Operators._greaterThan: + return eExcelConditionalFormattingRuleType.GreaterThan; - case ExcelConditionalFormattingConstants.Operators.LessThan: - return eExcelConditionalFormattingRuleType.LessThan; + case ExcelConditionalFormattingConstants.Operators._greaterThanOrEqual: + return eExcelConditionalFormattingRuleType.GreaterThanOrEqual; - case ExcelConditionalFormattingConstants.Operators.LessThanOrEqual: - return eExcelConditionalFormattingRuleType.LessThanOrEqual; + case ExcelConditionalFormattingConstants.Operators._lessThan: + return eExcelConditionalFormattingRuleType.LessThan; - case ExcelConditionalFormattingConstants.Operators.NotBetween: - return eExcelConditionalFormattingRuleType.NotBetween; + case ExcelConditionalFormattingConstants.Operators._lessThanOrEqual: + return eExcelConditionalFormattingRuleType.LessThanOrEqual; - case ExcelConditionalFormattingConstants.Operators.NotContains: - return eExcelConditionalFormattingRuleType.NotContains; + case ExcelConditionalFormattingConstants.Operators._notBetween: + return eExcelConditionalFormattingRuleType.NotBetween; - case ExcelConditionalFormattingConstants.Operators.NotEqual: - return eExcelConditionalFormattingRuleType.NotEqual; - default: - throw new Exception( - ExcelConditionalFormattingConstants.Errors.UnexistentOperatorTypeAttribute); - } - } - private static eExcelConditionalFormattingRuleType GetIconSetType(XmlNode topNode, XmlNamespaceManager nameSpaceManager) - { - var node = topNode.SelectSingleNode("d:iconSet/@iconSet", nameSpaceManager); - if (node == null) - { - return eExcelConditionalFormattingRuleType.ThreeIconSet; - } - else - { - var v = node.Value; + case ExcelConditionalFormattingConstants.Operators._notContains: + return eExcelConditionalFormattingRuleType.NotContains; - if (v[0] == '3') - { - return eExcelConditionalFormattingRuleType.ThreeIconSet; - } - else if (v[0] == '4') - { - return eExcelConditionalFormattingRuleType.FourIconSet; - } - else - { - return eExcelConditionalFormattingRuleType.FiveIconSet; - } - } - } - - /// <summary> - /// Get the "colorScale" rule type according to the number of "cfvo" and "color" nodes. - /// If we have excatly 2 "cfvo" and "color" childs, then we return "twoColorScale" - /// </summary> - /// <returns>TwoColorScale or ThreeColorScale</returns> - internal static eExcelConditionalFormattingRuleType GetColorScaleType( - XmlNode topNode, - XmlNamespaceManager nameSpaceManager) - { - // Get the <cfvo> nodes - var cfvoNodes = topNode.SelectNodes( - string.Format( - "{0}/{1}", - ExcelConditionalFormattingConstants.Paths.ColorScale, - ExcelConditionalFormattingConstants.Paths.Cfvo), - nameSpaceManager); - - // Get the <color> nodes - var colorNodes = topNode.SelectNodes( - string.Format( - "{0}/{1}", - ExcelConditionalFormattingConstants.Paths.ColorScale, - ExcelConditionalFormattingConstants.Paths.Color), - nameSpaceManager); - - // We determine if it is "TwoColorScale" or "ThreeColorScale" by the - // number of <cfvo> and <color> inside the <colorScale> node - if ((cfvoNodes == null) || (cfvoNodes.Count < 2) || (cfvoNodes.Count > 3) - || (colorNodes == null) || (colorNodes.Count < 2) || (colorNodes.Count > 3) - || (cfvoNodes.Count != colorNodes.Count)) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.WrongNumberCfvoColorNodes); - } - - // Return the corresponding rule type (TwoColorScale or ThreeColorScale) - return (cfvoNodes.Count == 2) - ? eExcelConditionalFormattingRuleType.TwoColorScale - : eExcelConditionalFormattingRuleType.ThreeColorScale; - } - - /// <summary> - /// Get the "aboveAverage" rule type according to the follwoing attributes: - /// "AboveAverage", "EqualAverage" and "StdDev". - /// - /// @StdDev greater than "0" == AboveStdDev - /// @StdDev less than "0" == BelowStdDev - /// @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage - /// @AboveAverage = "1"/null and @EqualAverage = "1" == AboveOrEqualAverage - /// @AboveAverage = "0" and @EqualAverage = "0"/null == BelowAverage - /// @AboveAverage = "0" and @EqualAverage = "1" == BelowOrEqualAverage - /// /// </summary> - /// <returns>AboveAverage, AboveOrEqualAverage, BelowAverage or BelowOrEqualAverage</returns> - internal static eExcelConditionalFormattingRuleType GetAboveAverageType( - XmlNode topNode, - XmlNamespaceManager nameSpaceManager) - { - // Get @StdDev attribute - int? stdDev = ExcelConditionalFormattingHelper.GetAttributeIntNullable( - topNode, - ExcelConditionalFormattingConstants.Attributes.StdDev); - - if (stdDev > 0) - { - // @StdDev > "0" --> AboveStdDev - return eExcelConditionalFormattingRuleType.AboveStdDev; - } - - if (stdDev < 0) - { - // @StdDev < "0" --> BelowStdDev - return eExcelConditionalFormattingRuleType.BelowStdDev; - } - - // Get @AboveAverage attribute - bool? isAboveAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( - topNode, - ExcelConditionalFormattingConstants.Attributes.AboveAverage); - - // Get @EqualAverage attribute - bool? isEqualAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( - topNode, - ExcelConditionalFormattingConstants.Attributes.EqualAverage); - - if ((isAboveAverage == null) || (isAboveAverage == true)) - { - if (isEqualAverage == true) - { - // @AboveAverage = "1"/null and @EqualAverage = "1" == AboveOrEqualAverage - return eExcelConditionalFormattingRuleType.AboveOrEqualAverage; - } - - // @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage - return eExcelConditionalFormattingRuleType.AboveAverage; - } - - if (isEqualAverage == true) - { - // @AboveAverage = "0" and @EqualAverage = "1" == BelowOrEqualAverage - return eExcelConditionalFormattingRuleType.BelowOrEqualAverage; - } - - // @AboveAverage = "0" and @EqualAverage = "0"/null == BelowAverage - return eExcelConditionalFormattingRuleType.BelowAverage; - } - - /// <summary> - /// Get the "top10" rule type according to the follwoing attributes: - /// "Bottom" and "Percent" - /// - /// @Bottom = "1" and @Percent = "0"/null == Bottom - /// @Bottom = "1" and @Percent = "1" == BottomPercent - /// @Bottom = "0"/null and @Percent = "0"/null == Top - /// @Bottom = "0"/null and @Percent = "1" == TopPercent - /// /// </summary> - /// <returns>Top, TopPercent, Bottom or BottomPercent</returns> - public static eExcelConditionalFormattingRuleType GetTop10Type( - XmlNode topNode, - XmlNamespaceManager nameSpaceManager) - { - // Get @Bottom attribute - bool? isBottom = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( - topNode, - ExcelConditionalFormattingConstants.Attributes.Bottom); - - // Get @Percent attribute - bool? isPercent = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( - topNode, - ExcelConditionalFormattingConstants.Attributes.Percent); - - if (isBottom == true) - { - if (isPercent == true) - { - // @Bottom = "1" and @Percent = "1" == BottomPercent - return eExcelConditionalFormattingRuleType.BottomPercent; - } - - // @Bottom = "1" and @Percent = "0"/null == Bottom - return eExcelConditionalFormattingRuleType.Bottom; - } - - if (isPercent == true) - { - // @Bottom = "0"/null and @Percent = "1" == TopPercent - return eExcelConditionalFormattingRuleType.TopPercent; - } - - // @Bottom = "0"/null and @Percent = "0"/null == Top - return eExcelConditionalFormattingRuleType.Top; - } - - /// <summary> - /// Get the "timePeriod" rule type according to "TimePeriod" attribute. - /// /// </summary> - /// <returns>Last7Days, LastMonth etc.</returns> - public static eExcelConditionalFormattingRuleType GetTimePeriodType( - XmlNode topNode, - XmlNamespaceManager nameSpaceManager) - { - eExcelConditionalFormattingTimePeriodType timePeriod = ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute( - ExcelConditionalFormattingHelper.GetAttributeString( - topNode, - ExcelConditionalFormattingConstants.Attributes.TimePeriod)); - - switch (timePeriod) - { - case eExcelConditionalFormattingTimePeriodType.Last7Days: - return eExcelConditionalFormattingRuleType.Last7Days; - - case eExcelConditionalFormattingTimePeriodType.LastMonth: - return eExcelConditionalFormattingRuleType.LastMonth; - - case eExcelConditionalFormattingTimePeriodType.LastWeek: - return eExcelConditionalFormattingRuleType.LastWeek; - - case eExcelConditionalFormattingTimePeriodType.NextMonth: - return eExcelConditionalFormattingRuleType.NextMonth; - - case eExcelConditionalFormattingTimePeriodType.NextWeek: - return eExcelConditionalFormattingRuleType.NextWeek; - - case eExcelConditionalFormattingTimePeriodType.ThisMonth: - return eExcelConditionalFormattingRuleType.ThisMonth; - - case eExcelConditionalFormattingTimePeriodType.ThisWeek: - return eExcelConditionalFormattingRuleType.ThisWeek; - - case eExcelConditionalFormattingTimePeriodType.Today: - return eExcelConditionalFormattingRuleType.Today; - - case eExcelConditionalFormattingTimePeriodType.Tomorrow: - return eExcelConditionalFormattingRuleType.Tomorrow; - - case eExcelConditionalFormattingTimePeriodType.Yesterday: - return eExcelConditionalFormattingRuleType.Yesterday; - } - - throw new Exception( - ExcelConditionalFormattingConstants.Errors.UnexistentTimePeriodTypeAttribute); - } - - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <returns></returns> - public static string GetAttributeByType( - eExcelConditionalFormattingRuleType type) - { - switch (type) - { - case eExcelConditionalFormattingRuleType.AboveAverage: - case eExcelConditionalFormattingRuleType.AboveOrEqualAverage: - case eExcelConditionalFormattingRuleType.BelowAverage: - case eExcelConditionalFormattingRuleType.BelowOrEqualAverage: - case eExcelConditionalFormattingRuleType.AboveStdDev: - case eExcelConditionalFormattingRuleType.BelowStdDev: - return ExcelConditionalFormattingConstants.RuleType.AboveAverage; - - case eExcelConditionalFormattingRuleType.Bottom: - case eExcelConditionalFormattingRuleType.BottomPercent: - case eExcelConditionalFormattingRuleType.Top: - case eExcelConditionalFormattingRuleType.TopPercent: - return ExcelConditionalFormattingConstants.RuleType.Top10; - - case eExcelConditionalFormattingRuleType.Last7Days: - case eExcelConditionalFormattingRuleType.LastMonth: - case eExcelConditionalFormattingRuleType.LastWeek: - case eExcelConditionalFormattingRuleType.NextMonth: - case eExcelConditionalFormattingRuleType.NextWeek: - case eExcelConditionalFormattingRuleType.ThisMonth: - case eExcelConditionalFormattingRuleType.ThisWeek: - case eExcelConditionalFormattingRuleType.Today: - case eExcelConditionalFormattingRuleType.Tomorrow: - case eExcelConditionalFormattingRuleType.Yesterday: - return ExcelConditionalFormattingConstants.RuleType.TimePeriod; - - case eExcelConditionalFormattingRuleType.Between: - case eExcelConditionalFormattingRuleType.Equal: - case eExcelConditionalFormattingRuleType.GreaterThan: - case eExcelConditionalFormattingRuleType.GreaterThanOrEqual: - case eExcelConditionalFormattingRuleType.LessThan: - case eExcelConditionalFormattingRuleType.LessThanOrEqual: - case eExcelConditionalFormattingRuleType.NotBetween: - case eExcelConditionalFormattingRuleType.NotEqual: - return ExcelConditionalFormattingConstants.RuleType.CellIs; - - case eExcelConditionalFormattingRuleType.ThreeIconSet: - case eExcelConditionalFormattingRuleType.FourIconSet: - case eExcelConditionalFormattingRuleType.FiveIconSet: - return ExcelConditionalFormattingConstants.RuleType.IconSet; - - case eExcelConditionalFormattingRuleType.ThreeColorScale: - case eExcelConditionalFormattingRuleType.TwoColorScale: - return ExcelConditionalFormattingConstants.RuleType.ColorScale; - - case eExcelConditionalFormattingRuleType.BeginsWith: - return ExcelConditionalFormattingConstants.RuleType.BeginsWith; - - case eExcelConditionalFormattingRuleType.ContainsBlanks: - return ExcelConditionalFormattingConstants.RuleType.ContainsBlanks; - - case eExcelConditionalFormattingRuleType.ContainsErrors: - return ExcelConditionalFormattingConstants.RuleType.ContainsErrors; - - case eExcelConditionalFormattingRuleType.ContainsText: - return ExcelConditionalFormattingConstants.RuleType.ContainsText; - - case eExcelConditionalFormattingRuleType.DuplicateValues: - return ExcelConditionalFormattingConstants.RuleType.DuplicateValues; - - case eExcelConditionalFormattingRuleType.EndsWith: - return ExcelConditionalFormattingConstants.RuleType.EndsWith; - - case eExcelConditionalFormattingRuleType.Expression: - return ExcelConditionalFormattingConstants.RuleType.Expression; - - case eExcelConditionalFormattingRuleType.NotContainsBlanks: - return ExcelConditionalFormattingConstants.RuleType.NotContainsBlanks; - - case eExcelConditionalFormattingRuleType.NotContainsErrors: - return ExcelConditionalFormattingConstants.RuleType.NotContainsErrors; - - case eExcelConditionalFormattingRuleType.NotContainsText: - return ExcelConditionalFormattingConstants.RuleType.NotContainsText; - - case eExcelConditionalFormattingRuleType.UniqueValues: - return ExcelConditionalFormattingConstants.RuleType.UniqueValues; - - case eExcelConditionalFormattingRuleType.DataBar: - return ExcelConditionalFormattingConstants.RuleType.DataBar; - } - - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingRuleType); - } - - /// <summary> - /// Return cfvo §18.3.1.11 parent according to the rule type - /// </summary> - /// <param name="type"></param> - /// <returns></returns> - public static string GetCfvoParentPathByType( - eExcelConditionalFormattingRuleType type) - { - switch (type) - { - case eExcelConditionalFormattingRuleType.TwoColorScale: - case eExcelConditionalFormattingRuleType.ThreeColorScale: - return ExcelConditionalFormattingConstants.Paths.ColorScale; - - case eExcelConditionalFormattingRuleType.ThreeIconSet: - case eExcelConditionalFormattingRuleType.FourIconSet: - case eExcelConditionalFormattingRuleType.FiveIconSet: - return ExcelConditionalFormattingConstants.RuleType.IconSet; - - case eExcelConditionalFormattingRuleType.DataBar: - return ExcelConditionalFormattingConstants.RuleType.DataBar; - } - - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingRuleType); + case ExcelConditionalFormattingConstants.Operators._notEqual: + return eExcelConditionalFormattingRuleType.NotEqual; + default: + throw new(ExcelConditionalFormattingConstants.Errors._unexistentOperatorTypeAttribute); } } -} \ No newline at end of file + + private static eExcelConditionalFormattingRuleType GetIconSetType( + XmlNode topNode, + XmlNamespaceManager nameSpaceManager) { + var node = topNode.SelectSingleNode("d:iconSet/@iconSet", nameSpaceManager); + if (node == null) { + return eExcelConditionalFormattingRuleType.ThreeIconSet; + } + var v = node.Value; + + if (v[0] == '3') { + return eExcelConditionalFormattingRuleType.ThreeIconSet; + } + if (v[0] == '4') { + return eExcelConditionalFormattingRuleType.FourIconSet; + } + return eExcelConditionalFormattingRuleType.FiveIconSet; + } + + /// <summary> + /// Get the "colorScale" rule type according to the number of "cfvo" and "color" nodes. + /// If we have excatly 2 "cfvo" and "color" childs, then we return "twoColorScale" + /// </summary> + /// <returns>TwoColorScale or ThreeColorScale</returns> + internal static eExcelConditionalFormattingRuleType GetColorScaleType( + XmlNode topNode, + XmlNamespaceManager nameSpaceManager) { + // Get the <cfvo> nodes + var cfvoNodes = topNode.SelectNodes( + string.Format( + "{0}/{1}", + ExcelConditionalFormattingConstants.Paths._colorScale, + ExcelConditionalFormattingConstants.Paths._cfvo), + nameSpaceManager); + + // Get the <color> nodes + var colorNodes = topNode.SelectNodes( + string.Format( + "{0}/{1}", + ExcelConditionalFormattingConstants.Paths._colorScale, + ExcelConditionalFormattingConstants.Paths._color), + nameSpaceManager); + + // We determine if it is "TwoColorScale" or "ThreeColorScale" by the + // number of <cfvo> and <color> inside the <colorScale> node + if ((cfvoNodes == null) + || (cfvoNodes.Count < 2) + || (cfvoNodes.Count > 3) + || (colorNodes == null) + || (colorNodes.Count < 2) + || (colorNodes.Count > 3) + || (cfvoNodes.Count != colorNodes.Count)) { + throw new(ExcelConditionalFormattingConstants.Errors._wrongNumberCfvoColorNodes); + } + + // Return the corresponding rule type (TwoColorScale or ThreeColorScale) + return (cfvoNodes.Count == 2) + ? eExcelConditionalFormattingRuleType.TwoColorScale + : eExcelConditionalFormattingRuleType.ThreeColorScale; + } + + /// <summary> + /// Get the "aboveAverage" rule type according to the follwoing attributes: + /// "AboveAverage", "EqualAverage" and "StdDev". + /// + /// @StdDev greater than "0" == AboveStdDev + /// @StdDev less than "0" == BelowStdDev + /// @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage + /// @AboveAverage = "1"/null and @EqualAverage = "1" == AboveOrEqualAverage + /// @AboveAverage = "0" and @EqualAverage = "0"/null == BelowAverage + /// @AboveAverage = "0" and @EqualAverage = "1" == BelowOrEqualAverage + /// /// </summary> + /// <returns>AboveAverage, AboveOrEqualAverage, BelowAverage or BelowOrEqualAverage</returns> + internal static eExcelConditionalFormattingRuleType GetAboveAverageType( + XmlNode topNode, + XmlNamespaceManager nameSpaceManager) { + // Get @StdDev attribute + int? stdDev = ExcelConditionalFormattingHelper.GetAttributeIntNullable( + topNode, + ExcelConditionalFormattingConstants.Attributes._stdDev); + + if (stdDev > 0) { + // @StdDev > "0" --> AboveStdDev + return eExcelConditionalFormattingRuleType.AboveStdDev; + } + + if (stdDev < 0) { + // @StdDev < "0" --> BelowStdDev + return eExcelConditionalFormattingRuleType.BelowStdDev; + } + + // Get @AboveAverage attribute + bool? isAboveAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( + topNode, + ExcelConditionalFormattingConstants.Attributes._aboveAverage); + + // Get @EqualAverage attribute + bool? isEqualAverage = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( + topNode, + ExcelConditionalFormattingConstants.Attributes._equalAverage); + + if ((isAboveAverage == null) || (isAboveAverage == true)) { + if (isEqualAverage == true) { + // @AboveAverage = "1"/null and @EqualAverage = "1" == AboveOrEqualAverage + return eExcelConditionalFormattingRuleType.AboveOrEqualAverage; + } + + // @AboveAverage = "1"/null and @EqualAverage = "0"/null == AboveAverage + return eExcelConditionalFormattingRuleType.AboveAverage; + } + + if (isEqualAverage == true) { + // @AboveAverage = "0" and @EqualAverage = "1" == BelowOrEqualAverage + return eExcelConditionalFormattingRuleType.BelowOrEqualAverage; + } + + // @AboveAverage = "0" and @EqualAverage = "0"/null == BelowAverage + return eExcelConditionalFormattingRuleType.BelowAverage; + } + + /// <summary> + /// Get the "top10" rule type according to the follwoing attributes: + /// "Bottom" and "Percent" + /// + /// @Bottom = "1" and @Percent = "0"/null == Bottom + /// @Bottom = "1" and @Percent = "1" == BottomPercent + /// @Bottom = "0"/null and @Percent = "0"/null == Top + /// @Bottom = "0"/null and @Percent = "1" == TopPercent + /// /// </summary> + /// <returns>Top, TopPercent, Bottom or BottomPercent</returns> + public static eExcelConditionalFormattingRuleType GetTop10Type( + XmlNode topNode, + XmlNamespaceManager nameSpaceManager) { + // Get @Bottom attribute + bool? isBottom = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( + topNode, + ExcelConditionalFormattingConstants.Attributes._bottom); + + // Get @Percent attribute + bool? isPercent = ExcelConditionalFormattingHelper.GetAttributeBoolNullable( + topNode, + ExcelConditionalFormattingConstants.Attributes._percent); + + if (isBottom == true) { + if (isPercent == true) { + // @Bottom = "1" and @Percent = "1" == BottomPercent + return eExcelConditionalFormattingRuleType.BottomPercent; + } + + // @Bottom = "1" and @Percent = "0"/null == Bottom + return eExcelConditionalFormattingRuleType.Bottom; + } + + if (isPercent == true) { + // @Bottom = "0"/null and @Percent = "1" == TopPercent + return eExcelConditionalFormattingRuleType.TopPercent; + } + + // @Bottom = "0"/null and @Percent = "0"/null == Top + return eExcelConditionalFormattingRuleType.Top; + } + + /// <summary> + /// Get the "timePeriod" rule type according to "TimePeriod" attribute. + /// /// </summary> + /// <returns>Last7Days, LastMonth etc.</returns> + public static eExcelConditionalFormattingRuleType GetTimePeriodType( + XmlNode topNode, + XmlNamespaceManager nameSpaceManager) { + eExcelConditionalFormattingTimePeriodType timePeriod = + ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute( + ExcelConditionalFormattingHelper.GetAttributeString( + topNode, + ExcelConditionalFormattingConstants.Attributes._timePeriod)); + + switch (timePeriod) { + case eExcelConditionalFormattingTimePeriodType.Last7Days: + return eExcelConditionalFormattingRuleType.Last7Days; + + case eExcelConditionalFormattingTimePeriodType.LastMonth: + return eExcelConditionalFormattingRuleType.LastMonth; + + case eExcelConditionalFormattingTimePeriodType.LastWeek: + return eExcelConditionalFormattingRuleType.LastWeek; + + case eExcelConditionalFormattingTimePeriodType.NextMonth: + return eExcelConditionalFormattingRuleType.NextMonth; + + case eExcelConditionalFormattingTimePeriodType.NextWeek: + return eExcelConditionalFormattingRuleType.NextWeek; + + case eExcelConditionalFormattingTimePeriodType.ThisMonth: + return eExcelConditionalFormattingRuleType.ThisMonth; + + case eExcelConditionalFormattingTimePeriodType.ThisWeek: + return eExcelConditionalFormattingRuleType.ThisWeek; + + case eExcelConditionalFormattingTimePeriodType.Today: + return eExcelConditionalFormattingRuleType.Today; + + case eExcelConditionalFormattingTimePeriodType.Tomorrow: + return eExcelConditionalFormattingRuleType.Tomorrow; + + case eExcelConditionalFormattingTimePeriodType.Yesterday: + return eExcelConditionalFormattingRuleType.Yesterday; + } + + throw new(ExcelConditionalFormattingConstants.Errors._unexistentTimePeriodTypeAttribute); + } + + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <returns></returns> + public static string GetAttributeByType(eExcelConditionalFormattingRuleType type) { + switch (type) { + case eExcelConditionalFormattingRuleType.AboveAverage: + case eExcelConditionalFormattingRuleType.AboveOrEqualAverage: + case eExcelConditionalFormattingRuleType.BelowAverage: + case eExcelConditionalFormattingRuleType.BelowOrEqualAverage: + case eExcelConditionalFormattingRuleType.AboveStdDev: + case eExcelConditionalFormattingRuleType.BelowStdDev: + return ExcelConditionalFormattingConstants.RuleType._aboveAverage; + + case eExcelConditionalFormattingRuleType.Bottom: + case eExcelConditionalFormattingRuleType.BottomPercent: + case eExcelConditionalFormattingRuleType.Top: + case eExcelConditionalFormattingRuleType.TopPercent: + return ExcelConditionalFormattingConstants.RuleType._top10; + + case eExcelConditionalFormattingRuleType.Last7Days: + case eExcelConditionalFormattingRuleType.LastMonth: + case eExcelConditionalFormattingRuleType.LastWeek: + case eExcelConditionalFormattingRuleType.NextMonth: + case eExcelConditionalFormattingRuleType.NextWeek: + case eExcelConditionalFormattingRuleType.ThisMonth: + case eExcelConditionalFormattingRuleType.ThisWeek: + case eExcelConditionalFormattingRuleType.Today: + case eExcelConditionalFormattingRuleType.Tomorrow: + case eExcelConditionalFormattingRuleType.Yesterday: + return ExcelConditionalFormattingConstants.RuleType._timePeriod; + + case eExcelConditionalFormattingRuleType.Between: + case eExcelConditionalFormattingRuleType.Equal: + case eExcelConditionalFormattingRuleType.GreaterThan: + case eExcelConditionalFormattingRuleType.GreaterThanOrEqual: + case eExcelConditionalFormattingRuleType.LessThan: + case eExcelConditionalFormattingRuleType.LessThanOrEqual: + case eExcelConditionalFormattingRuleType.NotBetween: + case eExcelConditionalFormattingRuleType.NotEqual: + return ExcelConditionalFormattingConstants.RuleType._cellIs; + + case eExcelConditionalFormattingRuleType.ThreeIconSet: + case eExcelConditionalFormattingRuleType.FourIconSet: + case eExcelConditionalFormattingRuleType.FiveIconSet: + return ExcelConditionalFormattingConstants.RuleType._iconSet; + + case eExcelConditionalFormattingRuleType.ThreeColorScale: + case eExcelConditionalFormattingRuleType.TwoColorScale: + return ExcelConditionalFormattingConstants.RuleType._colorScale; + + case eExcelConditionalFormattingRuleType.BeginsWith: + return ExcelConditionalFormattingConstants.RuleType._beginsWith; + + case eExcelConditionalFormattingRuleType.ContainsBlanks: + return ExcelConditionalFormattingConstants.RuleType._containsBlanks; + + case eExcelConditionalFormattingRuleType.ContainsErrors: + return ExcelConditionalFormattingConstants.RuleType._containsErrors; + + case eExcelConditionalFormattingRuleType.ContainsText: + return ExcelConditionalFormattingConstants.RuleType._containsText; + + case eExcelConditionalFormattingRuleType.DuplicateValues: + return ExcelConditionalFormattingConstants.RuleType._duplicateValues; + + case eExcelConditionalFormattingRuleType.EndsWith: + return ExcelConditionalFormattingConstants.RuleType._endsWith; + + case eExcelConditionalFormattingRuleType.Expression: + return ExcelConditionalFormattingConstants.RuleType._expression; + + case eExcelConditionalFormattingRuleType.NotContainsBlanks: + return ExcelConditionalFormattingConstants.RuleType._notContainsBlanks; + + case eExcelConditionalFormattingRuleType.NotContainsErrors: + return ExcelConditionalFormattingConstants.RuleType._notContainsErrors; + + case eExcelConditionalFormattingRuleType.NotContainsText: + return ExcelConditionalFormattingConstants.RuleType._notContainsText; + + case eExcelConditionalFormattingRuleType.UniqueValues: + return ExcelConditionalFormattingConstants.RuleType._uniqueValues; + + case eExcelConditionalFormattingRuleType.DataBar: + return ExcelConditionalFormattingConstants.RuleType._dataBar; + } + + throw new(ExcelConditionalFormattingConstants.Errors._missingRuleType); + } + + /// <summary> + /// Return cfvo §18.3.1.11 parent according to the rule type + /// </summary> + /// <param name="type"></param> + /// <returns></returns> + public static string GetCfvoParentPathByType(eExcelConditionalFormattingRuleType type) { + switch (type) { + case eExcelConditionalFormattingRuleType.TwoColorScale: + case eExcelConditionalFormattingRuleType.ThreeColorScale: + return ExcelConditionalFormattingConstants.Paths._colorScale; + + case eExcelConditionalFormattingRuleType.ThreeIconSet: + case eExcelConditionalFormattingRuleType.FourIconSet: + case eExcelConditionalFormattingRuleType.FiveIconSet: + return ExcelConditionalFormattingConstants.RuleType._iconSet; + + case eExcelConditionalFormattingRuleType.DataBar: + return ExcelConditionalFormattingConstants.RuleType._dataBar; + } + + throw new(ExcelConditionalFormattingConstants.Errors._missingRuleType); + } +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs index 75d8ab2..2051e7b 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingTimePeriodType.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,121 +13,109 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-17 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// Functions related to the <see cref="ExcelConditionalFormattingTimePeriodType"/> - /// </summary> - internal static class ExcelConditionalFormattingTimePeriodType - { - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <returns></returns> - public static string GetAttributeByType( - eExcelConditionalFormattingTimePeriodType type) - { - switch (type) - { - case eExcelConditionalFormattingTimePeriodType.Last7Days: - return ExcelConditionalFormattingConstants.TimePeriods.Last7Days; +namespace OfficeOpenXml.ConditionalFormatting; - case eExcelConditionalFormattingTimePeriodType.LastMonth: - return ExcelConditionalFormattingConstants.TimePeriods.LastMonth; +/// <summary> +/// Functions related to the <see cref="ExcelConditionalFormattingTimePeriodType"/> +/// </summary> +internal static class ExcelConditionalFormattingTimePeriodType { + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <returns></returns> + public static string GetAttributeByType(eExcelConditionalFormattingTimePeriodType type) { + switch (type) { + case eExcelConditionalFormattingTimePeriodType.Last7Days: + return ExcelConditionalFormattingConstants.TimePeriods._last7Days; - case eExcelConditionalFormattingTimePeriodType.LastWeek: - return ExcelConditionalFormattingConstants.TimePeriods.LastWeek; + case eExcelConditionalFormattingTimePeriodType.LastMonth: + return ExcelConditionalFormattingConstants.TimePeriods._lastMonth; - case eExcelConditionalFormattingTimePeriodType.NextMonth: - return ExcelConditionalFormattingConstants.TimePeriods.NextMonth; + case eExcelConditionalFormattingTimePeriodType.LastWeek: + return ExcelConditionalFormattingConstants.TimePeriods._lastWeek; - case eExcelConditionalFormattingTimePeriodType.NextWeek: - return ExcelConditionalFormattingConstants.TimePeriods.NextWeek; + case eExcelConditionalFormattingTimePeriodType.NextMonth: + return ExcelConditionalFormattingConstants.TimePeriods._nextMonth; - case eExcelConditionalFormattingTimePeriodType.ThisMonth: - return ExcelConditionalFormattingConstants.TimePeriods.ThisMonth; + case eExcelConditionalFormattingTimePeriodType.NextWeek: + return ExcelConditionalFormattingConstants.TimePeriods._nextWeek; - case eExcelConditionalFormattingTimePeriodType.ThisWeek: - return ExcelConditionalFormattingConstants.TimePeriods.ThisWeek; + case eExcelConditionalFormattingTimePeriodType.ThisMonth: + return ExcelConditionalFormattingConstants.TimePeriods._thisMonth; - case eExcelConditionalFormattingTimePeriodType.Today: - return ExcelConditionalFormattingConstants.TimePeriods.Today; + case eExcelConditionalFormattingTimePeriodType.ThisWeek: + return ExcelConditionalFormattingConstants.TimePeriods._thisWeek; - case eExcelConditionalFormattingTimePeriodType.Tomorrow: - return ExcelConditionalFormattingConstants.TimePeriods.Tomorrow; + case eExcelConditionalFormattingTimePeriodType.Today: + return ExcelConditionalFormattingConstants.TimePeriods._today; - case eExcelConditionalFormattingTimePeriodType.Yesterday: - return ExcelConditionalFormattingConstants.TimePeriods.Yesterday; - } + case eExcelConditionalFormattingTimePeriodType.Tomorrow: + return ExcelConditionalFormattingConstants.TimePeriods._tomorrow; - return string.Empty; - } - - /// <summary> - /// - /// </summary> - /// <param name="attribute"></param> - /// <returns></returns> - public static eExcelConditionalFormattingTimePeriodType GetTypeByAttribute( - string attribute) - { - switch (attribute) - { - case ExcelConditionalFormattingConstants.TimePeriods.Last7Days: - return eExcelConditionalFormattingTimePeriodType.Last7Days; - - case ExcelConditionalFormattingConstants.TimePeriods.LastMonth: - return eExcelConditionalFormattingTimePeriodType.LastMonth; - - case ExcelConditionalFormattingConstants.TimePeriods.LastWeek: - return eExcelConditionalFormattingTimePeriodType.LastWeek; - - case ExcelConditionalFormattingConstants.TimePeriods.NextMonth: - return eExcelConditionalFormattingTimePeriodType.NextMonth; - - case ExcelConditionalFormattingConstants.TimePeriods.NextWeek: - return eExcelConditionalFormattingTimePeriodType.NextWeek; - - case ExcelConditionalFormattingConstants.TimePeriods.ThisMonth: - return eExcelConditionalFormattingTimePeriodType.ThisMonth; - - case ExcelConditionalFormattingConstants.TimePeriods.ThisWeek: - return eExcelConditionalFormattingTimePeriodType.ThisWeek; - - case ExcelConditionalFormattingConstants.TimePeriods.Today: - return eExcelConditionalFormattingTimePeriodType.Today; - - case ExcelConditionalFormattingConstants.TimePeriods.Tomorrow: - return eExcelConditionalFormattingTimePeriodType.Tomorrow; - - case ExcelConditionalFormattingConstants.TimePeriods.Yesterday: - return eExcelConditionalFormattingTimePeriodType.Yesterday; - } - - throw new Exception( - ExcelConditionalFormattingConstants.Errors.UnexistentTimePeriodTypeAttribute); + case eExcelConditionalFormattingTimePeriodType.Yesterday: + return ExcelConditionalFormattingConstants.TimePeriods._yesterday; } + + return string.Empty; } -} \ No newline at end of file + + /// <summary> + /// + /// </summary> + /// <param name="attribute"></param> + /// <returns></returns> + public static eExcelConditionalFormattingTimePeriodType GetTypeByAttribute(string attribute) { + switch (attribute) { + case ExcelConditionalFormattingConstants.TimePeriods._last7Days: + return eExcelConditionalFormattingTimePeriodType.Last7Days; + + case ExcelConditionalFormattingConstants.TimePeriods._lastMonth: + return eExcelConditionalFormattingTimePeriodType.LastMonth; + + case ExcelConditionalFormattingConstants.TimePeriods._lastWeek: + return eExcelConditionalFormattingTimePeriodType.LastWeek; + + case ExcelConditionalFormattingConstants.TimePeriods._nextMonth: + return eExcelConditionalFormattingTimePeriodType.NextMonth; + + case ExcelConditionalFormattingConstants.TimePeriods._nextWeek: + return eExcelConditionalFormattingTimePeriodType.NextWeek; + + case ExcelConditionalFormattingConstants.TimePeriods._thisMonth: + return eExcelConditionalFormattingTimePeriodType.ThisMonth; + + case ExcelConditionalFormattingConstants.TimePeriods._thisWeek: + return eExcelConditionalFormattingTimePeriodType.ThisWeek; + + case ExcelConditionalFormattingConstants.TimePeriods._today: + return eExcelConditionalFormattingTimePeriodType.Today; + + case ExcelConditionalFormattingConstants.TimePeriods._tomorrow: + return eExcelConditionalFormattingTimePeriodType.Tomorrow; + + case ExcelConditionalFormattingConstants.TimePeriods._yesterday: + return eExcelConditionalFormattingTimePeriodType.Yesterday; + } + + throw new(ExcelConditionalFormattingConstants.Errors._unexistentTimePeriodTypeAttribute); + } +}
diff --git a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs index 2628487..9d28645 100644 --- a/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs +++ b/EPPlus/ConditionalFormatting/ExcelConditionalFormattingValueObjectType.cs
@@ -13,210 +13,188 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting Adaption 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// Functions related to the <see cref="ExcelConditionalFormattingColorScaleValue"/> - /// </summary> - internal static class ExcelConditionalFormattingValueObjectType - { - /// <summary> - /// Get the sequencial order of a cfvo/color by its position. - /// </summary> - /// <param name="position"></param> - /// <param name="ruleType"></param> - /// <returns>1, 2 or 3</returns> - internal static int GetOrderByPosition( - eExcelConditionalFormattingValueObjectPosition position, - eExcelConditionalFormattingRuleType ruleType) - { - switch (position) - { - case eExcelConditionalFormattingValueObjectPosition.Low: - return 1; +namespace OfficeOpenXml.ConditionalFormatting; - case eExcelConditionalFormattingValueObjectPosition.Middle: - return 2; +/// <summary> +/// Functions related to the <see cref="ExcelConditionalFormattingColorScaleValue"/> +/// </summary> +internal static class ExcelConditionalFormattingValueObjectType { + /// <summary> + /// Get the sequencial order of a cfvo/color by its position. + /// </summary> + /// <param name="position"></param> + /// <param name="ruleType"></param> + /// <returns>1, 2 or 3</returns> + internal static int GetOrderByPosition( + eExcelConditionalFormattingValueObjectPosition position, + eExcelConditionalFormattingRuleType ruleType) { + switch (position) { + case eExcelConditionalFormattingValueObjectPosition.Low: + return 1; - case eExcelConditionalFormattingValueObjectPosition.High: - // Check if the rule type is TwoColorScale. - if (ruleType == eExcelConditionalFormattingRuleType.TwoColorScale) - { - // There are only "Low" and "High". So "High" is the second - return 2; - } + case eExcelConditionalFormattingValueObjectPosition.Middle: + return 2; - // There are "Low", "Middle" and "High". So "High" is the third - return 3; - } + case eExcelConditionalFormattingValueObjectPosition.High: + // Check if the rule type is TwoColorScale. + if (ruleType == eExcelConditionalFormattingRuleType.TwoColorScale) { + // There are only "Low" and "High". So "High" is the second + return 2; + } - return 0; - } + // There are "Low", "Middle" and "High". So "High" is the third + return 3; + } - /// <summary> - /// Get the CFVO type by its @type attribute - /// </summary> - /// <param name="attribute"></param> - /// <returns></returns> - public static eExcelConditionalFormattingValueObjectType GetTypeByAttrbiute( - string attribute) - { - switch (attribute) - { - case ExcelConditionalFormattingConstants.CfvoType.Min: - return eExcelConditionalFormattingValueObjectType.Min; + return 0; + } - case ExcelConditionalFormattingConstants.CfvoType.Max: - return eExcelConditionalFormattingValueObjectType.Max; + /// <summary> + /// Get the CFVO type by its @type attribute + /// </summary> + /// <param name="attribute"></param> + /// <returns></returns> + public static eExcelConditionalFormattingValueObjectType GetTypeByAttrbiute(string attribute) { + switch (attribute) { + case ExcelConditionalFormattingConstants.CfvoType._min: + return eExcelConditionalFormattingValueObjectType.Min; - case ExcelConditionalFormattingConstants.CfvoType.Num: - return eExcelConditionalFormattingValueObjectType.Num; + case ExcelConditionalFormattingConstants.CfvoType._max: + return eExcelConditionalFormattingValueObjectType.Max; - case ExcelConditionalFormattingConstants.CfvoType.Formula: - return eExcelConditionalFormattingValueObjectType.Formula; + case ExcelConditionalFormattingConstants.CfvoType._num: + return eExcelConditionalFormattingValueObjectType.Num; - case ExcelConditionalFormattingConstants.CfvoType.Percent: - return eExcelConditionalFormattingValueObjectType.Percent; + case ExcelConditionalFormattingConstants.CfvoType._formula: + return eExcelConditionalFormattingValueObjectType.Formula; - case ExcelConditionalFormattingConstants.CfvoType.Percentile: - return eExcelConditionalFormattingValueObjectType.Percentile; - } + case ExcelConditionalFormattingConstants.CfvoType._percent: + return eExcelConditionalFormattingValueObjectType.Percent; - throw new Exception( - ExcelConditionalFormattingConstants.Errors.UnexistentCfvoTypeAttribute); - } + case ExcelConditionalFormattingConstants.CfvoType._percentile: + return eExcelConditionalFormattingValueObjectType.Percentile; + } - /// <summary> - /// - /// </summary> - /// <param name="position"></param> - ///<param name="ruleType"></param> - /// <param name="topNode"></param> - /// <param name="nameSpaceManager"></param> - /// <returns></returns> - public static XmlNode GetCfvoNodeByPosition( - eExcelConditionalFormattingValueObjectPosition position, - eExcelConditionalFormattingRuleType ruleType, - XmlNode topNode, - XmlNamespaceManager nameSpaceManager) - { - // Get the corresponding <cfvo> node (by the position) - var node = topNode.SelectSingleNode( - string.Format( - "{0}[position()={1}]", - // {0} - ExcelConditionalFormattingConstants.Paths.Cfvo, - // {1} - ExcelConditionalFormattingValueObjectType.GetOrderByPosition(position, ruleType)), - nameSpaceManager); + throw new(ExcelConditionalFormattingConstants.Errors._unexistentCfvoTypeAttribute); + } - if (node == null) - { - throw new Exception( - ExcelConditionalFormattingConstants.Errors.MissingCfvoNode); - } + /// <summary> + /// + /// </summary> + /// <param name="position"></param> + ///<param name="ruleType"></param> + /// <param name="topNode"></param> + /// <param name="nameSpaceManager"></param> + /// <returns></returns> + public static XmlNode GetCfvoNodeByPosition( + eExcelConditionalFormattingValueObjectPosition position, + eExcelConditionalFormattingRuleType ruleType, + XmlNode topNode, + XmlNamespaceManager nameSpaceManager) { + // Get the corresponding <cfvo> node (by the position) + var node = topNode.SelectSingleNode( + string.Format( + "{0}[position()={1}]", + // {0} + ExcelConditionalFormattingConstants.Paths._cfvo, + // {1} + GetOrderByPosition(position, ruleType)), + nameSpaceManager); - return node; - } + if (node == null) { + throw new(ExcelConditionalFormattingConstants.Errors._missingCfvoNode); + } - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <returns></returns> - public static string GetAttributeByType( - eExcelConditionalFormattingValueObjectType type) - { - switch (type) - { - case eExcelConditionalFormattingValueObjectType.Min: - return ExcelConditionalFormattingConstants.CfvoType.Min; + return node; + } - case eExcelConditionalFormattingValueObjectType.Max: - return ExcelConditionalFormattingConstants.CfvoType.Max; + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <returns></returns> + public static string GetAttributeByType(eExcelConditionalFormattingValueObjectType type) { + switch (type) { + case eExcelConditionalFormattingValueObjectType.Min: + return ExcelConditionalFormattingConstants.CfvoType._min; - case eExcelConditionalFormattingValueObjectType.Num: - return ExcelConditionalFormattingConstants.CfvoType.Num; + case eExcelConditionalFormattingValueObjectType.Max: + return ExcelConditionalFormattingConstants.CfvoType._max; - case eExcelConditionalFormattingValueObjectType.Formula: - return ExcelConditionalFormattingConstants.CfvoType.Formula; + case eExcelConditionalFormattingValueObjectType.Num: + return ExcelConditionalFormattingConstants.CfvoType._num; - case eExcelConditionalFormattingValueObjectType.Percent: - return ExcelConditionalFormattingConstants.CfvoType.Percent; + case eExcelConditionalFormattingValueObjectType.Formula: + return ExcelConditionalFormattingConstants.CfvoType._formula; - case eExcelConditionalFormattingValueObjectType.Percentile: - return ExcelConditionalFormattingConstants.CfvoType.Percentile; - } + case eExcelConditionalFormattingValueObjectType.Percent: + return ExcelConditionalFormattingConstants.CfvoType._percent; - return string.Empty; - } + case eExcelConditionalFormattingValueObjectType.Percentile: + return ExcelConditionalFormattingConstants.CfvoType._percentile; + } - /// <summary> - /// Get the cfvo (§18.3.1.11) node parent by the rule type. Can be any of the following: - /// "colorScale" (§18.3.1.16); "dataBar" (§18.3.1.28); "iconSet" (§18.3.1.49) - /// </summary> - /// <param name="ruleType"></param> - /// <returns></returns> - public static string GetParentPathByRuleType( - eExcelConditionalFormattingRuleType ruleType) - { - switch (ruleType) - { - case eExcelConditionalFormattingRuleType.TwoColorScale: - case eExcelConditionalFormattingRuleType.ThreeColorScale: - return ExcelConditionalFormattingConstants.Paths.ColorScale; + return string.Empty; + } - case eExcelConditionalFormattingRuleType.ThreeIconSet: - case eExcelConditionalFormattingRuleType.FourIconSet: - case eExcelConditionalFormattingRuleType.FiveIconSet: - return ExcelConditionalFormattingConstants.Paths.IconSet; + /// <summary> + /// Get the cfvo (§18.3.1.11) node parent by the rule type. Can be any of the following: + /// "colorScale" (§18.3.1.16); "dataBar" (§18.3.1.28); "iconSet" (§18.3.1.49) + /// </summary> + /// <param name="ruleType"></param> + /// <returns></returns> + public static string GetParentPathByRuleType(eExcelConditionalFormattingRuleType ruleType) { + switch (ruleType) { + case eExcelConditionalFormattingRuleType.TwoColorScale: + case eExcelConditionalFormattingRuleType.ThreeColorScale: + return ExcelConditionalFormattingConstants.Paths._colorScale; - case eExcelConditionalFormattingRuleType.DataBar: - return ExcelConditionalFormattingConstants.Paths.DataBar; - } + case eExcelConditionalFormattingRuleType.ThreeIconSet: + case eExcelConditionalFormattingRuleType.FourIconSet: + case eExcelConditionalFormattingRuleType.FiveIconSet: + return ExcelConditionalFormattingConstants.Paths._iconSet; - return string.Empty; - } + case eExcelConditionalFormattingRuleType.DataBar: + return ExcelConditionalFormattingConstants.Paths._dataBar; + } - /// <summary> - /// - /// </summary> - /// <param name="nodeType"></param> - /// <returns></returns> - public static string GetNodePathByNodeType( - eExcelConditionalFormattingValueObjectNodeType nodeType) - { - switch(nodeType) - { - case eExcelConditionalFormattingValueObjectNodeType.Cfvo: - return ExcelConditionalFormattingConstants.Paths.Cfvo; + return string.Empty; + } - case eExcelConditionalFormattingValueObjectNodeType.Color: - return ExcelConditionalFormattingConstants.Paths.Color; - } + /// <summary> + /// + /// </summary> + /// <param name="nodeType"></param> + /// <returns></returns> + public static string GetNodePathByNodeType( + eExcelConditionalFormattingValueObjectNodeType nodeType) { + switch (nodeType) { + case eExcelConditionalFormattingValueObjectNodeType.Cfvo: + return ExcelConditionalFormattingConstants.Paths._cfvo; - return string.Empty; - } - } -} \ No newline at end of file + case eExcelConditionalFormattingValueObjectNodeType.Color: + return ExcelConditionalFormattingConstants.Paths._color; + } + + return string.Empty; + } +}
diff --git a/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs b/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs index 841461d..debf061 100644 --- a/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs +++ b/EPPlus/ConditionalFormatting/RangeConditionalFormatting.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,519 +13,426 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Conditional Formatting 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.Utils; + +using System.Drawing; using OfficeOpenXml.ConditionalFormatting.Contracts; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.ConditionalFormatting -{ - internal class RangeConditionalFormatting - : IRangeConditionalFormatting - { - #region Public Properties - public ExcelWorksheet _worksheet; - public ExcelAddress _address; - #endregion Public Properties +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - public RangeConditionalFormatting( - ExcelWorksheet worksheet, - ExcelAddress address) - { - Require.Argument(worksheet).IsNotNull("worksheet"); - Require.Argument(address).IsNotNull("address"); +internal class RangeConditionalFormatting : IRangeConditionalFormatting { + public ExcelWorksheet _worksheet; + public ExcelAddress _address; - _worksheet = worksheet; - _address = address; - } - #endregion Constructors + public RangeConditionalFormatting(ExcelWorksheet worksheet, ExcelAddress address) { + Require.Argument(worksheet).IsNotNull("worksheet"); + Require.Argument(address).IsNotNull("address"); - #region Conditional Formatting Rule Types - /// <summary> - /// Add AboveOrEqualAverage Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddAboveAverage() - { - return _worksheet.ConditionalFormatting.AddAboveAverage( - _address); - } + _worksheet = worksheet; + _address = address; + } - /// <summary> - /// Add AboveOrEqualAverage Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage() - { - return _worksheet.ConditionalFormatting.AddAboveOrEqualAverage( - _address); - } + /// <summary> + /// Add AboveOrEqualAverage Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddAboveAverage() { + return _worksheet.ConditionalFormatting.AddAboveAverage(_address); + } - /// <summary> - /// Add BelowOrEqualAverage Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddBelowAverage() - { - return _worksheet.ConditionalFormatting.AddBelowAverage( - _address); - } + /// <summary> + /// Add AboveOrEqualAverage Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddAboveOrEqualAverage() { + return _worksheet.ConditionalFormatting.AddAboveOrEqualAverage(_address); + } - /// <summary> - /// Add BelowOrEqualAverage Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage() - { - return _worksheet.ConditionalFormatting.AddBelowOrEqualAverage( - _address); - } + /// <summary> + /// Add BelowOrEqualAverage Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddBelowAverage() { + return _worksheet.ConditionalFormatting.AddBelowAverage(_address); + } - /// <summary> - /// Add AboveStdDev Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingStdDevGroup AddAboveStdDev() - { - return _worksheet.ConditionalFormatting.AddAboveStdDev( - _address); - } + /// <summary> + /// Add BelowOrEqualAverage Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingAverageGroup AddBelowOrEqualAverage() { + return _worksheet.ConditionalFormatting.AddBelowOrEqualAverage(_address); + } - /// <summary> - /// Add BelowStdDev Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingStdDevGroup AddBelowStdDev() - { - return _worksheet.ConditionalFormatting.AddBelowStdDev( - _address); - } + /// <summary> + /// Add AboveStdDev Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingStdDevGroup AddAboveStdDev() { + return _worksheet.ConditionalFormatting.AddAboveStdDev(_address); + } - /// <summary> - /// Add Bottom Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddBottom() - { - return _worksheet.ConditionalFormatting.AddBottom( - _address); - } + /// <summary> + /// Add BelowStdDev Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingStdDevGroup AddBelowStdDev() { + return _worksheet.ConditionalFormatting.AddBelowStdDev(_address); + } - /// <summary> - /// Add BottomPercent Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddBottomPercent() - { - return _worksheet.ConditionalFormatting.AddBottomPercent( - _address); - } + /// <summary> + /// Add Bottom Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddBottom() { + return _worksheet.ConditionalFormatting.AddBottom(_address); + } - /// <summary> - /// Add Top Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddTop() - { - return _worksheet.ConditionalFormatting.AddTop( - _address); - } + /// <summary> + /// Add BottomPercent Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddBottomPercent() { + return _worksheet.ConditionalFormatting.AddBottomPercent(_address); + } - /// <summary> - /// Add TopPercent Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTopBottomGroup AddTopPercent() - { - return _worksheet.ConditionalFormatting.AddTopPercent( - _address); - } + /// <summary> + /// Add Top Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddTop() { + return _worksheet.ConditionalFormatting.AddTop(_address); + } - /// <summary> - /// Add Last7Days Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddLast7Days() - { - return _worksheet.ConditionalFormatting.AddLast7Days( - _address); - } + /// <summary> + /// Add TopPercent Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTopBottomGroup AddTopPercent() { + return _worksheet.ConditionalFormatting.AddTopPercent(_address); + } - /// <summary> - /// Add LastMonth Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddLastMonth() - { - return _worksheet.ConditionalFormatting.AddLastMonth( - _address); - } + /// <summary> + /// Add Last7Days Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddLast7Days() { + return _worksheet.ConditionalFormatting.AddLast7Days(_address); + } - /// <summary> - /// Add LastWeek Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddLastWeek() - { - return _worksheet.ConditionalFormatting.AddLastWeek( - _address); - } + /// <summary> + /// Add LastMonth Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddLastMonth() { + return _worksheet.ConditionalFormatting.AddLastMonth(_address); + } - /// <summary> - /// Add NextMonth Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddNextMonth() - { - return _worksheet.ConditionalFormatting.AddNextMonth( - _address); - } + /// <summary> + /// Add LastWeek Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddLastWeek() { + return _worksheet.ConditionalFormatting.AddLastWeek(_address); + } - /// <summary> - /// Add NextWeek Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddNextWeek() - { - return _worksheet.ConditionalFormatting.AddNextWeek( - _address); - } + /// <summary> + /// Add NextMonth Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddNextMonth() { + return _worksheet.ConditionalFormatting.AddNextMonth(_address); + } - /// <summary> - /// Add ThisMonth Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddThisMonth() - { - return _worksheet.ConditionalFormatting.AddThisMonth( - _address); - } + /// <summary> + /// Add NextWeek Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddNextWeek() { + return _worksheet.ConditionalFormatting.AddNextWeek(_address); + } - /// <summary> - /// Add ThisWeek Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddThisWeek() - { - return _worksheet.ConditionalFormatting.AddThisWeek( - _address); - } + /// <summary> + /// Add ThisMonth Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddThisMonth() { + return _worksheet.ConditionalFormatting.AddThisMonth(_address); + } - /// <summary> - /// Add Today Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddToday() - { - return _worksheet.ConditionalFormatting.AddToday( - _address); - } + /// <summary> + /// Add ThisWeek Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddThisWeek() { + return _worksheet.ConditionalFormatting.AddThisWeek(_address); + } - /// <summary> - /// Add Tomorrow Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddTomorrow() - { - return _worksheet.ConditionalFormatting.AddTomorrow( - _address); - } + /// <summary> + /// Add Today Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddToday() { + return _worksheet.ConditionalFormatting.AddToday(_address); + } - /// <summary> - /// Add Yesterday Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTimePeriodGroup AddYesterday() - { - return _worksheet.ConditionalFormatting.AddYesterday( - _address); - } + /// <summary> + /// Add Tomorrow Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddTomorrow() { + return _worksheet.ConditionalFormatting.AddTomorrow(_address); + } - /// <summary> - /// Add BeginsWith Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingBeginsWith AddBeginsWith() - { - return _worksheet.ConditionalFormatting.AddBeginsWith( - _address); - } + /// <summary> + /// Add Yesterday Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTimePeriodGroup AddYesterday() { + return _worksheet.ConditionalFormatting.AddYesterday(_address); + } - /// <summary> - /// Add Between Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingBetween AddBetween() - { - return _worksheet.ConditionalFormatting.AddBetween( - _address); - } + /// <summary> + /// Add BeginsWith Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingBeginsWith AddBeginsWith() { + return _worksheet.ConditionalFormatting.AddBeginsWith(_address); + } - /// <summary> - /// Add ContainsBlanks Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingContainsBlanks AddContainsBlanks() - { - return _worksheet.ConditionalFormatting.AddContainsBlanks( - _address); - } + /// <summary> + /// Add Between Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingBetween AddBetween() { + return _worksheet.ConditionalFormatting.AddBetween(_address); + } - /// <summary> - /// Add ContainsErrors Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingContainsErrors AddContainsErrors() - { - return _worksheet.ConditionalFormatting.AddContainsErrors( - _address); - } + /// <summary> + /// Add ContainsBlanks Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingContainsBlanks AddContainsBlanks() { + return _worksheet.ConditionalFormatting.AddContainsBlanks(_address); + } - /// <summary> - /// Add ContainsText Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingContainsText AddContainsText() - { - return _worksheet.ConditionalFormatting.AddContainsText( - _address); - } + /// <summary> + /// Add ContainsErrors Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingContainsErrors AddContainsErrors() { + return _worksheet.ConditionalFormatting.AddContainsErrors(_address); + } - /// <summary> - /// Add DuplicateValues Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingDuplicateValues AddDuplicateValues() - { - return _worksheet.ConditionalFormatting.AddDuplicateValues( - _address); - } + /// <summary> + /// Add ContainsText Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingContainsText AddContainsText() { + return _worksheet.ConditionalFormatting.AddContainsText(_address); + } - /// <summary> - /// Add EndsWith Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingEndsWith AddEndsWith() - { - return _worksheet.ConditionalFormatting.AddEndsWith( - _address); - } + /// <summary> + /// Add DuplicateValues Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingDuplicateValues AddDuplicateValues() { + return _worksheet.ConditionalFormatting.AddDuplicateValues(_address); + } - /// <summary> - /// Add Equal Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingEqual AddEqual() - { - return _worksheet.ConditionalFormatting.AddEqual( - _address); - } + /// <summary> + /// Add EndsWith Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingEndsWith AddEndsWith() { + return _worksheet.ConditionalFormatting.AddEndsWith(_address); + } - /// <summary> - /// Add Expression Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingExpression AddExpression() - { - return _worksheet.ConditionalFormatting.AddExpression( - _address); - } + /// <summary> + /// Add Equal Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingEqual AddEqual() { + return _worksheet.ConditionalFormatting.AddEqual(_address); + } - /// <summary> - /// Add GreaterThan Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingGreaterThan AddGreaterThan() - { - return _worksheet.ConditionalFormatting.AddGreaterThan( - _address); - } + /// <summary> + /// Add Expression Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingExpression AddExpression() { + return _worksheet.ConditionalFormatting.AddExpression(_address); + } - /// <summary> - /// Add GreaterThanOrEqual Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual() - { - return _worksheet.ConditionalFormatting.AddGreaterThanOrEqual( - _address); - } + /// <summary> + /// Add GreaterThan Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingGreaterThan AddGreaterThan() { + return _worksheet.ConditionalFormatting.AddGreaterThan(_address); + } - /// <summary> - /// Add LessThan Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingLessThan AddLessThan() - { - return _worksheet.ConditionalFormatting.AddLessThan( - _address); - } + /// <summary> + /// Add GreaterThanOrEqual Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingGreaterThanOrEqual AddGreaterThanOrEqual() { + return _worksheet.ConditionalFormatting.AddGreaterThanOrEqual(_address); + } - /// <summary> - /// Add LessThanOrEqual Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual() - { - return _worksheet.ConditionalFormatting.AddLessThanOrEqual( - _address); - } + /// <summary> + /// Add LessThan Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingLessThan AddLessThan() { + return _worksheet.ConditionalFormatting.AddLessThan(_address); + } - /// <summary> - /// Add NotBetween Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingNotBetween AddNotBetween() - { - return _worksheet.ConditionalFormatting.AddNotBetween( - _address); - } + /// <summary> + /// Add LessThanOrEqual Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingLessThanOrEqual AddLessThanOrEqual() { + return _worksheet.ConditionalFormatting.AddLessThanOrEqual(_address); + } - /// <summary> - /// Add NotContainsBlanks Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks() - { - return _worksheet.ConditionalFormatting.AddNotContainsBlanks( - _address); - } + /// <summary> + /// Add NotBetween Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingNotBetween AddNotBetween() { + return _worksheet.ConditionalFormatting.AddNotBetween(_address); + } - /// <summary> - /// Add NotContainsErrors Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors() - { - return _worksheet.ConditionalFormatting.AddNotContainsErrors( - _address); - } + /// <summary> + /// Add NotContainsBlanks Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingNotContainsBlanks AddNotContainsBlanks() { + return _worksheet.ConditionalFormatting.AddNotContainsBlanks(_address); + } - /// <summary> - /// Add NotContainsText Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingNotContainsText AddNotContainsText() - { - return _worksheet.ConditionalFormatting.AddNotContainsText( - _address); - } + /// <summary> + /// Add NotContainsErrors Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingNotContainsErrors AddNotContainsErrors() { + return _worksheet.ConditionalFormatting.AddNotContainsErrors(_address); + } - /// <summary> - /// Add NotEqual Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingNotEqual AddNotEqual() - { - return _worksheet.ConditionalFormatting.AddNotEqual( - _address); - } + /// <summary> + /// Add NotContainsText Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingNotContainsText AddNotContainsText() { + return _worksheet.ConditionalFormatting.AddNotContainsText(_address); + } - /// <summary> - /// Add UniqueValues Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingUniqueValues AddUniqueValues() - { - return _worksheet.ConditionalFormatting.AddUniqueValues( - _address); - } + /// <summary> + /// Add NotEqual Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingNotEqual AddNotEqual() { + return _worksheet.ConditionalFormatting.AddNotEqual(_address); + } - /// <summary> - /// Add ThreeColorScale Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingThreeColorScale AddThreeColorScale() - { - return (IExcelConditionalFormattingThreeColorScale)(_worksheet.ConditionalFormatting.AddRule( + /// <summary> + /// Add UniqueValues Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingUniqueValues AddUniqueValues() { + return _worksheet.ConditionalFormatting.AddUniqueValues(_address); + } + + /// <summary> + /// Add ThreeColorScale Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingThreeColorScale AddThreeColorScale() { + return (IExcelConditionalFormattingThreeColorScale)(_worksheet.ConditionalFormatting.AddRule( eExcelConditionalFormattingRuleType.ThreeColorScale, _address)); - } + } - /// <summary> - /// Add TwoColorScale Conditional Formatting - /// </summary> - /// <returns></returns> - public IExcelConditionalFormattingTwoColorScale AddTwoColorScale() - { - return (IExcelConditionalFormattingTwoColorScale)(_worksheet.ConditionalFormatting.AddRule( + /// <summary> + /// Add TwoColorScale Conditional Formatting + /// </summary> + /// <returns></returns> + public IExcelConditionalFormattingTwoColorScale AddTwoColorScale() { + return (IExcelConditionalFormattingTwoColorScale)(_worksheet.ConditionalFormatting.AddRule( eExcelConditionalFormattingRuleType.TwoColorScale, _address)); - } - - /// <summary> - /// Adds a ThreeIconSet rule - /// </summary> - /// <param name="IconSet"></param> - /// <returns></returns> - public IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet(eExcelconditionalFormatting3IconsSetType IconSet) - { - var rule = (IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>)(_worksheet.ConditionalFormatting.AddRule( - eExcelConditionalFormattingRuleType.ThreeIconSet, - _address)); - rule.IconSet = IconSet; - return rule; - } - - /// <summary> - /// Adds a FourIconSet rule - /// </summary> - /// <param name="IconSet"></param> - /// <returns></returns> - public IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet(eExcelconditionalFormatting4IconsSetType IconSet) - { - var rule = (IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>)(_worksheet.ConditionalFormatting.AddRule( - eExcelConditionalFormattingRuleType.FourIconSet, - _address)); - rule.IconSet = IconSet; - return rule; - } - - /// <summary> - /// Adds a FiveIconSet rule - /// </summary> - /// <param name="IconSet"></param> - /// <returns></returns> - public IExcelConditionalFormattingFiveIconSet AddFiveIconSet(eExcelconditionalFormatting5IconsSetType IconSet) - { - var rule = (IExcelConditionalFormattingFiveIconSet)(_worksheet.ConditionalFormatting.AddRule( - eExcelConditionalFormattingRuleType.FiveIconSet, - _address)); - rule.IconSet = IconSet; - return rule; - } - - /// <summary> - /// Adds a Databar rule - /// </summary> - /// <param name="Color">The color of the databar</param> - /// <returns></returns> - public IExcelConditionalFormattingDataBarGroup AddDatabar(System.Drawing.Color Color) - { - var rule = (IExcelConditionalFormattingDataBarGroup)(_worksheet.ConditionalFormatting.AddRule( - eExcelConditionalFormattingRuleType.DataBar, - _address)); - rule.Color = Color; - return rule; - } - #endregion Conditional Formatting Rule Types } -} \ No newline at end of file + + /// <summary> + /// Adds a ThreeIconSet rule + /// </summary> + /// <param name="iconSet"></param> + /// <returns></returns> + public IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType> AddThreeIconSet( + eExcelconditionalFormatting3IconsSetType iconSet) { + var rule = + (IExcelConditionalFormattingThreeIconSet<eExcelconditionalFormatting3IconsSetType>)(_worksheet.ConditionalFormatting.AddRule( + eExcelConditionalFormattingRuleType.ThreeIconSet, + _address)); + rule.IconSet = iconSet; + return rule; + } + + /// <summary> + /// Adds a FourIconSet rule + /// </summary> + /// <param name="iconSet"></param> + /// <returns></returns> + public IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> AddFourIconSet( + eExcelconditionalFormatting4IconsSetType iconSet) { + var rule = + (IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType>)(_worksheet.ConditionalFormatting.AddRule( + eExcelConditionalFormattingRuleType.FourIconSet, + _address)); + rule.IconSet = iconSet; + return rule; + } + + /// <summary> + /// Adds a FiveIconSet rule + /// </summary> + /// <param name="iconSet"></param> + /// <returns></returns> + public IExcelConditionalFormattingFiveIconSet AddFiveIconSet( + eExcelconditionalFormatting5IconsSetType iconSet) { + var rule = (IExcelConditionalFormattingFiveIconSet)(_worksheet.ConditionalFormatting.AddRule( + eExcelConditionalFormattingRuleType.FiveIconSet, + _address)); + rule.IconSet = iconSet; + return rule; + } + + /// <summary> + /// Adds a Databar rule + /// </summary> + /// <param name="color">The color of the databar</param> + /// <returns></returns> + public IExcelConditionalFormattingDataBarGroup AddDatabar(Color color) { + var rule = (IExcelConditionalFormattingDataBarGroup)(_worksheet.ConditionalFormatting.AddRule( + eExcelConditionalFormattingRuleType.DataBar, + _address)); + rule.Color = color; + return rule; + } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs index f35fe47..6e82c2f 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveAverage.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,110 +13,82 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingAboveAverage +/// </summary> +public class ExcelConditionalFormattingAboveAverage : ExcelConditionalFormattingAverageGroup { /// <summary> - /// ExcelConditionalFormattingAboveAverage + /// /// </summary> - public class ExcelConditionalFormattingAboveAverage - : ExcelConditionalFormattingAverageGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingAboveAverage( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingAboveAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.AboveAverage, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.AboveAverage, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - AboveAverage = true; - EqualAverage = false; - } + AboveAverage = true; + EqualAverage = false; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingAboveAverage( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingAboveAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingAboveAverage( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingAboveAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs index f87e2a8..60a89d0 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveOrEqualAverage.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,110 +13,83 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingAboveOrEqualAverage +/// </summary> +public class ExcelConditionalFormattingAboveOrEqualAverage + : ExcelConditionalFormattingAverageGroup { /// <summary> - /// ExcelConditionalFormattingAboveOrEqualAverage + /// /// </summary> - public class ExcelConditionalFormattingAboveOrEqualAverage - : ExcelConditionalFormattingAverageGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingAboveOrEqualAverage( + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingAboveOrEqualAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.AboveOrEqualAverage, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.AboveOrEqualAverage, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - AboveAverage = true; - EqualAverage = true; - } + AboveAverage = true; + EqualAverage = true; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingAboveOrEqualAverage( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingAboveOrEqualAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingAboveOrEqualAverage( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingAboveOrEqualAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs index 5b0fb33..0883462 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAboveStdDev.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingAboveStdDev - /// </summary> - public class ExcelConditionalFormattingAboveStdDev - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingStdDevGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingAboveStdDev( +/// <summary> +/// ExcelConditionalFormattingAboveStdDev +/// </summary> +public class ExcelConditionalFormattingAboveStdDev + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingStdDevGroup { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingAboveStdDev( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.AboveStdDev, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.AboveStdDev, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - AboveAverage = true; - StdDev = 1; - } + AboveAverage = true; + StdDev = 1; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingAboveStdDev( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingAboveStdDev( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingAboveStdDev( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingAboveStdDev( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs index dd11eb8..cebdb51 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingAverageGroup.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,51 +13,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingAverageGroup - /// </summary> - public class ExcelConditionalFormattingAverageGroup - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingAverageGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingAverageGroup( +/// <summary> +/// ExcelConditionalFormattingAverageGroup +/// </summary> +public class ExcelConditionalFormattingAverageGroup + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingAverageGroup { + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingAverageGroup( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, @@ -65,62 +57,40 @@ XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - type, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - } + type, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) {} - /// <summary> - /// - /// </summary> - ///<param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingAverageGroup( + /// <summary> + /// + /// </summary> + ///<param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingAverageGroup( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - type, - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(type, address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - ///<param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingAverageGroup( + /// <summary> + /// + /// </summary> + ///<param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingAverageGroup( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - type, - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(type, address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs index a5132c5..9dc918e 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBeginsWith.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,138 +13,100 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingBeginsWith - /// </summary> - public class ExcelConditionalFormattingBeginsWith - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingBeginsWith - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingBeginsWith( +/// <summary> +/// ExcelConditionalFormattingBeginsWith +/// </summary> +public class ExcelConditionalFormattingBeginsWith + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingBeginsWith { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingBeginsWith( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.BeginsWith, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.BeginsWith, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.BeginsWith; - Text = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.BeginsWith; + Text = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingBeginsWith( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingBeginsWith( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingBeginsWith( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingBeginsWith( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - /****************************************************************************************/ + /// <summary> + /// The text to search in the beginning of the cell + /// </summary> + public string Text { + get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute); + set { + SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value); - #region Exposed Properties - /// <summary> - /// The text to search in the beginning of the cell - /// </summary> - public string Text - { - get - { - return GetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute, - value); - - Formula = string.Format( + Formula = string.Format( "LEFT({0},LEN(\"{1}\"))=\"{1}\"", Address.Start.Address, value.Replace("\"", "\"\"")); - } } - #endregion Exposed Properties - - /****************************************************************************************/ } -} \ No newline at end of file +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs index f763b47..be13fa3 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowAverage.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,110 +13,82 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingBelowAverage +/// </summary> +public class ExcelConditionalFormattingBelowAverage : ExcelConditionalFormattingAverageGroup { /// <summary> - /// ExcelConditionalFormattingBelowAverage + /// /// </summary> - public class ExcelConditionalFormattingBelowAverage - : ExcelConditionalFormattingAverageGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingBelowAverage( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingBelowAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.BelowAverage, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.BelowAverage, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - AboveAverage = false; - EqualAverage = false; - } + AboveAverage = false; + EqualAverage = false; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingBelowAverage( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingBelowAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingBelowAverage( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingBelowAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs index 42d88a5..39eb327 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowOrEqualAverage.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,110 +13,83 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingBelowOrEqualAverage +/// </summary> +public class ExcelConditionalFormattingBelowOrEqualAverage + : ExcelConditionalFormattingAverageGroup { /// <summary> - /// ExcelConditionalFormattingBelowOrEqualAverage + /// /// </summary> - public class ExcelConditionalFormattingBelowOrEqualAverage - : ExcelConditionalFormattingAverageGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingBelowOrEqualAverage( + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingBelowOrEqualAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.BelowOrEqualAverage, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.BelowOrEqualAverage, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - AboveAverage = false; - EqualAverage = true; - } + AboveAverage = false; + EqualAverage = true; } + } - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingBelowOrEqualAverage( + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingBelowOrEqualAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingBelowOrEqualAverage( + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingBelowOrEqualAverage( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs index 95be06d..b2419f6 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBelowStdDev.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingBelowStdDev - /// </summary> - public class ExcelConditionalFormattingBelowStdDev - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingStdDevGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingBelowStdDev( +/// <summary> +/// ExcelConditionalFormattingBelowStdDev +/// </summary> +public class ExcelConditionalFormattingBelowStdDev + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingStdDevGroup { + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingBelowStdDev( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.BelowStdDev, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.BelowStdDev, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - AboveAverage = false; - StdDev = 1; - } + AboveAverage = false; + StdDev = 1; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingBelowStdDev( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingBelowStdDev( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingBelowStdDev( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingBelowStdDev( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs index 27c1446..b27a308 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBetween.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingBetween - /// </summary> - public class ExcelConditionalFormattingBetween - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingBetween - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingBetween( +/// <summary> +/// ExcelConditionalFormattingBetween +/// </summary> +public class ExcelConditionalFormattingBetween + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingBetween { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingBetween( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Between, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Between, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.Between; - Formula = string.Empty; - Formula2 = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.Between; + Formula = string.Empty; + Formula2 = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingBetween( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingBetween( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingBetween( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingBetween( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs index bea5fd7..4b23f49 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottom.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingBottom - /// </summary> - public class ExcelConditionalFormattingBottom - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingTopBottomGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingBottom( +/// <summary> +/// ExcelConditionalFormattingBottom +/// </summary> +public class ExcelConditionalFormattingBottom + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingTopBottomGroup { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingBottom( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Bottom, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Bottom, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Bottom = true; - Percent = false; - Rank = 10; // Last 10 values - } + Bottom = true; + Percent = false; + Rank = 10; // Last 10 values } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingBottom( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingBottom( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingBottom( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingBottom( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs index a95ad09..494078d 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingBottomPercent.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingBottomPercent - /// </summary> - public class ExcelConditionalFormattingBottomPercent - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingTopBottomGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingBottomPercent( +/// <summary> +/// ExcelConditionalFormattingBottomPercent +/// </summary> +public class ExcelConditionalFormattingBottomPercent + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingTopBottomGroup { + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingBottomPercent( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.BottomPercent, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.BottomPercent, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Bottom = true; - Percent = true; - Rank = 10; // Last 10 percent - } + Bottom = true; + Percent = true; + Rank = 10; // Last 10 percent } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingBottomPercent( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingBottomPercent( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingBottomPercent( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingBottomPercent( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs index 00b1b1f..16ea6c2 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsBlanks.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingContainsBlanks - /// </summary> - public class ExcelConditionalFormattingContainsBlanks - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingContainsBlanks - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingContainsBlanks( +/// <summary> +/// ExcelConditionalFormattingContainsBlanks +/// </summary> +public class ExcelConditionalFormattingContainsBlanks + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingContainsBlanks { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingContainsBlanks( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.ContainsBlanks, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.ContainsBlanks, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Formula = string.Format( - "LEN(TRIM({0}))=0", - Address.Start.Address); - } + Formula = string.Format("LEN(TRIM({0}))=0", Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingContainsBlanks( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingContainsBlanks( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingContainsBlanks( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingContainsBlanks( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs index 7c06f64..5c743dc 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsErrors.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingContainsErrors - /// </summary> - public class ExcelConditionalFormattingContainsErrors - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingContainsErrors - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingContainsErrors( +/// <summary> +/// ExcelConditionalFormattingContainsErrors +/// </summary> +public class ExcelConditionalFormattingContainsErrors + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingContainsErrors { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingContainsErrors( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.ContainsErrors, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.ContainsErrors, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Formula = string.Format( - "ISERROR({0})", - Address.Start.Address); - } + Formula = string.Format("ISERROR({0})", Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingContainsErrors( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingContainsErrors( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingContainsErrors( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingContainsErrors( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs index 59096cf..88a4d43 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingContainsText.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,138 +13,100 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingContainsText - /// </summary> - public class ExcelConditionalFormattingContainsText - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingContainsText - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingContainsText( +/// <summary> +/// ExcelConditionalFormattingContainsText +/// </summary> +public class ExcelConditionalFormattingContainsText + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingContainsText { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingContainsText( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.ContainsText, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.ContainsText, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.ContainsText; - Text = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.ContainsText; + Text = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingContainsText( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingContainsText( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingContainsText( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingContainsText( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - /****************************************************************************************/ + /// <summary> + /// The text to search inside the cell + /// </summary> + public string Text { + get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute); + set { + SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value); - #region Exposed Properties - /// <summary> - /// The text to search inside the cell - /// </summary> - public string Text - { - get - { - return GetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute, - value); - - Formula = string.Format( + Formula = string.Format( "NOT(ISERROR(SEARCH(\"{1}\",{0})))", Address.Start.Address, value.Replace("\"", "\"\"")); - } } - #endregion Exposed Properties - - /****************************************************************************************/ } -} \ No newline at end of file +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs index 2db9b02..ed32ace 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDataBar.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,221 +13,157 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using System.Drawing; +using System.Globalization; using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -using System.Globalization; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// Databar - /// </summary> - public class ExcelConditionalFormattingDataBar - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingDataBarGroup - { - /****************************************************************************************/ - #region Private Properties +namespace OfficeOpenXml.ConditionalFormatting; - #endregion Private Properties - - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingDataBar( - eExcelConditionalFormattingRuleType type, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode, - XmlNamespaceManager namespaceManager) - : base( - type, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - SchemaNodeOrder = new string[] { "cfvo", "color" }; - //Create the <dataBar> node inside the <cfRule> node - if (itemElementNode!=null && itemElementNode.HasChildNodes) - { - bool high=false; - foreach (XmlNode node in itemElementNode.SelectNodes("d:dataBar/d:cfvo", NameSpaceManager)) - { - if (high == false) - { - LowValue = new ExcelConditionalFormattingIconDataBarValue( - type, - address, - worksheet, - node, - namespaceManager); - high = true; - } - else - { - HighValue = new ExcelConditionalFormattingIconDataBarValue( - type, - address, - worksheet, - node, - namespaceManager); - } - } - } - else - { - var iconSetNode = CreateComplexNode( - Node, - ExcelConditionalFormattingConstants.Paths.DataBar); - - var lowNode = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(lowNode); - LowValue = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Min, - 0, - "", - eExcelConditionalFormattingRuleType.DataBar, - address, - priority, - worksheet, - lowNode, - namespaceManager); - - var highNode = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(highNode); - HighValue = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Max, - 0, - "", - eExcelConditionalFormattingRuleType.DataBar, - address, - priority, - worksheet, - highNode, - namespaceManager); - } - Type = type; +/// <summary> +/// Databar +/// </summary> +public class ExcelConditionalFormattingDataBar + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingDataBarGroup { + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingDataBar( + eExcelConditionalFormattingRuleType type, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base( + type, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + SchemaNodeOrder = new[] { "cfvo", "color" }; + //Create the <dataBar> node inside the <cfRule> node + if (itemElementNode != null && itemElementNode.HasChildNodes) { + bool high = false; + foreach (XmlNode node in itemElementNode.SelectNodes("d:dataBar/d:cfvo", NameSpaceManager)) { + if (high == false) { + LowValue = new(type, address, worksheet, node, namespaceManager); + high = true; + } else { + HighValue = new(type, address, worksheet, node, namespaceManager); } + } + } else { + var iconSetNode = CreateComplexNode(Node, ExcelConditionalFormattingConstants.Paths._dataBar); - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingDataBar( - eExcelConditionalFormattingRuleType type, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode) - : this( - type, - address, - priority, - worksheet, - itemElementNode, - null) - { - } + var lowNode = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(lowNode); + LowValue = new( + eExcelConditionalFormattingValueObjectType.Min, + 0, + "", + eExcelConditionalFormattingRuleType.DataBar, + address, + priority, + worksheet, + lowNode, + namespaceManager); - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingDataBar( - eExcelConditionalFormattingRuleType type, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet) - : this( - type, - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - private const string _showValuePath="d:dataBar/@showValue"; - public bool ShowValue - { - get - { - return GetXmlNodeBool(_showValuePath, true); - } - set - { - SetXmlNodeBool(_showValuePath, value); - } - } - - - public ExcelConditionalFormattingIconDataBarValue LowValue - { - get; - internal set; - } - - public ExcelConditionalFormattingIconDataBarValue HighValue - { - get; - internal set; - } - - - private const string _colorPath = "d:dataBar/d:color/@rgb"; - public Color Color - { - get - { - var rgb=GetXmlNodeString(_colorPath); - if(!string.IsNullOrEmpty(rgb)) - { - return Color.FromArgb(int.Parse(rgb, NumberStyles.HexNumber)); - } - return Color.White; - } - set - { - SetXmlNodeString(_colorPath, value.ToArgb().ToString("X")); - } - } + var highNode = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(highNode); + HighValue = new( + eExcelConditionalFormattingValueObjectType.Max, + 0, + "", + eExcelConditionalFormattingRuleType.DataBar, + address, + priority, + worksheet, + highNode, + namespaceManager); } -} \ No newline at end of file + Type = type; + } + + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingDataBar( + eExcelConditionalFormattingRuleType type, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNode itemElementNode) + : this(type, address, priority, worksheet, itemElementNode, null) {} + + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingDataBar( + eExcelConditionalFormattingRuleType type, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet) + : this(type, address, priority, worksheet, null, null) {} + + private const string _showValuePath = "d:dataBar/@showValue"; + + public bool ShowValue { + get => GetXmlNodeBool(_showValuePath, true); + set => SetXmlNodeBool(_showValuePath, value); + } + + public ExcelConditionalFormattingIconDataBarValue LowValue { get; internal set; } + + public ExcelConditionalFormattingIconDataBarValue HighValue { get; internal set; } + + private const string _colorPath = "d:dataBar/d:color/@rgb"; + + public Color Color { + get { + var rgb = GetXmlNodeString(_colorPath); + if (!string.IsNullOrEmpty(rgb)) { + return Color.FromArgb(int.Parse(rgb, NumberStyles.HexNumber)); + } + return Color.White; + } + set => SetXmlNodeString(_colorPath, value.ToArgb().ToString("X")); + } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs index d7efca8..1231fc9 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingDuplicateValues.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,106 +13,78 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingDuplicateValues - /// </summary> - public class ExcelConditionalFormattingDuplicateValues - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingDuplicateValues - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingDuplicateValues( +/// <summary> +/// ExcelConditionalFormattingDuplicateValues +/// </summary> +public class ExcelConditionalFormattingDuplicateValues + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingDuplicateValues { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingDuplicateValues( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.DuplicateValues, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - } + eExcelConditionalFormattingRuleType.DuplicateValues, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingDuplicateValues( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingDuplicateValues( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingDuplicateValues( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingDuplicateValues( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs index d9b58c3..d02ed50 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEndsWith.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,138 +13,100 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingEndsWith - /// </summary> - public class ExcelConditionalFormattingEndsWith - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingEndsWith - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingEndsWith( +/// <summary> +/// ExcelConditionalFormattingEndsWith +/// </summary> +public class ExcelConditionalFormattingEndsWith + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingEndsWith { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingEndsWith( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.EndsWith, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.EndsWith, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.EndsWith; - Text = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.EndsWith; + Text = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingEndsWith( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingEndsWith( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingEndsWith( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingEndsWith( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - /****************************************************************************************/ + /// <summary> + /// The text to search in the end of the cell + /// </summary> + public string Text { + get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute); + set { + SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value); - #region Exposed Properties - /// <summary> - /// The text to search in the end of the cell - /// </summary> - public string Text - { - get - { - return GetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute, - value); - - Formula = string.Format( + Formula = string.Format( "RIGHT({0},LEN(\"{1}\"))=\"{1}\"", Address.Start.Address, value.Replace("\"", "\"\"")); - } } - #endregion Exposed Properties - - /****************************************************************************************/ } -} \ No newline at end of file +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs index a93a67d..8a6ed42 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingEqual - /// </summary> - public class ExcelConditionalFormattingEqual - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingEqual - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingEqual( +/// <summary> +/// ExcelConditionalFormattingEqual +/// </summary> +public class ExcelConditionalFormattingEqual + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingEqual { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Equal, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Equal, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.Equal; - Formula = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.Equal; + Formula = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs index c653590..8ba9823 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingExpression.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,110 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingExpression - /// </summary> - public class ExcelConditionalFormattingExpression - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingExpression - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingExpression( +/// <summary> +/// ExcelConditionalFormattingExpression +/// </summary> +public class ExcelConditionalFormattingExpression + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingExpression { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingExpression( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Expression, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Expression, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Formula = string.Empty; - } + Formula = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingExpression( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingExpression( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingExpression( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingExpression( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs index 627128f..8c557d7 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFiveIconSet.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,168 +13,137 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingThreeIconSet +/// </summary> +public class ExcelConditionalFormattingFiveIconSet + : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting5IconsSetType>, + IExcelConditionalFormattingFiveIconSet { /// <summary> - /// ExcelConditionalFormattingThreeIconSet + /// /// </summary> - public class ExcelConditionalFormattingFiveIconSet - : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting5IconsSetType>, IExcelConditionalFormattingFiveIconSet - { - /****************************************************************************************/ - - #region Private Properties - - #endregion Private Properties - - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingFiveIconSet( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingFiveIconSet( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.FiveIconSet, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - if (itemElementNode != null && itemElementNode.HasChildNodes) - { - XmlNode iconNode4 = TopNode.SelectSingleNode("d:iconSet/d:cfvo[position()=4]", NameSpaceManager); - Icon4 = new ExcelConditionalFormattingIconDataBarValue( - eExcelConditionalFormattingRuleType.FiveIconSet, - address, - worksheet, - iconNode4, - namespaceManager); - - XmlNode iconNode5 = TopNode.SelectSingleNode("d:iconSet/d:cfvo[position()=5]", NameSpaceManager); - Icon5 = new ExcelConditionalFormattingIconDataBarValue( - eExcelConditionalFormattingRuleType.FiveIconSet, - address, - worksheet, - iconNode5, - namespaceManager); - } - else - { - XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager); - var iconNode4 = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(iconNode4); + eExcelConditionalFormattingRuleType.FiveIconSet, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode != null && itemElementNode.HasChildNodes) { + XmlNode iconNode4 = TopNode.SelectSingleNode( + "d:iconSet/d:cfvo[position()=4]", + NameSpaceManager); + Icon4 = new( + eExcelConditionalFormattingRuleType.FiveIconSet, + address, + worksheet, + iconNode4, + namespaceManager); - Icon4 = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Percent, - 60, - "", - eExcelConditionalFormattingRuleType.ThreeIconSet, - address, - priority, - worksheet, - iconNode4, - namespaceManager); + XmlNode iconNode5 = TopNode.SelectSingleNode( + "d:iconSet/d:cfvo[position()=5]", + NameSpaceManager); + Icon5 = new( + eExcelConditionalFormattingRuleType.FiveIconSet, + address, + worksheet, + iconNode5, + namespaceManager); + } else { + XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager); + var iconNode4 = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(iconNode4); - var iconNode5 = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(iconNode5); + Icon4 = new( + eExcelConditionalFormattingValueObjectType.Percent, + 60, + "", + eExcelConditionalFormattingRuleType.ThreeIconSet, + address, + priority, + worksheet, + iconNode4, + namespaceManager); - Icon5 = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Percent, - 80, - "", - eExcelConditionalFormattingRuleType.ThreeIconSet, - address, - priority, - worksheet, - iconNode5, - namespaceManager); - } + var iconNode5 = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(iconNode5); + + Icon5 = new( + eExcelConditionalFormattingValueObjectType.Percent, + 80, + "", + eExcelConditionalFormattingRuleType.ThreeIconSet, + address, + priority, + worksheet, + iconNode5, + namespaceManager); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingFiveIconSet( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingFiveIconSet( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingFiveIconSet( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingFiveIconSet( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - public ExcelConditionalFormattingIconDataBarValue Icon5 - { - get; - internal set; - } + public ExcelConditionalFormattingIconDataBarValue Icon5 { get; internal set; } - public ExcelConditionalFormattingIconDataBarValue Icon4 - { - get; - internal set; - } - } - } + public ExcelConditionalFormattingIconDataBarValue Icon4 { get; internal set; } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs index 476441f..14430b9 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingFourIconSet.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,142 +13,109 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingThreeIconSet +/// </summary> +public class ExcelConditionalFormattingFourIconSet + : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting4IconsSetType>, + IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> { /// <summary> - /// ExcelConditionalFormattingThreeIconSet + /// /// </summary> - public class ExcelConditionalFormattingFourIconSet - : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting4IconsSetType>, IExcelConditionalFormattingFourIconSet<eExcelconditionalFormatting4IconsSetType> - { - /****************************************************************************************/ - - #region Private Properties - - #endregion Private Properties - - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingFourIconSet( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingFourIconSet( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.FourIconSet, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - if(itemElementNode!=null && itemElementNode.HasChildNodes) - { - XmlNode iconNode4 = TopNode.SelectSingleNode("d:iconSet/d:cfvo[position()=4]", NameSpaceManager); - Icon4 = new ExcelConditionalFormattingIconDataBarValue( - eExcelConditionalFormattingRuleType.FourIconSet, - address, - worksheet, - iconNode4, - namespaceManager); - } - else - { - XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager); - var iconNode4 = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(iconNode4); + eExcelConditionalFormattingRuleType.FourIconSet, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode != null && itemElementNode.HasChildNodes) { + XmlNode iconNode4 = TopNode.SelectSingleNode( + "d:iconSet/d:cfvo[position()=4]", + NameSpaceManager); + Icon4 = new( + eExcelConditionalFormattingRuleType.FourIconSet, + address, + worksheet, + iconNode4, + namespaceManager); + } else { + XmlNode iconSetNode = TopNode.SelectSingleNode("d:iconSet", NameSpaceManager); + var iconNode4 = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(iconNode4); - - Icon4 = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Percent, - 75, - "", - eExcelConditionalFormattingRuleType.ThreeIconSet, - address, - priority, - worksheet, - iconNode4, - namespaceManager); - } + Icon4 = new( + eExcelConditionalFormattingValueObjectType.Percent, + 75, + "", + eExcelConditionalFormattingRuleType.ThreeIconSet, + address, + priority, + worksheet, + iconNode4, + namespaceManager); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingFourIconSet( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingFourIconSet( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingFourIconSet( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingFourIconSet( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - public ExcelConditionalFormattingIconDataBarValue Icon4 - { - get; - internal set; - } - } - } + public ExcelConditionalFormattingIconDataBarValue Icon4 { get; internal set; } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs index ea5ecac..2e3d9ee 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThan.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingGreaterThan - /// </summary> - public class ExcelConditionalFormattingGreaterThan - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingGreaterThan - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingGreaterThan( +/// <summary> +/// ExcelConditionalFormattingGreaterThan +/// </summary> +public class ExcelConditionalFormattingGreaterThan + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingGreaterThan { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingGreaterThan( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.GreaterThan, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.GreaterThan, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.GreaterThan; - Formula = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.GreaterThan; + Formula = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingGreaterThan( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingGreaterThan( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingGreaterThan( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingGreaterThan( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs index f0d652b..6a19464 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingGreaterThanOrEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingGreaterThanOrEqual - /// </summary> - public class ExcelConditionalFormattingGreaterThanOrEqual - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingGreaterThanOrEqual - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingGreaterThanOrEqual( +/// <summary> +/// ExcelConditionalFormattingGreaterThanOrEqual +/// </summary> +public class ExcelConditionalFormattingGreaterThanOrEqual + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingGreaterThanOrEqual { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingGreaterThanOrEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.GreaterThanOrEqual, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.GreaterThanOrEqual, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.GreaterThanOrEqual; - Formula = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.GreaterThanOrEqual; + Formula = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingGreaterThanOrEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingGreaterThanOrEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingGreaterThanOrEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingGreaterThanOrEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs index ef70a93..e2593d3 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLast7Days.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingLast7Days +/// </summary> +public class ExcelConditionalFormattingLast7Days : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingLast7Days + /// /// </summary> - public class ExcelConditionalFormattingLast7Days - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingLast7Days( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingLast7Days( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Last7Days, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Last7Days, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.Last7Days; - Formula = string.Format( - "AND(TODAY()-FLOOR({0},1)<=6,FLOOR({0},1)<=TODAY())", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.Last7Days; + Formula = string.Format( + "AND(TODAY()-FLOOR({0},1)<=6,FLOOR({0},1)<=TODAY())", + Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingLast7Days( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingLast7Days( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingLast7Days( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingLast7Days( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs index 90689d4..1d31a44 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastMonth.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingLastMonth +/// </summary> +public class ExcelConditionalFormattingLastMonth : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingLastMonth + /// /// </summary> - public class ExcelConditionalFormattingLastMonth - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingLastMonth( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingLastMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.LastMonth, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.LastMonth, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.LastMonth; - Formula = string.Format( - "AND(MONTH({0})=MONTH(EDATE(TODAY(),0-1)),YEAR({0})=YEAR(EDATE(TODAY(),0-1)))", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.LastMonth; + Formula = string.Format( + "AND(MONTH({0})=MONTH(EDATE(TODAY(),0-1)),YEAR({0})=YEAR(EDATE(TODAY(),0-1)))", + Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingLastMonth( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingLastMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingLastMonth( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingLastMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs index b356496..05c6513 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLastWeek.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingLastWeek +/// </summary> +public class ExcelConditionalFormattingLastWeek : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingLastWeek + /// /// </summary> - public class ExcelConditionalFormattingLastWeek - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingLastWeek( + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingLastWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.LastWeek, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.LastWeek, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.LastWeek; - Formula = string.Format( - "AND(TODAY()-ROUNDDOWN({0},0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN({0},0)<(WEEKDAY(TODAY())+7))", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.LastWeek; + Formula = string.Format( + "AND(TODAY()-ROUNDDOWN({0},0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN({0},0)<(WEEKDAY(TODAY())+7))", + Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingLastWeek( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingLastWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingLastWeek( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingLastWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs index 91cb2ac..de178ec 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThan.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingLessThan - /// </summary> - public class ExcelConditionalFormattingLessThan - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingLessThan - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingLessThan( +/// <summary> +/// ExcelConditionalFormattingLessThan +/// </summary> +public class ExcelConditionalFormattingLessThan + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingLessThan { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingLessThan( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.LessThan, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.LessThan, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.LessThan; - Formula = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.LessThan; + Formula = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingLessThan( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingLessThan( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingLessThan( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingLessThan( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs index e774cf6..7c43a2e 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingLessThanOrEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingLessThanOrEqual - /// </summary> - public class ExcelConditionalFormattingLessThanOrEqual - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingLessThanOrEqual - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingLessThanOrEqual( +/// <summary> +/// ExcelConditionalFormattingLessThanOrEqual +/// </summary> +public class ExcelConditionalFormattingLessThanOrEqual + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingLessThanOrEqual { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingLessThanOrEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.LessThanOrEqual, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.LessThanOrEqual, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.LessThanOrEqual; - Formula = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.LessThanOrEqual; + Formula = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingLessThanOrEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingLessThanOrEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingLessThanOrEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingLessThanOrEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs index 98933a6..3d756f4 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextMonth.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingNextMonth +/// </summary> +public class ExcelConditionalFormattingNextMonth : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingNextMonth + /// /// </summary> - public class ExcelConditionalFormattingNextMonth - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingNextMonth( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingNextMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.NextMonth, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.NextMonth, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.NextMonth; - Formula = string.Format( - "AND(MONTH({0})=MONTH(EDATE(TODAY(),0+1)), YEAR({0})=YEAR(EDATE(TODAY(),0+1)))", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.NextMonth; + Formula = string.Format( + "AND(MONTH({0})=MONTH(EDATE(TODAY(),0+1)), YEAR({0})=YEAR(EDATE(TODAY(),0+1)))", + Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingNextMonth( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingNextMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingNextMonth( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingNextMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs index ed610bd..95726a1 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNextWeek.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingNextWeek +/// </summary> +public class ExcelConditionalFormattingNextWeek : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingNextWeek + /// /// </summary> - public class ExcelConditionalFormattingNextWeek - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingNextWeek( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingNextWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.NextWeek, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.NextWeek, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.NextWeek; - Formula = string.Format( - "AND(ROUNDDOWN({0},0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN({0},0)-TODAY()<(15-WEEKDAY(TODAY())))", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.NextWeek; + Formula = string.Format( + "AND(ROUNDDOWN({0},0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN({0},0)-TODAY()<(15-WEEKDAY(TODAY())))", + Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingNextWeek( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingNextWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingNextWeek( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingNextWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs index 116dd6d..71c565c 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotBetween.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingNotBetween - /// </summary> - public class ExcelConditionalFormattingNotBetween - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingNotBetween - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingNotBetween( +/// <summary> +/// ExcelConditionalFormattingNotBetween +/// </summary> +public class ExcelConditionalFormattingNotBetween + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingNotBetween { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingNotBetween( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.NotBetween, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.NotBetween, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.NotBetween; - Formula = string.Empty; - Formula2 = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.NotBetween; + Formula = string.Empty; + Formula2 = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingNotBetween( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingNotBetween( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingNotBetween( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingNotBetween( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs index 8607db4..b0e06b2 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsBlanks.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingNotContainsBlanks - /// </summary> - public class ExcelConditionalFormattingNotContainsBlanks - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingNotContainsBlanks - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingNotContainsBlanks( +/// <summary> +/// ExcelConditionalFormattingNotContainsBlanks +/// </summary> +public class ExcelConditionalFormattingNotContainsBlanks + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingNotContainsBlanks { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingNotContainsBlanks( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.NotContainsBlanks, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.NotContainsBlanks, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Formula = string.Format( - "LEN(TRIM({0}))>0", - Address.Start.Address); - } + Formula = string.Format("LEN(TRIM({0}))>0", Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingNotContainsBlanks( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingNotContainsBlanks( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingNotContainsBlanks( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingNotContainsBlanks( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs index 9b30895..7d42bd3 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsErrors.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingNotContainsErrors - /// </summary> - public class ExcelConditionalFormattingNotContainsErrors - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingNotContainsErrors - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingNotContainsErrors( +/// <summary> +/// ExcelConditionalFormattingNotContainsErrors +/// </summary> +public class ExcelConditionalFormattingNotContainsErrors + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingNotContainsErrors { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingNotContainsErrors( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.NotContainsErrors, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.NotContainsErrors, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Formula = string.Format( - "NOT(ISERROR({0}))", - Address.Start.Address); - } + Formula = string.Format("NOT(ISERROR({0}))", Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingNotContainsErrors( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingNotContainsErrors( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingNotContainsErrors( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingNotContainsErrors( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs index 7b8ac46..279d6b4 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotContainsText.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,138 +13,100 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingNotContainsText - /// </summary> - public class ExcelConditionalFormattingNotContainsText - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingNotContainsText - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingNotContainsText( +/// <summary> +/// ExcelConditionalFormattingNotContainsText +/// </summary> +public class ExcelConditionalFormattingNotContainsText + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingNotContainsText { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingNotContainsText( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.NotContainsText, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.NotContainsText, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.NotContains; - Text = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.NotContains; + Text = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingNotContainsText( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingNotContainsText( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingNotContainsText( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingNotContainsText( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - /****************************************************************************************/ + /// <summary> + /// The text to search inside the cell + /// </summary> + public string Text { + get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute); + set { + SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._textAttribute, value); - #region Exposed Properties - /// <summary> - /// The text to search inside the cell - /// </summary> - public string Text - { - get - { - return GetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TextAttribute, - value); - - Formula = string.Format( + Formula = string.Format( "ISERROR(SEARCH(\"{1}\",{0}))", Address.Start.Address, value.Replace("\"", "\"\"")); - } } - #endregion Exposed Properties - - /****************************************************************************************/ } -} \ No newline at end of file +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs index 06d8d05..e882682 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingNotEqual.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,111 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingNotEqual - /// </summary> - public class ExcelConditionalFormattingNotEqual - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingNotEqual - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingNotEqual( +/// <summary> +/// ExcelConditionalFormattingNotEqual +/// </summary> +public class ExcelConditionalFormattingNotEqual + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingNotEqual { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingNotEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.NotEqual, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.NotEqual, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Operator = eExcelConditionalFormattingOperatorType.NotEqual; - Formula = string.Empty; - } + Operator = eExcelConditionalFormattingOperatorType.NotEqual; + Formula = string.Empty; } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingNotEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingNotEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingNotEqual( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingNotEqual( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs index ae285b1..a9a12ae 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingRule.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,616 +13,477 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; using System.Xml; -using OfficeOpenXml.Utils; -using System.Text.RegularExpressions; using OfficeOpenXml.ConditionalFormatting.Contracts; using OfficeOpenXml.Style.Dxf; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// +/// </summary> +public abstract class ExcelConditionalFormattingRule : XmlHelper, IExcelConditionalFormattingRule { + private eExcelConditionalFormattingRuleType? _type; + private ExcelWorksheet _worksheet; + /// <summary> - /// + /// Sinalize that we are in a Cnaging Priorities opeartion so that we won't enter + /// a recursive loop. /// </summary> - public abstract class ExcelConditionalFormattingRule - : XmlHelper, - IExcelConditionalFormattingRule - { - /****************************************************************************************/ + private static bool _changingPriority; - #region Private Properties - private eExcelConditionalFormattingRuleType? _type; - private ExcelWorksheet _worksheet; - - /// <summary> - /// Sinalize that we are in a Cnaging Priorities opeartion so that we won't enter - /// a recursive loop. - /// </summary> - private static bool _changingPriority = false; - #endregion Private Properties - - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// Initialize the <see cref="ExcelConditionalFormattingRule"/> - /// </summary> - /// <param name="type"></param> - /// <param name="address"></param> - /// <param name="priority">Used also as the cfRule unique key</param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingRule( + /// <summary> + /// Initialize the <see cref="ExcelConditionalFormattingRule"/> + /// </summary> + /// <param name="type"></param> + /// <param name="address"></param> + /// <param name="priority">Used also as the cfRule unique key</param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingRule( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base( - namespaceManager, - itemElementNode) - { - Require.Argument(address).IsNotNull("address"); - Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); - Require.Argument(worksheet).IsNotNull("worksheet"); + : base(namespaceManager, itemElementNode) { + Require.Argument(address).IsNotNull("address"); + Require.Argument(priority).IsInRange(1, int.MaxValue, "priority"); + Require.Argument(worksheet).IsNotNull("worksheet"); - _type = type; - _worksheet = worksheet; - SchemaNodeOrder = _worksheet.SchemaNodeOrder; + _type = type; + _worksheet = worksheet; + SchemaNodeOrder = _worksheet.SchemaNodeOrder; - if (itemElementNode == null) - { - // Create/Get the <cfRule> inside <conditionalFormatting> - itemElementNode = CreateComplexNode( + if (itemElementNode == null) { + // Create/Get the <cfRule> inside <conditionalFormatting> + itemElementNode = CreateComplexNode( _worksheet.WorksheetXml.DocumentElement, string.Format( - "{0}[{1}='{2}']/{1}='{2}'/{3}[{4}='{5}']/{4}='{5}'", - //{0} - ExcelConditionalFormattingConstants.Paths.ConditionalFormatting, - // {1} - ExcelConditionalFormattingConstants.Paths.SqrefAttribute, - // {2} - address.AddressSpaceSeparated, //CF node don't what to have comma between multi addresses, use space instead. - // {3} - ExcelConditionalFormattingConstants.Paths.CfRule, - //{4} - ExcelConditionalFormattingConstants.Paths.PriorityAttribute, - //{5} - priority)); - } - - // Point to <cfRule> - TopNode = itemElementNode; - - Address = address; - Priority = priority; - Type = type; - if (DxfId >= 0) - { - worksheet.Workbook.Styles.Dxfs[DxfId].AllowChange = true; //This Id is referenced by CF, so we can use it when we save. - _style = worksheet.Workbook.Styles.Dxfs[DxfId].Clone(); //Clone, so it can be altered without effecting other dxf styles - } + "{0}[{1}='{2}']/{1}='{2}'/{3}[{4}='{5}']/{4}='{5}'", + //{0} + ExcelConditionalFormattingConstants.Paths._conditionalFormatting, + // {1} + ExcelConditionalFormattingConstants.Paths._sqrefAttribute, + // {2} + address.AddressSpaceSeparated, //CF node don't what to have comma between multi addresses, use space instead. + // {3} + ExcelConditionalFormattingConstants.Paths._cfRule, + //{4} + ExcelConditionalFormattingConstants.Paths._priorityAttribute, + //{5} + priority)); } - /// <summary> - /// Initialize the <see cref="ExcelConditionalFormattingRule"/> - /// </summary> - /// <param name="type"></param> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingRule( + // Point to <cfRule> + TopNode = itemElementNode; + + Address = address; + Priority = priority; + Type = type; + if (DxfId >= 0) { + worksheet.Workbook.Styles.Dxfs[DxfId].AllowChange = true; //This Id is referenced by CF, so we can use it when we save. + _style = worksheet.Workbook.Styles.Dxfs[DxfId].Clone(); //Clone, so it can be altered without effecting other dxf styles + } + } + + /// <summary> + /// Initialize the <see cref="ExcelConditionalFormattingRule"/> + /// </summary> + /// <param name="type"></param> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingRule( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNamespaceManager namespaceManager) - : this( - type, - address, - priority, - worksheet, - null, - namespaceManager) - { - } - #endregion Constructors + : this(type, address, priority, worksheet, null, namespaceManager) {} - /****************************************************************************************/ + /// <summary> + /// Get the <cfRule> node + /// </summary> + public XmlNode Node => TopNode; - #region Methods - #endregion Methods + /// <summary> + /// Address of the conditional formatting rule + /// </summary> + /// <remarks> + /// The address is stores in a parent node called <conditionalFormatting> in the + /// @sqref attribute. Excel groups rules that have the same address inside one node. + /// </remarks> + public ExcelAddress Address { + get => + new(Node.ParentNode.Attributes[ExcelConditionalFormattingConstants.Attributes._sqref].Value); + set { + // Check if the address is to be changed + if (Address.Address != value.Address) { + // Save the old parente node + XmlNode oldNode = Node; + XmlNode oldParentNode = Node.ParentNode; - /****************************************************************************************/ - - #region Exposed Properties - /// <summary> - /// Get the <cfRule> node - /// </summary> - public XmlNode Node - { - get { return TopNode; } - } - - /// <summary> - /// Address of the conditional formatting rule - /// </summary> - /// <remarks> - /// The address is stores in a parent node called <conditionalFormatting> in the - /// @sqref attribute. Excel groups rules that have the same address inside one node. - /// </remarks> - public ExcelAddress Address - { - get - { - return new ExcelAddress( - Node.ParentNode.Attributes[ExcelConditionalFormattingConstants.Attributes.Sqref].Value); - } - set - { - // Check if the address is to be changed - if (Address.Address != value.Address) - { - // Save the old parente node - XmlNode oldNode = Node; - XmlNode oldParentNode = Node.ParentNode; - - // Create/Get the new <conditionalFormatting> parent node - XmlNode newParentNode = CreateComplexNode( + // Create/Get the new <conditionalFormatting> parent node + XmlNode newParentNode = CreateComplexNode( _worksheet.WorksheetXml.DocumentElement, string.Format( - "{0}[{1}='{2}']/{1}='{2}'", - //{0} - ExcelConditionalFormattingConstants.Paths.ConditionalFormatting, - // {1} - ExcelConditionalFormattingConstants.Paths.SqrefAttribute, - // {2} - value.AddressSpaceSeparated)); + "{0}[{1}='{2}']/{1}='{2}'", + //{0} + ExcelConditionalFormattingConstants.Paths._conditionalFormatting, + // {1} + ExcelConditionalFormattingConstants.Paths._sqrefAttribute, + // {2} + value.AddressSpaceSeparated)); - // Move the <cfRule> node to the new <conditionalFormatting> parent node - TopNode = newParentNode.AppendChild(Node); + // Move the <cfRule> node to the new <conditionalFormatting> parent node + TopNode = newParentNode.AppendChild(Node); - // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it - if (!oldParentNode.HasChildNodes) - { - // Remove the old parent node - oldParentNode.ParentNode.RemoveChild(oldParentNode); - } + // Check if the old <conditionalFormatting> parent node has <cfRule> node inside it + if (!oldParentNode.HasChildNodes) { + // Remove the old parent node + oldParentNode.ParentNode.RemoveChild(oldParentNode); } } } + } - /// <summary> - /// Type of conditional formatting rule. ST_CfType §18.18.12. - /// </summary> - public eExcelConditionalFormattingRuleType Type - { - get - { - // Transform the @type attribute to EPPlus Rule Type (slighty diferente) - if(_type==null) - { - _type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute( - GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TypeAttribute), - TopNode, - _worksheet.NameSpaceManager); - } - return (eExcelConditionalFormattingRuleType)_type; + /// <summary> + /// Type of conditional formatting rule. ST_CfType §18.18.12. + /// </summary> + public eExcelConditionalFormattingRuleType Type { + get { + // Transform the @type attribute to EPPlus Rule Type (slighty diferente) + if (_type == null) { + _type = ExcelConditionalFormattingRuleType.GetTypeByAttrbiute( + GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._typeAttribute), + TopNode, + _worksheet.NameSpaceManager); } - internal set - { - _type = value; - // Transform the EPPlus Rule Type to @type attribute (slighty diferente) - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TypeAttribute, + return (eExcelConditionalFormattingRuleType)_type; + } + internal set { + _type = value; + // Transform the EPPlus Rule Type to @type attribute (slighty diferente) + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._typeAttribute, ExcelConditionalFormattingRuleType.GetAttributeByType(value), true); - } } + } - /// <summary> - /// The priority of this conditional formatting rule. This value is used to determine - /// which format should be evaluated and rendered. Lower numeric values are higher - /// priority than higher numeric values, where 1 is the highest priority. - /// </summary> - public int Priority - { - get - { - return GetXmlNodeInt( - ExcelConditionalFormattingConstants.Paths.PriorityAttribute); - } - set - { - // Save the current CF rule priority - int priority = Priority; + /// <summary> + /// The priority of this conditional formatting rule. This value is used to determine + /// which format should be evaluated and rendered. Lower numeric values are higher + /// priority than higher numeric values, where 1 is the highest priority. + /// </summary> + public int Priority { + get => GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._priorityAttribute); + set { + // Save the current CF rule priority + int priority = Priority; - // Check if the @priority is to be changed - if (priority != value) - { - // Check if we are not already inside a "Change Priority" operation - if (!_changingPriority) - { - if (value < 1) - { - throw new IndexOutOfRangeException( - ExcelConditionalFormattingConstants.Errors.InvalidPriority); - } - - // Sinalize that we are already changing cfRules priorities - _changingPriority = true; - - // Check if we lowered the priority - if (priority > value) - { - for (int i = priority - 1; i >= value; i--) - { - var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i); - - if (cfRule != null) - { - cfRule.Priority++; - } - } - } - else - { - for (int i = priority + 1; i <= value; i++) - { - var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i); - - if (cfRule != null) - { - cfRule.Priority--; - } - } - } - - // Sinalize that we are no longer changing cfRules priorities - _changingPriority = false; + // Check if the @priority is to be changed + if (priority != value) { + // Check if we are not already inside a "Change Priority" operation + if (!_changingPriority) { + if (value < 1) { + throw new IndexOutOfRangeException( + ExcelConditionalFormattingConstants.Errors._invalidPriority); } - // Change the priority in the XML - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.PriorityAttribute, + // Sinalize that we are already changing cfRules priorities + _changingPriority = true; + + // Check if we lowered the priority + if (priority > value) { + for (int i = priority - 1; i >= value; i--) { + var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i); + + if (cfRule != null) { + cfRule.Priority++; + } + } + } else { + for (int i = priority + 1; i <= value; i++) { + var cfRule = _worksheet.ConditionalFormatting.RulesByPriority(i); + + if (cfRule != null) { + cfRule.Priority--; + } + } + } + + // Sinalize that we are no longer changing cfRules priorities + _changingPriority = false; + } + + // Change the priority in the XML + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._priorityAttribute, value.ToString(), true); - } } } + } - /// <summary> - /// If this flag is true, no rules with lower priority shall be applied over this rule, - /// when this rule evaluates to true. - /// </summary> - public bool StopIfTrue - { - get - { - return GetXmlNodeBool( - ExcelConditionalFormattingConstants.Paths.StopIfTrueAttribute); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.StopIfTrueAttribute, - (value == true) ? "1" : string.Empty, + /// <summary> + /// If this flag is true, no rules with lower priority shall be applied over this rule, + /// when this rule evaluates to true. + /// </summary> + public bool StopIfTrue { + get => GetXmlNodeBool(ExcelConditionalFormattingConstants.Paths._stopIfTrueAttribute); + set => + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._stopIfTrueAttribute, + value ? "1" : string.Empty, true); - } - } + } - /// <summary> - /// DxfId Style Attribute - /// </summary> - internal int DxfId - { - get - { - return GetXmlNodeInt( - ExcelConditionalFormattingConstants.Paths.DxfIdAttribute); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.DxfIdAttribute, + /// <summary> + /// DxfId Style Attribute + /// </summary> + internal int DxfId { + get => GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._dxfIdAttribute); + set => + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._dxfIdAttribute, (value == int.MinValue) ? string.Empty : value.ToString(), true); + } + + internal ExcelDxfStyleConditionalFormatting _style; + + public ExcelDxfStyleConditionalFormatting Style { + get { + if (_style == null) { + _style = new(NameSpaceManager, null, _worksheet.Workbook.Styles); } + return _style; } - internal ExcelDxfStyleConditionalFormatting _style = null; - public ExcelDxfStyleConditionalFormatting Style - { - get - { - if (_style == null) - { - _style = new ExcelDxfStyleConditionalFormatting(NameSpaceManager, null, _worksheet.Workbook.Styles); - } - return _style; - } - } - /// <summary> - /// StdDev (zero is not allowed and will be converted to 1) - /// </summary> - public UInt16 StdDev - { - get - { - return Convert.ToUInt16(GetXmlNodeInt( - ExcelConditionalFormattingConstants.Paths.StdDevAttribute)); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.StdDevAttribute, + } + + /// <summary> + /// StdDev (zero is not allowed and will be converted to 1) + /// </summary> + public UInt16 StdDev { + get => + Convert.ToUInt16(GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._stdDevAttribute)); + set => + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._stdDevAttribute, (value == 0) ? "1" : value.ToString(), true); - } - } + } - /// <summary> - /// Rank (zero is not allowed and will be converted to 1) - /// </summary> - public UInt16 Rank - { - get - { - return Convert.ToUInt16(GetXmlNodeInt( - ExcelConditionalFormattingConstants.Paths.RankAttribute)); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.RankAttribute, + /// <summary> + /// Rank (zero is not allowed and will be converted to 1) + /// </summary> + public UInt16 Rank { + get => + Convert.ToUInt16(GetXmlNodeInt(ExcelConditionalFormattingConstants.Paths._rankAttribute)); + set => + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._rankAttribute, (value == 0) ? "1" : value.ToString(), true); - } + } + + /// <summary> + /// AboveAverage + /// </summary> + internal protected bool? AboveAverage { + get { + bool? aboveAverage = GetXmlNodeBoolNullable( + ExcelConditionalFormattingConstants.Paths._aboveAverageAttribute); + + // Above Avarege if TRUE or if attribute does not exists + return (aboveAverage == true) || (aboveAverage == null); } - #endregion Exposed Properties + set { + string aboveAverageValue = string.Empty; - /****************************************************************************************/ - - #region Internal Properties - /// <summary> - /// AboveAverage - /// </summary> - internal protected bool? AboveAverage - { - get - { - bool? aboveAverage = GetXmlNodeBoolNullable( - ExcelConditionalFormattingConstants.Paths.AboveAverageAttribute); - - // Above Avarege if TRUE or if attribute does not exists - return (aboveAverage == true) || (aboveAverage == null); - } - set - { - string aboveAverageValue = string.Empty; - - // Only the types that needs the @AboveAverage - if ((_type == eExcelConditionalFormattingRuleType.BelowAverage) + // Only the types that needs the @AboveAverage + if ((_type == eExcelConditionalFormattingRuleType.BelowAverage) || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage) - || (_type == eExcelConditionalFormattingRuleType.BelowStdDev)) - { - aboveAverageValue = "0"; - } + || (_type == eExcelConditionalFormattingRuleType.BelowStdDev)) { + aboveAverageValue = "0"; + } - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.AboveAverageAttribute, + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._aboveAverageAttribute, aboveAverageValue, true); - } } + } - /// <summary> - /// EqualAverage - /// </summary> - internal protected bool? EqualAverage - { - get - { - bool? equalAverage = GetXmlNodeBoolNullable( - ExcelConditionalFormattingConstants.Paths.EqualAverageAttribute); + /// <summary> + /// EqualAverage + /// </summary> + internal protected bool? EqualAverage { + get { + bool? equalAverage = GetXmlNodeBoolNullable( + ExcelConditionalFormattingConstants.Paths._equalAverageAttribute); - // Equal Avarege only if TRUE - return (equalAverage == true); + // Equal Avarege only if TRUE + return (equalAverage == true); + } + set { + string equalAverageValue = string.Empty; + + // Only the types that needs the @EqualAverage + if ((_type == eExcelConditionalFormattingRuleType.AboveOrEqualAverage) + || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage)) { + equalAverageValue = "1"; } - set - { - string equalAverageValue = string.Empty; - // Only the types that needs the @EqualAverage - if ((_type == eExcelConditionalFormattingRuleType.AboveOrEqualAverage) - || (_type == eExcelConditionalFormattingRuleType.BelowOrEqualAverage)) - { - equalAverageValue = "1"; - } - - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.EqualAverageAttribute, + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._equalAverageAttribute, equalAverageValue, true); - } } + } - /// <summary> - /// Bottom attribute - /// </summary> - internal protected bool? Bottom - { - get - { - bool? bottom = GetXmlNodeBoolNullable( - ExcelConditionalFormattingConstants.Paths.BottomAttribute); + /// <summary> + /// Bottom attribute + /// </summary> + internal protected bool? Bottom { + get { + bool? bottom = GetXmlNodeBoolNullable( + ExcelConditionalFormattingConstants.Paths._bottomAttribute); - // Bottom if TRUE - return (bottom == true); + // Bottom if TRUE + return (bottom == true); + } + set { + string bottomValue = string.Empty; + + // Only the types that needs the @Bottom + if ((_type == eExcelConditionalFormattingRuleType.Bottom) + || (_type == eExcelConditionalFormattingRuleType.BottomPercent)) { + bottomValue = "1"; } - set - { - string bottomValue = string.Empty; - // Only the types that needs the @Bottom - if ((_type == eExcelConditionalFormattingRuleType.Bottom) - || (_type == eExcelConditionalFormattingRuleType.BottomPercent)) - { - bottomValue = "1"; - } - - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.BottomAttribute, + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._bottomAttribute, bottomValue, true); - } } + } - /// <summary> - /// Percent attribute - /// </summary> - internal protected bool? Percent - { - get - { - bool? percent = GetXmlNodeBoolNullable( - ExcelConditionalFormattingConstants.Paths.PercentAttribute); + /// <summary> + /// Percent attribute + /// </summary> + internal protected bool? Percent { + get { + bool? percent = GetXmlNodeBoolNullable( + ExcelConditionalFormattingConstants.Paths._percentAttribute); - // Bottom if TRUE - return (percent == true); + // Bottom if TRUE + return (percent == true); + } + set { + string percentValue = string.Empty; + + // Only the types that needs the @Bottom + if ((_type == eExcelConditionalFormattingRuleType.BottomPercent) + || (_type == eExcelConditionalFormattingRuleType.TopPercent)) { + percentValue = "1"; } - set - { - string percentValue = string.Empty; - // Only the types that needs the @Bottom - if ((_type == eExcelConditionalFormattingRuleType.BottomPercent) - || (_type == eExcelConditionalFormattingRuleType.TopPercent)) - { - percentValue = "1"; - } - - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.PercentAttribute, + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._percentAttribute, percentValue, true); - } } + } - /// <summary> - /// TimePeriod - /// </summary> - internal protected eExcelConditionalFormattingTimePeriodType TimePeriod - { - get - { - return ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute( - GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.TimePeriodAttribute)); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.TimePeriodAttribute, + /// <summary> + /// TimePeriod + /// </summary> + internal protected eExcelConditionalFormattingTimePeriodType TimePeriod { + get => + ExcelConditionalFormattingTimePeriodType.GetTypeByAttribute( + GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._timePeriodAttribute)); + set => + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._timePeriodAttribute, ExcelConditionalFormattingTimePeriodType.GetAttributeByType(value), true); - } - } + } - /// <summary> - /// Operator - /// </summary> - internal protected eExcelConditionalFormattingOperatorType Operator - { - get - { - return ExcelConditionalFormattingOperatorType.GetTypeByAttribute( - GetXmlNodeString(ExcelConditionalFormattingConstants.Paths.OperatorAttribute)); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.OperatorAttribute, + /// <summary> + /// Operator + /// </summary> + internal protected eExcelConditionalFormattingOperatorType Operator { + get => + ExcelConditionalFormattingOperatorType.GetTypeByAttribute( + GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._operatorAttribute)); + set => + SetXmlNodeString( + ExcelConditionalFormattingConstants.Paths._operatorAttribute, ExcelConditionalFormattingOperatorType.GetAttributeByType(value), true); - } - } - - /// <summary> - /// Formula - /// </summary> - public string Formula - { - get - { - return GetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.Formula); - } - set - { - SetXmlNodeString( - ExcelConditionalFormattingConstants.Paths.Formula, - value); - } - } - - /// <summary> - /// Formula2 - /// </summary> - public string Formula2 - { - get - { - return GetXmlNodeString( - string.Format( - "{0}[position()=2]", - // {0} - ExcelConditionalFormattingConstants.Paths.Formula)); - } - set - { - // Create/Get the first <formula> node (ensure that it exists) - var firstNode = CreateComplexNode( - TopNode, - string.Format( - "{0}[position()=1]", - // {0} - ExcelConditionalFormattingConstants.Paths.Formula)); - - // Create/Get the seconde <formula> node (ensure that it exists) - var secondNode = CreateComplexNode( - TopNode, - string.Format( - "{0}[position()=2]", - // {0} - ExcelConditionalFormattingConstants.Paths.Formula)); - - // Save the formula in the second <formula> node - secondNode.InnerText = value; - } - } - #endregion Internal Properties - /****************************************************************************************/ } -} \ No newline at end of file + + /// <summary> + /// Formula + /// </summary> + public string Formula { + get => GetXmlNodeString(ExcelConditionalFormattingConstants.Paths._formula); + set => SetXmlNodeString(ExcelConditionalFormattingConstants.Paths._formula, value); + } + + /// <summary> + /// Formula2 + /// </summary> + public string Formula2 { + get => + GetXmlNodeString( + string.Format( + "{0}[position()=2]", + // {0} + ExcelConditionalFormattingConstants.Paths._formula)); + set { + // Create/Get the first <formula> node (ensure that it exists) + var firstNode = CreateComplexNode( + TopNode, + string.Format( + "{0}[position()=1]", + // {0} + ExcelConditionalFormattingConstants.Paths._formula)); + + // Create/Get the seconde <formula> node (ensure that it exists) + var secondNode = CreateComplexNode( + TopNode, + string.Format( + "{0}[position()=2]", + // {0} + ExcelConditionalFormattingConstants.Paths._formula)); + + // Save the formula in the second <formula> node + secondNode.InnerText = value; + } + } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs index c404ca7..6104959 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisMonth.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingThisMonth +/// </summary> +public class ExcelConditionalFormattingThisMonth : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingThisMonth + /// /// </summary> - public class ExcelConditionalFormattingThisMonth - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingThisMonth( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingThisMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.ThisMonth, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.ThisMonth, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisMonth; - Formula = string.Format( - "AND(MONTH({0})=MONTH(TODAY()), YEAR({0})=YEAR(TODAY()))", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisMonth; + Formula = string.Format( + "AND(MONTH({0})=MONTH(TODAY()), YEAR({0})=YEAR(TODAY()))", + Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingThisMonth( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingThisMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingThisMonth( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingThisMonth( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs index 9baa8ad..a42007d 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThisWeek.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingThisWeek +/// </summary> +public class ExcelConditionalFormattingThisWeek : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingThisWeek + /// /// </summary> - public class ExcelConditionalFormattingThisWeek - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingThisWeek( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingThisWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.ThisWeek, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.ThisWeek, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisWeek; - Formula = string.Format( - "AND(TODAY()-ROUNDDOWN({0},0)<=WEEKDAY(TODAY())-1,ROUNDDOWN({0},0)-TODAY()<=7-WEEKDAY(TODAY()))", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.ThisWeek; + Formula = string.Format( + "AND(TODAY()-ROUNDDOWN({0},0)<=WEEKDAY(TODAY())-1,ROUNDDOWN({0},0)-TODAY()<=7-WEEKDAY(TODAY()))", + Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingThisWeek( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingThisWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingThisWeek( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingThisWeek( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs index cb6d46c..a63bf04 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeColorScale.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,103 +13,76 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using System.Drawing; using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingThreeColorScale - /// </summary> - public class ExcelConditionalFormattingThreeColorScale +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingThreeColorScale +/// </summary> +public class ExcelConditionalFormattingThreeColorScale : ExcelConditionalFormattingRule, - IExcelConditionalFormattingThreeColorScale - { - /****************************************************************************************/ - - #region Private Properties - /// <summary> - /// Private Low Value - /// </summary> - private ExcelConditionalFormattingColorScaleValue _lowValue; - - /// <summary> - /// Private Middle Value - /// </summary> - private ExcelConditionalFormattingColorScaleValue _middleValue; - - /// <summary> - /// Private High Value - /// </summary> - private ExcelConditionalFormattingColorScaleValue _highValue; - #endregion Private Properties - - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingThreeColorScale( + IExcelConditionalFormattingThreeColorScale { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingThreeColorScale( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.ThreeColorScale, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - // Create the <colorScale> node inside the <cfRule> node - var colorScaleNode = CreateComplexNode( + eExcelConditionalFormattingRuleType.ThreeColorScale, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + // Create the <colorScale> node inside the <cfRule> node + var colorScaleNode = CreateComplexNode( Node, - ExcelConditionalFormattingConstants.Paths.ColorScale); + ExcelConditionalFormattingConstants.Paths._colorScale); - // LowValue default - LowValue = new ExcelConditionalFormattingColorScaleValue( + // LowValue default + LowValue = new( eExcelConditionalFormattingValueObjectPosition.Low, eExcelConditionalFormattingValueObjectType.Min, - ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors.CfvoLowValue), + ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoLowValue), eExcelConditionalFormattingRuleType.ThreeColorScale, address, priority, worksheet, NameSpaceManager); - // MiddleValue default - MiddleValue = new ExcelConditionalFormattingColorScaleValue( + // MiddleValue default + MiddleValue = new( eExcelConditionalFormattingValueObjectPosition.Middle, eExcelConditionalFormattingValueObjectType.Percent, - ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors.CfvoMiddleValue), + ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoMiddleValue), 50, string.Empty, eExcelConditionalFormattingRuleType.ThreeColorScale, @@ -118,90 +91,56 @@ worksheet, NameSpaceManager); - // HighValue default - HighValue = new ExcelConditionalFormattingColorScaleValue( + // HighValue default + HighValue = new( eExcelConditionalFormattingValueObjectPosition.High, eExcelConditionalFormattingValueObjectType.Max, - ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors.CfvoHighValue), + ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoHighValue), eExcelConditionalFormattingRuleType.ThreeColorScale, address, priority, worksheet, NameSpaceManager); - } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingThreeColorScale( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingThreeColorScale( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingThreeColorScale( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingThreeColorScale( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - /****************************************************************************************/ + /// <summary> + /// Low Value for Three Color Scale Object Value + /// </summary> + public ExcelConditionalFormattingColorScaleValue LowValue { get; set; } - #region Public Properties - /// <summary> - /// Low Value for Three Color Scale Object Value - /// </summary> - public ExcelConditionalFormattingColorScaleValue LowValue - { - get { return _lowValue; } - set { _lowValue = value; } - } + /// <summary> + /// Middle Value for Three Color Scale Object Value + /// </summary> + public ExcelConditionalFormattingColorScaleValue MiddleValue { get; set; } - /// <summary> - /// Middle Value for Three Color Scale Object Value - /// </summary> - public ExcelConditionalFormattingColorScaleValue MiddleValue - { - get { return _middleValue; } - set { _middleValue = value; } - } - - /// <summary> - /// High Value for Three Color Scale Object Value - /// </summary> - public ExcelConditionalFormattingColorScaleValue HighValue - { - get { return _highValue; } - set { _highValue = value; } - } - #endregion Public Properties - - /****************************************************************************************/ - } -} \ No newline at end of file + /// <summary> + /// High Value for Three Color Scale Object Value + /// </summary> + public ExcelConditionalFormattingColorScaleValue HighValue { get; set; } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs index 4ec19e1..cc0a2ad 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingThreeIconSet.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,368 +13,278 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - public class ExcelConditionalFormattingThreeIconSet : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting3IconsSetType> - { - internal ExcelConditionalFormattingThreeIconSet( - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode, - XmlNamespaceManager namespaceManager) - : base( - eExcelConditionalFormattingRuleType.ThreeIconSet, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { +namespace OfficeOpenXml.ConditionalFormatting; + +public class ExcelConditionalFormattingThreeIconSet + : ExcelConditionalFormattingIconSetBase<eExcelconditionalFormatting3IconsSetType> { + internal ExcelConditionalFormattingThreeIconSet( + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base( + eExcelConditionalFormattingRuleType.ThreeIconSet, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) {} +} + +/// <summary> +/// ExcelConditionalFormattingThreeIconSet +/// </summary> +public class ExcelConditionalFormattingIconSetBase<T> + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingThreeIconSet<T> { + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingIconSetBase( + eExcelConditionalFormattingRuleType type, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base( + type, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode != null && itemElementNode.HasChildNodes) { + int pos = 1; + foreach (XmlNode node in itemElementNode.SelectNodes("d:iconSet/d:cfvo", NameSpaceManager)) { + if (pos == 1) { + Icon1 = new(type, address, worksheet, node, namespaceManager); + } else if (pos == 2) { + Icon2 = new(type, address, worksheet, node, namespaceManager); + } else if (pos == 3) { + Icon3 = new(type, address, worksheet, node, namespaceManager); + } else { + break; } + pos++; + } + } else { + var iconSetNode = CreateComplexNode(Node, ExcelConditionalFormattingConstants.Paths._iconSet); + + //Create the <iconSet> node inside the <cfRule> node + double spann; + if (type == eExcelConditionalFormattingRuleType.ThreeIconSet) { + spann = 3; + } else if (type == eExcelConditionalFormattingRuleType.FourIconSet) { + spann = 4; + } else { + spann = 5; + } + + var iconNode1 = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(iconNode1); + Icon1 = new( + eExcelConditionalFormattingValueObjectType.Percent, + 0, + "", + eExcelConditionalFormattingRuleType.ThreeIconSet, + address, + priority, + worksheet, + iconNode1, + namespaceManager); + + var iconNode2 = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(iconNode2); + Icon2 = new( + eExcelConditionalFormattingValueObjectType.Percent, + Math.Round(100D / spann, 0), + "", + eExcelConditionalFormattingRuleType.ThreeIconSet, + address, + priority, + worksheet, + iconNode2, + namespaceManager); + + var iconNode3 = iconSetNode.OwnerDocument.CreateElement( + ExcelConditionalFormattingConstants.Paths._cfvo, + ExcelPackage._schemaMain); + iconSetNode.AppendChild(iconNode3); + Icon3 = new( + eExcelConditionalFormattingValueObjectType.Percent, + Math.Round(100D * (2D / spann), 0), + "", + eExcelConditionalFormattingRuleType.ThreeIconSet, + address, + priority, + worksheet, + iconNode3, + namespaceManager); + Type = type; } - /// <summary> - /// ExcelConditionalFormattingThreeIconSet - /// </summary> - public class ExcelConditionalFormattingIconSetBase<T> - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingThreeIconSet<T> - { - /****************************************************************************************/ + } - #region Private Properties + /// <summary> + /// + /// </summary> + ///<param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingIconSetBase( + eExcelConditionalFormattingRuleType type, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet, + XmlNode itemElementNode) + : this(type, address, priority, worksheet, itemElementNode, null) {} - #endregion Private Properties + /// <summary> + /// + /// </summary> + ///<param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingIconSetBase( + eExcelConditionalFormattingRuleType type, + ExcelAddress address, + int priority, + ExcelWorksheet worksheet) + : this(type, address, priority, worksheet, null, null) {} - /****************************************************************************************/ + /// <summary> + /// Settings for icon 1 in the iconset + /// </summary> + public ExcelConditionalFormattingIconDataBarValue Icon1 { get; internal set; } - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingIconSetBase( - eExcelConditionalFormattingRuleType type, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode, - XmlNamespaceManager namespaceManager) - : base( - type, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - if (itemElementNode != null && itemElementNode.HasChildNodes) - { - int pos = 1; - foreach (XmlNode node in itemElementNode.SelectNodes("d:iconSet/d:cfvo", NameSpaceManager)) - { - if(pos==1) - { - Icon1 = new ExcelConditionalFormattingIconDataBarValue( - type, - address, - worksheet, - node, - namespaceManager); - } - else if (pos == 2) - { - Icon2 = new ExcelConditionalFormattingIconDataBarValue( - type, - address, - worksheet, - node, - namespaceManager); - } - else if (pos == 3) - { - Icon3 = new ExcelConditionalFormattingIconDataBarValue( - type, - address, - worksheet, - node, - namespaceManager); - } - else - { - break; - } - pos++; - } - } - else - { - var iconSetNode = CreateComplexNode( - Node, - ExcelConditionalFormattingConstants.Paths.IconSet); + /// <summary> + /// Settings for icon 2 in the iconset + /// </summary> + public ExcelConditionalFormattingIconDataBarValue Icon2 { get; internal set; } - //Create the <iconSet> node inside the <cfRule> node - double spann; - if (type == eExcelConditionalFormattingRuleType.ThreeIconSet) - { - spann = 3; - } - else if (type == eExcelConditionalFormattingRuleType.FourIconSet) - { - spann = 4; - } - else - { - spann = 5; - } + /// <summary> + /// Settings for icon 2 in the iconset + /// </summary> + public ExcelConditionalFormattingIconDataBarValue Icon3 { get; internal set; } - var iconNode1 = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(iconNode1); - Icon1 = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Percent, - 0, - "", - eExcelConditionalFormattingRuleType.ThreeIconSet, - address, - priority, - worksheet, - iconNode1, - namespaceManager); + private const string _reversePath = "d:iconSet/@reverse"; - var iconNode2 = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(iconNode2); - Icon2 = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Percent, - Math.Round(100D / spann, 0), - "", - eExcelConditionalFormattingRuleType.ThreeIconSet, - address, - priority, - worksheet, - iconNode2, - namespaceManager); + /// <summary> + /// Reverse the order of the icons + /// </summary> + public bool Reverse { + get => GetXmlNodeBool(_reversePath, false); + set => SetXmlNodeBool(_reversePath, value); + } - var iconNode3 = iconSetNode.OwnerDocument.CreateElement(ExcelConditionalFormattingConstants.Paths.Cfvo, ExcelPackage.schemaMain); - iconSetNode.AppendChild(iconNode3); - Icon3 = new ExcelConditionalFormattingIconDataBarValue(eExcelConditionalFormattingValueObjectType.Percent, - Math.Round(100D * (2D / spann), 0), - "", - eExcelConditionalFormattingRuleType.ThreeIconSet, - address, - priority, - worksheet, - iconNode3, - namespaceManager); - Type = type; - } - } + private const string _showValuePath = "d:iconSet/@showValue"; - /// <summary> - /// - /// </summary> - ///<param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingIconSetBase( - eExcelConditionalFormattingRuleType type, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet, - XmlNode itemElementNode) - : this( - type, - address, - priority, - worksheet, - itemElementNode, - null) - { - } + /// <summary> + /// If the cell values are visible + /// </summary> + public bool ShowValue { + get => GetXmlNodeBool(_showValuePath, true); + set => SetXmlNodeBool(_showValuePath, value); + } - /// <summary> - /// - /// </summary> - ///<param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingIconSetBase( - eExcelConditionalFormattingRuleType type, - ExcelAddress address, - int priority, - ExcelWorksheet worksheet) - : this( - type, - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + private const string _iconSetPath = "d:iconSet/@iconSet"; - /// <summary> - /// Settings for icon 1 in the iconset - /// </summary> - public ExcelConditionalFormattingIconDataBarValue Icon1 - { - get; - internal set; - } - - /// <summary> - /// Settings for icon 2 in the iconset - /// </summary> - public ExcelConditionalFormattingIconDataBarValue Icon2 - { - get; - internal set; - } - /// <summary> - /// Settings for icon 2 in the iconset - /// </summary> - public ExcelConditionalFormattingIconDataBarValue Icon3 - { - get; - internal set; - } - private const string _reversePath = "d:iconSet/@reverse"; - /// <summary> - /// Reverse the order of the icons - /// </summary> - public bool Reverse - { - get - { - return GetXmlNodeBool(_reversePath, false); - } - set - { - SetXmlNodeBool(_reversePath, value); - } - } - - private const string _showValuePath = "d:iconSet/@showValue"; - /// <summary> - /// If the cell values are visible - /// </summary> - public bool ShowValue - { - get - { - return GetXmlNodeBool(_showValuePath, true); - } - set - { - SetXmlNodeBool(_showValuePath, value); - } - } - private const string _iconSetPath = "d:iconSet/@iconSet"; - /// <summary> - /// Type of iconset - /// </summary> - public T IconSet - { - get - { - var v = GetXmlNodeString(_iconSetPath); - v = v.Substring(1); //Skip first icon. - return (T)Enum.Parse(typeof(T), v, true); - } - set - { - SetXmlNodeString(_iconSetPath, GetIconSetString(value)); - } - } - private string GetIconSetString(T value) - { - if (Type == eExcelConditionalFormattingRuleType.FourIconSet) - { - switch (value.ToString()) - { - case "Arrows": - return "4Arrows"; - case "ArrowsGray": - return "4ArrowsGray"; - case "Rating": - return "4Rating"; - case "RedToBlack": - return "4RedToBlack"; - case "TrafficLights": - return "4TrafficLights"; - default: - throw (new ArgumentException("Invalid type")); - } - } - else if (Type == eExcelConditionalFormattingRuleType.FiveIconSet) - { - switch (value.ToString()) - { - case "Arrows": - return "5Arrows"; - case "ArrowsGray": - return "5ArrowsGray"; - case "Quarters": - return "5Quarters"; - case "Rating": - return "5Rating"; - default: - throw (new ArgumentException("Invalid type")); - } - } - else - { - switch (value.ToString()) - { - case "Arrows": - return "3Arrows"; - case "ArrowsGray": - return "3ArrowsGray"; - case "Flags": - return "3Flags"; - case "Signs": - return "3Signs"; - case "Symbols": - return "3Symbols"; - case "Symbols2": - return "3Symbols2"; - case "TrafficLights1": - return "3TrafficLights1"; - case "TrafficLights2": - return "3TrafficLights2"; - default: - throw (new ArgumentException("Invalid type")); - } - } - } + /// <summary> + /// Type of iconset + /// </summary> + public T IconSet { + get { + var v = GetXmlNodeString(_iconSetPath); + v = v.Substring(1); //Skip first icon. + return (T)Enum.Parse(typeof(T), v, true); } -} \ No newline at end of file + set => SetXmlNodeString(_iconSetPath, GetIconSetString(value)); + } + + private string GetIconSetString(T value) { + if (Type == eExcelConditionalFormattingRuleType.FourIconSet) { + switch (value.ToString()) { + case "Arrows": + return "4Arrows"; + case "ArrowsGray": + return "4ArrowsGray"; + case "Rating": + return "4Rating"; + case "RedToBlack": + return "4RedToBlack"; + case "TrafficLights": + return "4TrafficLights"; + default: + throw (new ArgumentException("Invalid type")); + } + } + if (Type == eExcelConditionalFormattingRuleType.FiveIconSet) { + switch (value.ToString()) { + case "Arrows": + return "5Arrows"; + case "ArrowsGray": + return "5ArrowsGray"; + case "Quarters": + return "5Quarters"; + case "Rating": + return "5Rating"; + default: + throw (new ArgumentException("Invalid type")); + } + } + switch (value.ToString()) { + case "Arrows": + return "3Arrows"; + case "ArrowsGray": + return "3ArrowsGray"; + case "Flags": + return "3Flags"; + case "Signs": + return "3Signs"; + case "Symbols": + return "3Symbols"; + case "Symbols2": + return "3Symbols2"; + case "TrafficLights1": + return "3TrafficLights1"; + case "TrafficLights2": + return "3TrafficLights2"; + default: + throw (new ArgumentException("Invalid type")); + } + } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs index ec7d836..f8ebade 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTimePeriodGroup.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,51 +13,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingTimePeriodGroup - /// </summary> - public class ExcelConditionalFormattingTimePeriodGroup - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingTimePeriodGroup( +/// <summary> +/// ExcelConditionalFormattingTimePeriodGroup +/// </summary> +public class ExcelConditionalFormattingTimePeriodGroup + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingTimePeriodGroup { + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingTimePeriodGroup( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, @@ -65,62 +57,40 @@ XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - type, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - } + type, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) {} - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingTimePeriodGroup( + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingTimePeriodGroup( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - type, - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(type, address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="type"></param> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingTimePeriodGroup( + /// <summary> + /// + /// </summary> + /// <param name="type"></param> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingTimePeriodGroup( eExcelConditionalFormattingRuleType type, ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - type, - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(type, address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs index c217665..6b99262 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingToday.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,82 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingToday +/// </summary> +public class ExcelConditionalFormattingToday : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingToday + /// /// </summary> - public class ExcelConditionalFormattingToday - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingToday( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingToday( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Today, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Today, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.Today; - Formula = string.Format( - "FLOOR({0},1)=TODAY()", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.Today; + Formula = string.Format("FLOOR({0},1)=TODAY()", Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingToday( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingToday( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingToday( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingToday( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs index cec82b0..6b5aa92 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTomorrow.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,82 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingTomorrow +/// </summary> +public class ExcelConditionalFormattingTomorrow : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingTomorrow + /// /// </summary> - public class ExcelConditionalFormattingTomorrow - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingTomorrow( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingTomorrow( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Tomorrow, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Tomorrow, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.Tomorrow; - Formula = string.Format( - "FLOOR({0},1)=TODAY()+1", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.Tomorrow; + Formula = string.Format("FLOOR({0},1)=TODAY()+1", Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingTomorrow( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingTomorrow( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingTomorrow( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingTomorrow( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs index 787f1c9..95697d0 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTop.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingTop - /// </summary> - public class ExcelConditionalFormattingTop - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingTopBottomGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingTop( +/// <summary> +/// ExcelConditionalFormattingTop +/// </summary> +public class ExcelConditionalFormattingTop + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingTopBottomGroup { + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingTop( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Top, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Top, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Bottom = false; - Percent = false; - Rank = 10; // First 10 values - } + Bottom = false; + Percent = false; + Rank = 10; // First 10 values } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingTop( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingTop( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingTop( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingTop( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs index 5c299cc..929369d 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTopPercent.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingTopPercent - /// </summary> - public class ExcelConditionalFormattingTopPercent - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingTopBottomGroup - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingTopPercent( +/// <summary> +/// ExcelConditionalFormattingTopPercent +/// </summary> +public class ExcelConditionalFormattingTopPercent + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingTopBottomGroup { + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingTopPercent( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.TopPercent, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.TopPercent, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - Bottom = false; - Percent = true; - Rank = 10; // First 10 percent - } + Bottom = false; + Percent = true; + Rank = 10; // First 10 percent } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingTopPercent( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingTopPercent( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingTopPercent( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingTopPercent( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs index ef322f0..29a5a9e 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingTwoColorScale.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,168 +13,132 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using System.Drawing; using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingTwoColorScale - /// </summary> - public class ExcelConditionalFormattingTwoColorScale +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingTwoColorScale +/// </summary> +public class ExcelConditionalFormattingTwoColorScale : ExcelConditionalFormattingRule, - IExcelConditionalFormattingTwoColorScale - { - /****************************************************************************************/ + IExcelConditionalFormattingTwoColorScale { + /// <summary> + /// Private Low Value + /// </summary> + private ExcelConditionalFormattingColorScaleValue _lowValue; - #region Private Properties - /// <summary> - /// Private Low Value - /// </summary> - private ExcelConditionalFormattingColorScaleValue _lowValue; + /// <summary> + /// Private High Value + /// </summary> + private ExcelConditionalFormattingColorScaleValue _highValue; - /// <summary> - /// Private High Value - /// </summary> - private ExcelConditionalFormattingColorScaleValue _highValue; - #endregion Private Properties - - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingTwoColorScale( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingTwoColorScale( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.TwoColorScale, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - // Create the <colorScale> node inside the <cfRule> node - var colorScaleNode = CreateComplexNode( + eExcelConditionalFormattingRuleType.TwoColorScale, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + // Create the <colorScale> node inside the <cfRule> node + var colorScaleNode = CreateComplexNode( Node, - ExcelConditionalFormattingConstants.Paths.ColorScale); + ExcelConditionalFormattingConstants.Paths._colorScale); - // LowValue default - LowValue = new ExcelConditionalFormattingColorScaleValue( + // LowValue default + LowValue = new( eExcelConditionalFormattingValueObjectPosition.Low, eExcelConditionalFormattingValueObjectType.Min, - ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors.CfvoLowValue), + ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoLowValue), eExcelConditionalFormattingRuleType.TwoColorScale, address, priority, worksheet, NameSpaceManager); - // HighValue default - HighValue = new ExcelConditionalFormattingColorScaleValue( + // HighValue default + HighValue = new( eExcelConditionalFormattingValueObjectPosition.High, eExcelConditionalFormattingValueObjectType.Max, - ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors.CfvoHighValue), + ColorTranslator.FromHtml(ExcelConditionalFormattingConstants.Colors._cfvoHighValue), eExcelConditionalFormattingRuleType.TwoColorScale, address, priority, worksheet, NameSpaceManager); - } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingTwoColorScale( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingTwoColorScale( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingTwoColorScale( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingTwoColorScale( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors + : this(address, priority, worksheet, null, null) {} - /****************************************************************************************/ - - #region Public Properties - /// <summary> - /// Low Value for Two Color Scale Object Value - /// </summary> - public ExcelConditionalFormattingColorScaleValue LowValue - { - get { return _lowValue; } - set { _lowValue = value; } - } - - /// <summary> - /// High Value for Two Color Scale Object Value - /// </summary> - public ExcelConditionalFormattingColorScaleValue HighValue - { - get { return _highValue; } - set { _highValue = value; } - } - #endregion Public Properties - - /****************************************************************************************/ + /// <summary> + /// Low Value for Two Color Scale Object Value + /// </summary> + public ExcelConditionalFormattingColorScaleValue LowValue { + get => _lowValue; + set => _lowValue = value; } -} \ No newline at end of file + + /// <summary> + /// High Value for Two Color Scale Object Value + /// </summary> + public ExcelConditionalFormattingColorScaleValue HighValue { + get => _highValue; + set => _highValue = value; + } +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs index fd32210..ef4d72e 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingUniqueValues.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,106 +13,78 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ - /// <summary> - /// ExcelConditionalFormattingUniqueValues - /// </summary> - public class ExcelConditionalFormattingUniqueValues - : ExcelConditionalFormattingRule, - IExcelConditionalFormattingUniqueValues - { - /****************************************************************************************/ +namespace OfficeOpenXml.ConditionalFormatting; - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="address"></param> - /// <param name="priority"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingUniqueValues( +/// <summary> +/// ExcelConditionalFormattingUniqueValues +/// </summary> +public class ExcelConditionalFormattingUniqueValues + : ExcelConditionalFormattingRule, + IExcelConditionalFormattingUniqueValues { + /// <summary> + /// + /// </summary> + /// <param name="address"></param> + /// <param name="priority"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingUniqueValues( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.UniqueValues, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) - { - } + eExcelConditionalFormattingRuleType.UniqueValues, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingUniqueValues( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingUniqueValues( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingUniqueValues( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingUniqueValues( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs index 87fe86f..158948c 100644 --- a/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs +++ b/EPPlus/ConditionalFormatting/Rules/ExcelConditionalFormattingYesterday.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,112 +13,82 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Eyal Seagull Added 2012-04-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; + using System.Xml; -using OfficeOpenXml.ConditionalFormatting.Contracts; -namespace OfficeOpenXml.ConditionalFormatting -{ +namespace OfficeOpenXml.ConditionalFormatting; + +/// <summary> +/// ExcelConditionalFormattingYesterday +/// </summary> +public class ExcelConditionalFormattingYesterday : ExcelConditionalFormattingTimePeriodGroup { /// <summary> - /// ExcelConditionalFormattingYesterday + /// /// </summary> - public class ExcelConditionalFormattingYesterday - : ExcelConditionalFormattingTimePeriodGroup - { - /****************************************************************************************/ - - #region Constructors - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelConditionalFormattingYesterday( + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelConditionalFormattingYesterday( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) : base( - eExcelConditionalFormattingRuleType.Yesterday, - address, - priority, - worksheet, - itemElementNode, - (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) + eExcelConditionalFormattingRuleType.Yesterday, + address, + priority, + worksheet, + itemElementNode, + (namespaceManager == null) ? worksheet.NameSpaceManager : namespaceManager) { + if (itemElementNode + == null) //Set default values and create attributes if needed { - if (itemElementNode==null) //Set default values and create attributes if needed - { - TimePeriod = eExcelConditionalFormattingTimePeriodType.Yesterday; - Formula = string.Format( - "FLOOR({0},1)=TODAY()-1", - Address.Start.Address); - } + TimePeriod = eExcelConditionalFormattingTimePeriodType.Yesterday; + Formula = string.Format("FLOOR({0},1)=TODAY()-1", Address.Start.Address); } + } - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - /// <param name="itemElementNode"></param> - internal ExcelConditionalFormattingYesterday( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + /// <param name="itemElementNode"></param> + internal ExcelConditionalFormattingYesterday( ExcelAddress address, int priority, ExcelWorksheet worksheet, XmlNode itemElementNode) - : this( - address, - priority, - worksheet, - itemElementNode, - null) - { - } + : this(address, priority, worksheet, itemElementNode, null) {} - /// <summary> - /// - /// </summary> - /// <param name="priority"></param> - /// <param name="address"></param> - /// <param name="worksheet"></param> - internal ExcelConditionalFormattingYesterday( + /// <summary> + /// + /// </summary> + /// <param name="priority"></param> + /// <param name="address"></param> + /// <param name="worksheet"></param> + internal ExcelConditionalFormattingYesterday( ExcelAddress address, int priority, ExcelWorksheet worksheet) - : this( - address, - priority, - worksheet, - null, - null) - { - } - #endregion Constructors - - /****************************************************************************************/ - } -} \ No newline at end of file + : this(address, priority, worksheet, null, null) {} +}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs index ecc2208..44b5d3e 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidation.cs
@@ -13,83 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Interface for data validation - /// </summary> - public interface IExcelDataValidation - { - /// <summary> - /// Address of data validation - /// </summary> - ExcelAddress Address { get; } - /// <summary> - /// Validation type - /// </summary> - ExcelDataValidationType ValidationType { get; } - /// <summary> - /// Controls how Excel will handle invalid values. - /// </summary> - ExcelDataValidationWarningStyle ErrorStyle{ get; set; } - /// <summary> - /// True if input message should be shown - /// </summary> - bool? AllowBlank { get; set; } - /// <summary> - /// True if input message should be shown - /// </summary> - bool? ShowInputMessage { get; set; } - /// <summary> - /// True if error message should be shown. - /// </summary> - bool? ShowErrorMessage { get; set; } - /// <summary> - /// Title of error message box (see property ShowErrorMessage) - /// </summary> - string ErrorTitle { get; set; } - /// <summary> - /// Error message box text (see property ShowErrorMessage) - /// </summary> - string Error { get; set; } - /// <summary> - /// Title of info box if input message should be shown (see property ShowInputMessage) - /// </summary> - string PromptTitle { get; set; } - /// <summary> - /// Info message text (see property ShowErrorMessage) - /// </summary> - string Prompt { get; set; } - /// <summary> - /// True if the current validation type allows operator. - /// </summary> - bool AllowsOperator { get; } - /// <summary> - /// Validates the state of the validation. - /// </summary> - void Validate(); +namespace OfficeOpenXml.DataValidation.Contracts; +/// <summary> +/// Interface for data validation +/// </summary> +public interface IExcelDataValidation { + /// <summary> + /// Address of data validation + /// </summary> + ExcelAddress Address { get; } - } + /// <summary> + /// Validation type + /// </summary> + ExcelDataValidationType ValidationType { get; } + + /// <summary> + /// Controls how Excel will handle invalid values. + /// </summary> + ExcelDataValidationWarningStyle ErrorStyle { get; set; } + + /// <summary> + /// True if input message should be shown + /// </summary> + bool? AllowBlank { get; set; } + + /// <summary> + /// True if input message should be shown + /// </summary> + bool? ShowInputMessage { get; set; } + + /// <summary> + /// True if error message should be shown. + /// </summary> + bool? ShowErrorMessage { get; set; } + + /// <summary> + /// Title of error message box (see property ShowErrorMessage) + /// </summary> + string ErrorTitle { get; set; } + + /// <summary> + /// Error message box text (see property ShowErrorMessage) + /// </summary> + string Error { get; set; } + + /// <summary> + /// Title of info box if input message should be shown (see property ShowInputMessage) + /// </summary> + string PromptTitle { get; set; } + + /// <summary> + /// Info message text (see property ShowErrorMessage) + /// </summary> + string Prompt { get; set; } + + /// <summary> + /// True if the current validation type allows operator. + /// </summary> + bool AllowsOperator { get; } + + /// <summary> + /// Validates the state of the validation. + /// </summary> + void Validate(); }
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationAny.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationAny.cs index 350ddaf..c3b6bfd 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationAny.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationAny.cs
@@ -13,33 +13,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Raziq York Added 2014-08-08 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Data validation interface for Any value validation. - /// </summary> - public interface IExcelDataValidationAny : IExcelDataValidation - { - } -} +namespace OfficeOpenXml.DataValidation.Contracts; + +/// <summary> +/// Data validation interface for Any value validation. +/// </summary> +public interface IExcelDataValidationAny : IExcelDataValidation {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationCustom.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationCustom.cs index 1cfdba9..f567ce4 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationCustom.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationCustom.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,34 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Data validation interface for custom validation. - /// </summary> - public interface IExcelDataValidationCustom : IExcelDataValidationWithFormula<IExcelDataValidationFormula>, IExcelDataValidationWithOperator - { - } -} +namespace OfficeOpenXml.DataValidation.Contracts; + +/// <summary> +/// Data validation interface for custom validation. +/// </summary> +public interface IExcelDataValidationCustom + : IExcelDataValidationWithFormula<IExcelDataValidationFormula>, + IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationDateTime.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationDateTime.cs index 3e96b03..6ab40d0 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationDateTime.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationDateTime.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,34 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Validation interface for datetime validations - /// </summary> - public interface IExcelDataValidationDateTime : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>, IExcelDataValidationWithOperator - { - } -} +namespace OfficeOpenXml.DataValidation.Contracts; + +/// <summary> +/// Validation interface for datetime validations +/// </summary> +public interface IExcelDataValidationDateTime + : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>, + IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationDecimal.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationDecimal.cs index 8b4f356..48983ed 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationDecimal.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationDecimal.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,34 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Data validation interface for decimal values - /// </summary> - public interface IExcelDataValidationDecimal : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>, IExcelDataValidationWithOperator - { - } -} +namespace OfficeOpenXml.DataValidation.Contracts; + +/// <summary> +/// Data validation interface for decimal values +/// </summary> +public interface IExcelDataValidationDecimal + : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>, + IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationInt.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationInt.cs index a54863d..9d984e2 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationInt.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationInt.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,31 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - public interface IExcelDataValidationInt : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>, IExcelDataValidationWithOperator - { - } -} +namespace OfficeOpenXml.DataValidation.Contracts; + +public interface IExcelDataValidationInt + : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>, + IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationList.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationList.cs index d0ae4f2..13bb5a9 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationList.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationList.cs
@@ -13,31 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - public interface IExcelDataValidationList : IExcelDataValidationWithFormula<IExcelDataValidationFormulaList> - { - } -} +namespace OfficeOpenXml.DataValidation.Contracts; + +public interface IExcelDataValidationList + : IExcelDataValidationWithFormula<IExcelDataValidationFormulaList> {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationTime.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationTime.cs index ea26dd5..4c57587 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationTime.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationTime.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,34 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Data validation interface for time validation. - /// </summary> - public interface IExcelDataValidationTime : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>, IExcelDataValidationWithOperator - { - } -} +namespace OfficeOpenXml.DataValidation.Contracts; + +/// <summary> +/// Data validation interface for time validation. +/// </summary> +public interface IExcelDataValidationTime + : IExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>, + IExcelDataValidationWithOperator {}
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs index 251f079..b93dd30 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula.cs
@@ -13,33 +13,28 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - public interface IExcelDataValidationWithFormula<T> : IExcelDataValidation - where T : IExcelDataValidationFormula - { - T Formula { get; } - } +namespace OfficeOpenXml.DataValidation.Contracts; + +public interface IExcelDataValidationWithFormula<T> : IExcelDataValidation + where T : IExcelDataValidationFormula { + T Formula { get; } }
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs index 41da1ef..2f6692b 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithFormula2.cs
@@ -13,40 +13,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Interface for a data validation with two formulas - /// </summary> - /// <typeparam name="T"></typeparam> - public interface IExcelDataValidationWithFormula2<T> : IExcelDataValidationWithFormula<T> - where T : IExcelDataValidationFormula - { - /// <summary> - /// Formula 2 - /// </summary> - T Formula2 { get; } - } +namespace OfficeOpenXml.DataValidation.Contracts; + +/// <summary> +/// Interface for a data validation with two formulas +/// </summary> +/// <typeparam name="T"></typeparam> +public interface IExcelDataValidationWithFormula2<T> : IExcelDataValidationWithFormula<T> + where T : IExcelDataValidationFormula { + /// <summary> + /// Formula 2 + /// </summary> + T Formula2 { get; } }
diff --git a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs index a24bd4f..48b06cb 100644 --- a/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs +++ b/EPPlus/DataValidation/Contracts/IExcelDataValidationWithOperator.cs
@@ -13,37 +13,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Contracts -{ - /// <summary> - /// Represents a validation with an operator - /// </summary> - public interface IExcelDataValidationWithOperator - { - /// <summary> - /// Operator type - /// </summary> - ExcelDataValidationOperator Operator { get; set; } - } +namespace OfficeOpenXml.DataValidation.Contracts; + +/// <summary> +/// Represents a validation with an operator +/// </summary> +public interface IExcelDataValidationWithOperator { + /// <summary> + /// Operator type + /// </summary> + ExcelDataValidationOperator Operator { get; set; } }
diff --git a/EPPlus/DataValidation/ExcelDataValidation.cs b/EPPlus/DataValidation/ExcelDataValidation.cs index cd2fdda..0f74ed9 100644 --- a/EPPlus/DataValidation/ExcelDataValidation.cs +++ b/EPPlus/DataValidation/ExcelDataValidation.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,387 +13,293 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -using OfficeOpenXml.Utils; -using System.Xml; using System.Text.RegularExpressions; -using OfficeOpenXml.DataValidation.Formulas.Contracts; +using System.Xml; using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Excel datavalidation - /// </summary> - public abstract class ExcelDataValidation : XmlHelper, IExcelDataValidation - { - private const string _itemElementNodeName = "d:dataValidation"; +namespace OfficeOpenXml.DataValidation; +/// <summary> +/// Excel datavalidation +/// </summary> +public abstract class ExcelDataValidation : XmlHelper, IExcelDataValidation { + private const string _itemElementNodeName = "d:dataValidation"; - private readonly string _errorStylePath = "@errorStyle"; - private readonly string _errorTitlePath = "@errorTitle"; - private readonly string _errorPath = "@error"; - private readonly string _promptTitlePath = "@promptTitle"; - private readonly string _promptPath = "@prompt"; - private readonly string _operatorPath = "@operator"; - private readonly string _showErrorMessagePath = "@showErrorMessage"; - private readonly string _showInputMessagePath = "@showInputMessage"; - private readonly string _typeMessagePath = "@type"; - private readonly string _sqrefPath = "@sqref"; - private readonly string _allowBlankPath = "@allowBlank"; - protected readonly string _formula1Path = "d:formula1"; - protected readonly string _formula2Path = "d:formula2"; + private readonly string _errorStylePath = "@errorStyle"; + private readonly string _errorTitlePath = "@errorTitle"; + private readonly string _errorPath = "@error"; + private readonly string _promptTitlePath = "@promptTitle"; + private readonly string _promptPath = "@prompt"; + private readonly string _operatorPath = "@operator"; + private readonly string _showErrorMessagePath = "@showErrorMessage"; + private readonly string _showInputMessagePath = "@showInputMessage"; + private readonly string _typeMessagePath = "@type"; + private readonly string _sqrefPath = "@sqref"; + private readonly string _allowBlankPath = "@allowBlank"; + protected readonly string _formula1Path = "d:formula1"; + protected readonly string _formula2Path = "d:formula2"; - internal ExcelDataValidation(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : this(worksheet, address, validationType, null) - { } + internal ExcelDataValidation( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : this(worksheet, address, validationType, null) {} - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet">worksheet that owns the validation</param> - /// <param name="itemElementNode">Xml top node (dataValidations)</param> - /// <param name="validationType">Data validation type</param> - /// <param name="address">address for data validation</param> - internal ExcelDataValidation(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : this(worksheet, address, validationType, itemElementNode, null) - { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet">worksheet that owns the validation</param> + /// <param name="itemElementNode">Xml top node (dataValidations)</param> + /// <param name="validationType">Data validation type</param> + /// <param name="address">address for data validation</param> + internal ExcelDataValidation( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : this(worksheet, address, validationType, itemElementNode, null) {} - } - - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet">worksheet that owns the validation</param> - /// <param name="itemElementNode">Xml top node (dataValidations) when importing xml</param> - /// <param name="validationType">Data validation type</param> - /// <param name="address">address for data validation</param> - /// <param name="namespaceManager">Xml Namespace manager</param> - internal ExcelDataValidation(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(namespaceManager != null ? namespaceManager : worksheet.NameSpaceManager) - { - Require.Argument(address).IsNotNullOrEmpty("address"); - address = CheckAndFixRangeAddress(address); - if (itemElementNode == null) - { - //var xmlDoc = worksheet.WorksheetXml; - TopNode = worksheet.WorksheetXml.SelectSingleNode("//d:dataValidations", worksheet.NameSpaceManager); - // did not succeed using the XmlHelper methods here... so I'm creating the new node using XmlDocument... - var nsUri = NameSpaceManager.LookupNamespace("d"); - //itemElementNode = TopNode.OwnerDocument.CreateElement(_itemElementNodeName, nsUri); - itemElementNode = TopNode.OwnerDocument.CreateElement(_itemElementNodeName.Split(':')[1], nsUri); - TopNode.AppendChild(itemElementNode); - } - TopNode = itemElementNode; - ValidationType = validationType; - Address = new ExcelAddress(address); - Init(); - } - - private void Init() - { - // set schema node order - SchemaNodeOrder = new string[]{ - "type", - "errorStyle", - "operator", - "allowBlank", - "showInputMessage", - "showErrorMessage", - "errorTitle", - "error", - "promptTitle", - "prompt", - "sqref", - "formula1", - "formula2" - }; - } - - private string CheckAndFixRangeAddress(string address) - { - if (address.Contains(',')) - { - throw new FormatException("Multiple addresses may not be commaseparated, use space instead"); - } - address = address.ToUpper(CultureInfo.InvariantCulture); - if (Regex.IsMatch(address, @"[A-Z]+:[A-Z]+")) - { - address = AddressUtility.ParseEntireColumnSelections(address); - } - return address; - } - - private void SetNullableBoolValue(string path, bool? val) - { - if (val.HasValue) - { - SetXmlNodeBool(path, val.Value); - } - else - { - DeleteNode(path); - } - } - - /// <summary> - /// This method will validate the state of the validation - /// </summary> - /// <exception cref="InvalidOperationException">If the state breaks the rules of the validation</exception> - public virtual void Validate() - { - var address = Address.Address; - // validate Formula1 - if (string.IsNullOrEmpty(Formula1Internal)) - { - throw new InvalidOperationException("Validation of " + address + " failed: Formula1 cannot be empty"); - } - } - - #region Public properties - - /// <summary> - /// True if the validation type allows operator to be set. - /// </summary> - public bool AllowsOperator - { - get - { - return ValidationType.AllowOperator; - } - } - - /// <summary> - /// Address of data validation - /// </summary> - public ExcelAddress Address - { - get - { - return new ExcelAddress(GetXmlNodeString(_sqrefPath)); - } - private set - { - var address = AddressUtility.ParseEntireColumnSelections(value.Address); - SetXmlNodeString(_sqrefPath, address); - } - } - /// <summary> - /// Validation type - /// </summary> - public ExcelDataValidationType ValidationType - { - get - { - var typeString = GetXmlNodeString(_typeMessagePath); - return ExcelDataValidationType.GetBySchemaName(typeString); - } - private set - { - SetXmlNodeString(_typeMessagePath, value.SchemaName, true); - } - } - - /// <summary> - /// Operator for comparison between the entered value and Formula/Formulas. - /// </summary> - public ExcelDataValidationOperator Operator - { - get - { - var operatorString = GetXmlNodeString(_operatorPath); - if (!string.IsNullOrEmpty(operatorString)) - { - return (ExcelDataValidationOperator)Enum.Parse(typeof(ExcelDataValidationOperator), operatorString); - } - return default(ExcelDataValidationOperator); - } - set - { - if (!ValidationType.AllowOperator) - { - throw new InvalidOperationException("The current validation type does not allow operator to be set"); - } - SetXmlNodeString(_operatorPath, value.ToString()); - } - } - - /// <summary> - /// Warning style - /// </summary> - public ExcelDataValidationWarningStyle ErrorStyle - { - get - { - var errorStyleString = GetXmlNodeString(_errorStylePath); - if (!string.IsNullOrEmpty(errorStyleString)) - { - return (ExcelDataValidationWarningStyle)Enum.Parse(typeof(ExcelDataValidationWarningStyle), errorStyleString); - } - return ExcelDataValidationWarningStyle.undefined; - } - set - { - if (value == ExcelDataValidationWarningStyle.undefined) - { - DeleteNode(_errorStylePath); - } - SetXmlNodeString(_errorStylePath, value.ToString()); - } - } - - /// <summary> - /// True if blanks should be allowed - /// </summary> - public bool? AllowBlank - { - get - { - return GetXmlNodeBoolNullable(_allowBlankPath); - } - set - { - SetNullableBoolValue(_allowBlankPath, value); - } - } - - /// <summary> - /// True if input message should be shown - /// </summary> - public bool? ShowInputMessage - { - get - { - return GetXmlNodeBoolNullable(_showInputMessagePath); - } - set - { - SetNullableBoolValue(_showInputMessagePath, value); - } - } - - /// <summary> - /// True if error message should be shown - /// </summary> - public bool? ShowErrorMessage - { - get - { - return GetXmlNodeBoolNullable(_showErrorMessagePath); - } - set - { - SetNullableBoolValue(_showErrorMessagePath, value); - } - } - - /// <summary> - /// Title of error message box - /// </summary> - public string ErrorTitle - { - get - { - return GetXmlNodeString(_errorTitlePath); - } - set - { - SetXmlNodeString(_errorTitlePath, value); - } - } - - /// <summary> - /// Error message box text - /// </summary> - public string Error - { - get - { - return GetXmlNodeString(_errorPath); - } - set - { - SetXmlNodeString(_errorPath, value); - } - } - - public string PromptTitle - { - get - { - return GetXmlNodeString(_promptTitlePath); - } - set - { - SetXmlNodeString(_promptTitlePath, value); - } - } - - public string Prompt - { - get - { - return GetXmlNodeString(_promptPath); - } - set - { - SetXmlNodeString(_promptPath, value); - } - } - - /// <summary> - /// Formula 1 - /// </summary> - protected string Formula1Internal - { - get - { - return GetXmlNodeString(_formula1Path); - } - } - - /// <summary> - /// Formula 2 - /// </summary> - protected string Formula2Internal - { - get - { - return GetXmlNodeString(_formula2Path); - } - } - - #endregion - - protected void SetValue<T>(Nullable<T> val, string path) - where T : struct - { - if (!val.HasValue) - { - DeleteNode(path); - } - var stringValue = val.Value.ToString().Replace(',', '.'); - SetXmlNodeString(path, stringValue); - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet">worksheet that owns the validation</param> + /// <param name="itemElementNode">Xml top node (dataValidations) when importing xml</param> + /// <param name="validationType">Data validation type</param> + /// <param name="address">address for data validation</param> + /// <param name="namespaceManager">Xml Namespace manager</param> + internal ExcelDataValidation( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(namespaceManager != null ? namespaceManager : worksheet.NameSpaceManager) { + Require.Argument(address).IsNotNullOrEmpty("address"); + address = CheckAndFixRangeAddress(address); + if (itemElementNode == null) { + //var xmlDoc = worksheet.WorksheetXml; + TopNode = worksheet.WorksheetXml.SelectSingleNode( + "//d:dataValidations", + worksheet.NameSpaceManager); + // did not succeed using the XmlHelper methods here... so I'm creating the new node using XmlDocument... + var nsUri = NameSpaceManager.LookupNamespace("d"); + //itemElementNode = TopNode.OwnerDocument.CreateElement(_itemElementNodeName, nsUri); + itemElementNode = TopNode.OwnerDocument.CreateElement( + _itemElementNodeName.Split(':')[1], + nsUri); + TopNode.AppendChild(itemElementNode); } + TopNode = itemElementNode; + ValidationType = validationType; + Address = new(address); + Init(); + } + + private void Init() { + // set schema node order + SchemaNodeOrder = new[] { + "type", + "errorStyle", + "operator", + "allowBlank", + "showInputMessage", + "showErrorMessage", + "errorTitle", + "error", + "promptTitle", + "prompt", + "sqref", + "formula1", + "formula2", + }; + } + + private string CheckAndFixRangeAddress(string address) { + if (address.Contains(',')) { + throw new FormatException("Multiple addresses may not be commaseparated, use space instead"); + } + address = address.ToUpper(CultureInfo.InvariantCulture); + if (Regex.IsMatch(address, "[A-Z]+:[A-Z]+")) { + address = AddressUtility.ParseEntireColumnSelections(address); + } + return address; + } + + private void SetNullableBoolValue(string path, bool? val) { + if (val.HasValue) { + SetXmlNodeBool(path, val.Value); + } else { + DeleteNode(path); + } + } + + /// <summary> + /// This method will validate the state of the validation + /// </summary> + /// <exception cref="InvalidOperationException">If the state breaks the rules of the validation</exception> + public virtual void Validate() { + var address = Address.Address; + // validate Formula1 + if (string.IsNullOrEmpty(Formula1Internal)) { + throw new InvalidOperationException( + "Validation of " + address + " failed: Formula1 cannot be empty"); + } + } + + /// <summary> + /// True if the validation type allows operator to be set. + /// </summary> + public bool AllowsOperator => ValidationType.AllowOperator; + + /// <summary> + /// Address of data validation + /// </summary> + public ExcelAddress Address { + get => new(GetXmlNodeString(_sqrefPath)); + private set { + var address = AddressUtility.ParseEntireColumnSelections(value.Address); + SetXmlNodeString(_sqrefPath, address); + } + } + + /// <summary> + /// Validation type + /// </summary> + public ExcelDataValidationType ValidationType { + get { + var typeString = GetXmlNodeString(_typeMessagePath); + return ExcelDataValidationType.GetBySchemaName(typeString); + } + private set => SetXmlNodeString(_typeMessagePath, value.SchemaName, true); + } + + /// <summary> + /// Operator for comparison between the entered value and Formula/Formulas. + /// </summary> + public ExcelDataValidationOperator Operator { + get { + var operatorString = GetXmlNodeString(_operatorPath); + if (!string.IsNullOrEmpty(operatorString)) { + return (ExcelDataValidationOperator) + Enum.Parse(typeof(ExcelDataValidationOperator), operatorString); + } + return default(ExcelDataValidationOperator); + } + set { + if (!ValidationType.AllowOperator) { + throw new InvalidOperationException( + "The current validation type does not allow operator to be set"); + } + SetXmlNodeString(_operatorPath, value.ToString()); + } + } + + /// <summary> + /// Warning style + /// </summary> + public ExcelDataValidationWarningStyle ErrorStyle { + get { + var errorStyleString = GetXmlNodeString(_errorStylePath); + if (!string.IsNullOrEmpty(errorStyleString)) { + return (ExcelDataValidationWarningStyle) + Enum.Parse(typeof(ExcelDataValidationWarningStyle), errorStyleString); + } + return ExcelDataValidationWarningStyle.Undefined; + } + set { + if (value == ExcelDataValidationWarningStyle.Undefined) { + DeleteNode(_errorStylePath); + } + SetXmlNodeString(_errorStylePath, value.ToString()); + } + } + + /// <summary> + /// True if blanks should be allowed + /// </summary> + public bool? AllowBlank { + get => GetXmlNodeBoolNullable(_allowBlankPath); + set => SetNullableBoolValue(_allowBlankPath, value); + } + + /// <summary> + /// True if input message should be shown + /// </summary> + public bool? ShowInputMessage { + get => GetXmlNodeBoolNullable(_showInputMessagePath); + set => SetNullableBoolValue(_showInputMessagePath, value); + } + + /// <summary> + /// True if error message should be shown + /// </summary> + public bool? ShowErrorMessage { + get => GetXmlNodeBoolNullable(_showErrorMessagePath); + set => SetNullableBoolValue(_showErrorMessagePath, value); + } + + /// <summary> + /// Title of error message box + /// </summary> + public string ErrorTitle { + get => GetXmlNodeString(_errorTitlePath); + set => SetXmlNodeString(_errorTitlePath, value); + } + + /// <summary> + /// Error message box text + /// </summary> + public string Error { + get => GetXmlNodeString(_errorPath); + set => SetXmlNodeString(_errorPath, value); + } + + public string PromptTitle { + get => GetXmlNodeString(_promptTitlePath); + set => SetXmlNodeString(_promptTitlePath, value); + } + + public string Prompt { + get => GetXmlNodeString(_promptPath); + set => SetXmlNodeString(_promptPath, value); + } + + /// <summary> + /// Formula 1 + /// </summary> + protected string Formula1Internal => GetXmlNodeString(_formula1Path); + + /// <summary> + /// Formula 2 + /// </summary> + protected string Formula2Internal => GetXmlNodeString(_formula2Path); + + protected void SetValue<T>(T? val, string path) + where T : struct { + if (!val.HasValue) { + DeleteNode(path); + } + var stringValue = val.Value.ToString().Replace(',', '.'); + SetXmlNodeString(path, stringValue); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationAny.cs b/EPPlus/DataValidation/ExcelDataValidationAny.cs index e8fae1e..8d00268 100644 --- a/EPPlus/DataValidation/ExcelDataValidationAny.cs +++ b/EPPlus/DataValidation/ExcelDataValidationAny.cs
@@ -13,78 +13,75 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Raziq York Added 2014-08-08 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -using OfficeOpenXml.DataValidation.Formulas; + using System.Xml; using OfficeOpenXml.DataValidation.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Any value validation. - /// </summary> - public class ExcelDataValidationAny : ExcelDataValidation, IExcelDataValidationAny - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationAny(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : base(worksheet, address, validationType) - { - } +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - internal ExcelDataValidationAny(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - } +/// <summary> +/// Any value validation. +/// </summary> +public class ExcelDataValidationAny : ExcelDataValidation, IExcelDataValidationAny { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationAny( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : base(worksheet, address, validationType) {} - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelDataValidationAny(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + internal ExcelDataValidationAny( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) {} - /// <summary> - /// This method will validate the state of the validation - /// </summary> - public override void Validate() - { - } - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelDataValidationAny( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) {} + + /// <summary> + /// This method will validate the state of the validation + /// </summary> + public override void Validate() {} }
diff --git a/EPPlus/DataValidation/ExcelDataValidationCollection.cs b/EPPlus/DataValidation/ExcelDataValidationCollection.cs index d13791b..6692f9d 100644 --- a/EPPlus/DataValidation/ExcelDataValidationCollection.cs +++ b/EPPlus/DataValidation/ExcelDataValidationCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 @@ -32,377 +32,358 @@ * Jan Källman License changed GPL-->LGPL 2011-12-27 * Raziq York Added support for Any type 2014-08-08 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Collections; -using OfficeOpenXml.Utils; +using System.Collections.Generic; using System.Xml; using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// <para> - /// Collection of <see cref="ExcelDataValidation"/>. This class is providing the API for EPPlus data validation. - /// </para> - /// <para> - /// The public methods of this class (Add[...]Validation) will create a datavalidation entry in the worksheet. When this - /// validation has been created changes to the properties will affect the workbook immediately. - /// </para> - /// <para> - /// Each type of validation has either a formula or a typed value/values, except for custom validation which has a formula only. - /// </para> - /// <code> - /// // Add a date time validation - /// var validation = worksheet.DataValidation.AddDateTimeValidation("A1"); - /// // set validation properties - /// validation.ShowErrorMessage = true; - /// validation.ErrorTitle = "An invalid date was entered"; - /// validation.Error = "The date must be between 2011-01-31 and 2011-12-31"; - /// validation.Prompt = "Enter date here"; - /// validation.Formula.Value = DateTime.Parse("2011-01-01"); - /// validation.Formula2.Value = DateTime.Parse("2011-12-31"); - /// validation.Operator = ExcelDataValidationOperator.between; - /// </code> - /// </summary> - public class ExcelDataValidationCollection : XmlHelper, IEnumerable<IExcelDataValidation> - { - private List<IExcelDataValidation> _validations = new List<IExcelDataValidation>(); - private ExcelWorksheet _worksheet = null; +namespace OfficeOpenXml.DataValidation; - private const string DataValidationPath = "//d:dataValidations"; - private readonly string DataValidationItemsPath = string.Format("{0}/d:dataValidation", DataValidationPath); +/// <summary> +/// <para> +/// Collection of <see cref="ExcelDataValidation"/>. This class is providing the API for EPPlus data validation. +/// </para> +/// <para> +/// The public methods of this class (Add[...]Validation) will create a datavalidation entry in the worksheet. When this +/// validation has been created changes to the properties will affect the workbook immediately. +/// </para> +/// <para> +/// Each type of validation has either a formula or a typed value/values, except for custom validation which has a formula only. +/// </para> +/// <code> +/// // Add a date time validation +/// var validation = worksheet.DataValidation.AddDateTimeValidation("A1"); +/// // set validation properties +/// validation.ShowErrorMessage = true; +/// validation.ErrorTitle = "An invalid date was entered"; +/// validation.Error = "The date must be between 2011-01-31 and 2011-12-31"; +/// validation.Prompt = "Enter date here"; +/// validation.Formula.Value = DateTime.Parse("2011-01-01"); +/// validation.Formula2.Value = DateTime.Parse("2011-12-31"); +/// validation.Operator = ExcelDataValidationOperator.between; +/// </code> +/// </summary> +public class ExcelDataValidationCollection : XmlHelper, IEnumerable<IExcelDataValidation> { + private List<IExcelDataValidation> _validations = new(); + private ExcelWorksheet _worksheet; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - internal ExcelDataValidationCollection(ExcelWorksheet worksheet) - : base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) - { - Require.Argument(worksheet).IsNotNull("worksheet"); - _worksheet = worksheet; - SchemaNodeOrder = worksheet.SchemaNodeOrder; + private const string _dataValidationPath = "//d:dataValidations"; + private readonly string DataValidationItemsPath = string.Format( + "{0}/d:dataValidation", + _dataValidationPath); - // check existing nodes and load them - var dataValidationNodes = worksheet.WorksheetXml.SelectNodes(DataValidationItemsPath, worksheet.NameSpaceManager); - if (dataValidationNodes != null && dataValidationNodes.Count > 0) - { - foreach (XmlNode node in dataValidationNodes) - { - if (node.Attributes["sqref"] == null) continue; + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + internal ExcelDataValidationCollection(ExcelWorksheet worksheet) + : base(worksheet.NameSpaceManager, worksheet.WorksheetXml.DocumentElement) { + Require.Argument(worksheet).IsNotNull("worksheet"); + _worksheet = worksheet; + SchemaNodeOrder = worksheet.SchemaNodeOrder; - var addr = node.Attributes["sqref"].Value; - - var typeSchema = node.Attributes["type"] != null ? node.Attributes["type"].Value : ""; - - var type = ExcelDataValidationType.GetBySchemaName(typeSchema); - _validations.Add(ExcelDataValidationFactory.Create(type, worksheet, addr, node)); - } - } - if (_validations.Count > 0) - { - OnValidationCountChanged(); - } + // check existing nodes and load them + var dataValidationNodes = worksheet.WorksheetXml.SelectNodes( + DataValidationItemsPath, + worksheet.NameSpaceManager); + if (dataValidationNodes != null && dataValidationNodes.Count > 0) { + foreach (XmlNode node in dataValidationNodes) { + if (node.Attributes["sqref"] == null) { + continue; } - private void EnsureRootElementExists() - { - var node = _worksheet.WorksheetXml.SelectSingleNode(DataValidationPath, _worksheet.NameSpaceManager); - if (node == null) - { - CreateNode(DataValidationPath.TrimStart('/')); - } - } + var addr = node.Attributes["sqref"].Value; - private void OnValidationCountChanged() - { - //if (TopNode != null) - //{ - // SetXmlNodeString("@count", _validations.Count.ToString()); - //} - } + var typeSchema = node.Attributes["type"] != null ? node.Attributes["type"].Value : ""; - private XmlNode GetRootNode() - { - EnsureRootElementExists(); - TopNode = _worksheet.WorksheetXml.SelectSingleNode(DataValidationPath, _worksheet.NameSpaceManager); - return TopNode; - } - - /// <summary> - /// Validates address - not empty, collisions - /// </summary> - /// <param name="address"></param> - /// <param name="validatingValidation"></param> - private void ValidateAddress(string address, IExcelDataValidation validatingValidation) - { - Require.Argument(address).IsNotNullOrEmpty("address"); - - // ensure that the new address does not collide with an existing validation. - var newAddress = new ExcelAddress(address); - if (_validations.Count > 0) - { - foreach (var validation in _validations) - { - if (validatingValidation != null && validatingValidation == validation) - { - continue; - } - var result = validation.Address.Collide(newAddress); - if (result != ExcelAddressBase.eAddressCollition.No) - { - throw new InvalidOperationException(string.Format("The address ({0}) collides with an existing validation ({1})", address, validation.Address.Address)); - } - } - } - } - - private void ValidateAddress(string address) - { - ValidateAddress(address, null); - } - - /// <summary> - /// Validates all data validations. - /// </summary> - internal void ValidateAll() - { - foreach (var validation in _validations) - { - validation.Validate(); - - ValidateAddress(validation.Address.Address, validation); - } - } - - /// <summary> - /// Adds a <see cref="ExcelDataValidationAny"/> to the worksheet. - /// </summary> - /// <param name="address">The range/address to validate</param> - /// <returns></returns> - public IExcelDataValidationAny AddAnyValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationAny(_worksheet, address, ExcelDataValidationType.Any); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - - /// <summary> - /// Adds an <see cref="IExcelDataValidationInt"/> to the worksheet. Whole means that the only accepted values - /// are integer values. - /// </summary> - /// <param name="address">the range/address to validate</param> - public IExcelDataValidationInt AddIntegerValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.Whole); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - - /// <summary> - /// Addes an <see cref="IExcelDataValidationDecimal"/> to the worksheet. The only accepted values are - /// decimal values. - /// </summary> - /// <param name="address">The range/address to validate</param> - /// <returns></returns> - public IExcelDataValidationDecimal AddDecimalValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationDecimal(_worksheet, address, ExcelDataValidationType.Decimal); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - - /// <summary> - /// Adds an <see cref="IExcelDataValidationList"/> to the worksheet. The accepted values are defined - /// in a list. - /// </summary> - /// <param name="address">The range/address to validate</param> - /// <returns></returns> - public IExcelDataValidationList AddListValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationList(_worksheet, address, ExcelDataValidationType.List); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - - /// <summary> - /// Adds an <see cref="IExcelDataValidationInt"/> regarding text length to the worksheet. - /// </summary> - /// <param name="address">The range/address to validate</param> - /// <returns></returns> - public IExcelDataValidationInt AddTextLengthValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.TextLength); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - - /// <summary> - /// Adds an <see cref="IExcelDataValidationDateTime"/> to the worksheet. - /// </summary> - /// <param name="address">The range/address to validate</param> - /// <returns></returns> - public IExcelDataValidationDateTime AddDateTimeValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationDateTime(_worksheet, address, ExcelDataValidationType.DateTime); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - - - public IExcelDataValidationTime AddTimeValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationTime(_worksheet, address, ExcelDataValidationType.Time); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - /// <summary> - /// Adds a <see cref="ExcelDataValidationCustom"/> to the worksheet. - /// </summary> - /// <param name="address">The range/address to validate</param> - /// <returns></returns> - public IExcelDataValidationCustom AddCustomValidation(string address) - { - ValidateAddress(address); - EnsureRootElementExists(); - var item = new ExcelDataValidationCustom(_worksheet, address, ExcelDataValidationType.Custom); - _validations.Add(item); - OnValidationCountChanged(); - return item; - } - - /// <summary> - /// Removes an <see cref="ExcelDataValidation"/> from the collection. - /// </summary> - /// <param name="item">The item to remove</param> - /// <returns>True if remove succeeds, otherwise false</returns> - /// <exception cref="ArgumentNullException">if <paramref name="item"/> is null</exception> - public bool Remove(IExcelDataValidation item) - { - if (!(item is ExcelDataValidation)) - { - throw new InvalidCastException("The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation"); - } - Require.Argument(item).IsNotNull("item"); - TopNode.RemoveChild(((ExcelDataValidation)item).TopNode); - var retVal = _validations.Remove(item); - if (retVal) OnValidationCountChanged(); - return retVal; - } - - /// <summary> - /// Number of validations - /// </summary> - public int Count - { - get { return _validations.Count; } - } - - /// <summary> - /// Index operator, returns by 0-based index - /// </summary> - /// <param name="index"></param> - /// <returns></returns> - public IExcelDataValidation this[int index] - { - get { return _validations[index]; } - set { _validations[index] = value; } - } - - /// <summary> - /// Index operator, returns a data validation which address partly or exactly matches the searched address. - /// </summary> - /// <param name="address">A cell address or range</param> - /// <returns>A <see cref="ExcelDataValidation"/> or null if no match</returns> - public IExcelDataValidation this[string address] - { - get - { - var searchedAddress = new ExcelAddress(address); - return _validations.Find(x => x.Address.Collide(searchedAddress) != ExcelAddressBase.eAddressCollition.No); - } - } - - /// <summary> - /// Returns all validations that matches the supplied predicate <paramref name="match"/>. - /// </summary> - /// <param name="match">predicate to filter out matching validations</param> - /// <returns></returns> - public IEnumerable<IExcelDataValidation> FindAll(Predicate<IExcelDataValidation> match) - { - return _validations.FindAll(match); - } - - /// <summary> - /// Returns the first matching validation. - /// </summary> - /// <param name="match"></param> - /// <returns></returns> - public IExcelDataValidation Find(Predicate<IExcelDataValidation> match) - { - return _validations.Find(match); - } - - /// <summary> - /// Removes all validations from the collection. - /// </summary> - public void Clear() - { - DeleteAllNode(DataValidationItemsPath.TrimStart('/')); - _validations.Clear(); - } - - /// <summary> - /// Removes the validations that matches the predicate - /// </summary> - /// <param name="match"></param> - public void RemoveAll(Predicate<IExcelDataValidation> match) - { - var matches = _validations.FindAll(match); - foreach (var m in matches) - { - if (!(m is ExcelDataValidation)) - { - throw new InvalidCastException("The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation"); - } - TopNode.SelectSingleNode(DataValidationPath.TrimStart('/'), NameSpaceManager).RemoveChild(((ExcelDataValidation)m).TopNode); - } - _validations.RemoveAll(match); - OnValidationCountChanged(); - } - - IEnumerator<IExcelDataValidation> IEnumerable<IExcelDataValidation>.GetEnumerator() - { - return _validations.GetEnumerator(); - } - - IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _validations.GetEnumerator(); - } + var type = ExcelDataValidationType.GetBySchemaName(typeSchema); + _validations.Add(ExcelDataValidationFactory.Create(type, worksheet, addr, node)); + } } + if (_validations.Count > 0) { + OnValidationCountChanged(); + } + } + + private void EnsureRootElementExists() { + var node = _worksheet.WorksheetXml.SelectSingleNode( + _dataValidationPath, + _worksheet.NameSpaceManager); + if (node == null) { + CreateNode(_dataValidationPath.TrimStart('/')); + } + } + + private void OnValidationCountChanged() { + //if (TopNode != null) + //{ + // SetXmlNodeString("@count", _validations.Count.ToString()); + //} + } + + private XmlNode GetRootNode() { + EnsureRootElementExists(); + TopNode = _worksheet.WorksheetXml.SelectSingleNode( + _dataValidationPath, + _worksheet.NameSpaceManager); + return TopNode; + } + + /// <summary> + /// Validates address - not empty, collisions + /// </summary> + /// <param name="address"></param> + /// <param name="validatingValidation"></param> + private void ValidateAddress(string address, IExcelDataValidation validatingValidation) { + Require.Argument(address).IsNotNullOrEmpty("address"); + + // ensure that the new address does not collide with an existing validation. + var newAddress = new ExcelAddress(address); + if (_validations.Count > 0) { + foreach (var validation in _validations) { + if (validatingValidation != null && validatingValidation == validation) { + continue; + } + var result = validation.Address.Collide(newAddress); + if (result != ExcelAddressBase.eAddressCollition.No) { + throw new InvalidOperationException( + string.Format( + "The address ({0}) collides with an existing validation ({1})", + address, + validation.Address.Address)); + } + } + } + } + + private void ValidateAddress(string address) { + ValidateAddress(address, null); + } + + /// <summary> + /// Validates all data validations. + /// </summary> + internal void ValidateAll() { + foreach (var validation in _validations) { + validation.Validate(); + + ValidateAddress(validation.Address.Address, validation); + } + } + + /// <summary> + /// Adds a <see cref="ExcelDataValidationAny"/> to the worksheet. + /// </summary> + /// <param name="address">The range/address to validate</param> + /// <returns></returns> + public IExcelDataValidationAny AddAnyValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationAny(_worksheet, address, ExcelDataValidationType.Any); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + /// <summary> + /// Adds an <see cref="IExcelDataValidationInt"/> to the worksheet. Whole means that the only accepted values + /// are integer values. + /// </summary> + /// <param name="address">the range/address to validate</param> + public IExcelDataValidationInt AddIntegerValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.Whole); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + /// <summary> + /// Addes an <see cref="IExcelDataValidationDecimal"/> to the worksheet. The only accepted values are + /// decimal values. + /// </summary> + /// <param name="address">The range/address to validate</param> + /// <returns></returns> + public IExcelDataValidationDecimal AddDecimalValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationDecimal(_worksheet, address, ExcelDataValidationType.Decimal); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + /// <summary> + /// Adds an <see cref="IExcelDataValidationList"/> to the worksheet. The accepted values are defined + /// in a list. + /// </summary> + /// <param name="address">The range/address to validate</param> + /// <returns></returns> + public IExcelDataValidationList AddListValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationList(_worksheet, address, ExcelDataValidationType.List); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + /// <summary> + /// Adds an <see cref="IExcelDataValidationInt"/> regarding text length to the worksheet. + /// </summary> + /// <param name="address">The range/address to validate</param> + /// <returns></returns> + public IExcelDataValidationInt AddTextLengthValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationInt(_worksheet, address, ExcelDataValidationType.TextLength); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + /// <summary> + /// Adds an <see cref="IExcelDataValidationDateTime"/> to the worksheet. + /// </summary> + /// <param name="address">The range/address to validate</param> + /// <returns></returns> + public IExcelDataValidationDateTime AddDateTimeValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationDateTime( + _worksheet, + address, + ExcelDataValidationType.DateTime); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + public IExcelDataValidationTime AddTimeValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationTime(_worksheet, address, ExcelDataValidationType.Time); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + /// <summary> + /// Adds a <see cref="ExcelDataValidationCustom"/> to the worksheet. + /// </summary> + /// <param name="address">The range/address to validate</param> + /// <returns></returns> + public IExcelDataValidationCustom AddCustomValidation(string address) { + ValidateAddress(address); + EnsureRootElementExists(); + var item = new ExcelDataValidationCustom(_worksheet, address, ExcelDataValidationType.Custom); + _validations.Add(item); + OnValidationCountChanged(); + return item; + } + + /// <summary> + /// Removes an <see cref="ExcelDataValidation"/> from the collection. + /// </summary> + /// <param name="item">The item to remove</param> + /// <returns>True if remove succeeds, otherwise false</returns> + /// <exception cref="ArgumentNullException">if <paramref name="item"/> is null</exception> + public bool Remove(IExcelDataValidation item) { + if (!(item is ExcelDataValidation)) { + throw new InvalidCastException( + "The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation"); + } + Require.Argument(item).IsNotNull("item"); + TopNode.RemoveChild(((ExcelDataValidation)item).TopNode); + var retVal = _validations.Remove(item); + if (retVal) { + OnValidationCountChanged(); + } + return retVal; + } + + /// <summary> + /// Number of validations + /// </summary> + public int Count => _validations.Count; + + /// <summary> + /// Index operator, returns by 0-based index + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public IExcelDataValidation this[int index] { + get { return _validations[index]; } + set { _validations[index] = value; } + } + + /// <summary> + /// Index operator, returns a data validation which address partly or exactly matches the searched address. + /// </summary> + /// <param name="address">A cell address or range</param> + /// <returns>A <see cref="ExcelDataValidation"/> or null if no match</returns> + public IExcelDataValidation this[string address] { + get { + var searchedAddress = new ExcelAddress(address); + return _validations.Find(x => + x.Address.Collide(searchedAddress) != ExcelAddressBase.eAddressCollition.No); + } + } + + /// <summary> + /// Returns all validations that matches the supplied predicate <paramref name="match"/>. + /// </summary> + /// <param name="match">predicate to filter out matching validations</param> + /// <returns></returns> + public IEnumerable<IExcelDataValidation> FindAll(Predicate<IExcelDataValidation> match) { + return _validations.FindAll(match); + } + + /// <summary> + /// Returns the first matching validation. + /// </summary> + /// <param name="match"></param> + /// <returns></returns> + public IExcelDataValidation Find(Predicate<IExcelDataValidation> match) { + return _validations.Find(match); + } + + /// <summary> + /// Removes all validations from the collection. + /// </summary> + public void Clear() { + DeleteAllNode(DataValidationItemsPath.TrimStart('/')); + _validations.Clear(); + } + + /// <summary> + /// Removes the validations that matches the predicate + /// </summary> + /// <param name="match"></param> + public void RemoveAll(Predicate<IExcelDataValidation> match) { + var matches = _validations.FindAll(match); + foreach (var m in matches) { + if (!(m is ExcelDataValidation)) { + throw new InvalidCastException( + "The supplied item must inherit OfficeOpenXml.DataValidation.ExcelDataValidation"); + } + TopNode + .SelectSingleNode(_dataValidationPath.TrimStart('/'), NameSpaceManager) + .RemoveChild(((ExcelDataValidation)m).TopNode); + } + _validations.RemoveAll(match); + OnValidationCountChanged(); + } + + IEnumerator<IExcelDataValidation> IEnumerable<IExcelDataValidation>.GetEnumerator() { + return _validations.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _validations.GetEnumerator(); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationCustom.cs b/EPPlus/DataValidation/ExcelDataValidationCustom.cs index 10718f3..f98b2f6 100644 --- a/EPPlus/DataValidation/ExcelDataValidationCustom.cs +++ b/EPPlus/DataValidation/ExcelDataValidationCustom.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,75 +13,81 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -using OfficeOpenXml.DataValidation.Formulas; + using System.Xml; using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.DataValidation.Formulas; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Custom validation, i.e. a formula. - /// </summary> - public class ExcelDataValidationCustom : ExcelDataValidationWithFormula<IExcelDataValidationFormula>, IExcelDataValidationCustom - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationCustom(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : base(worksheet, address, validationType) - { - Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path); - } +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - internal ExcelDataValidationCustom(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path); - } +/// <summary> +/// Custom validation, i.e. a formula. +/// </summary> +public class ExcelDataValidationCustom + : ExcelDataValidationWithFormula<IExcelDataValidationFormula>, + IExcelDataValidationCustom { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationCustom( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : base(worksheet, address, validationType) { + Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path); + } - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelDataValidationCustom(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { - Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path); - } - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + internal ExcelDataValidationCustom( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) { + Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path); + } + + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelDataValidationCustom( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) { + Formula = new ExcelDataValidationFormulaCustom(NameSpaceManager, TopNode, _formula1Path); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationDateTime.cs b/EPPlus/DataValidation/ExcelDataValidationDateTime.cs index 2a99ca0..c72a83d 100644 --- a/EPPlus/DataValidation/ExcelDataValidationDateTime.cs +++ b/EPPlus/DataValidation/ExcelDataValidationDateTime.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,78 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -using OfficeOpenXml.DataValidation.Formulas; using System.Xml; using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.DataValidation.Formulas; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Validation for <see cref="DateTime"/>. - /// </summary> - public class ExcelDataValidationDateTime : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>, IExcelDataValidationDateTime - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationDateTime(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : base(worksheet, address, validationType) - { - Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path); - } +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - internal ExcelDataValidationDateTime(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path); - } +/// <summary> +/// Validation for <see cref="DateTime"/>. +/// </summary> +public class ExcelDataValidationDateTime + : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDateTime>, + IExcelDataValidationDateTime { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationDateTime( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : base(worksheet, address, validationType) { + Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path); + } - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelDataValidationDateTime(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { - Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path); - } - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + internal ExcelDataValidationDateTime( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) { + Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path); + } + + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelDataValidationDateTime( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) { + Formula = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaDateTime(NameSpaceManager, TopNode, _formula2Path); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationDecimal.cs b/EPPlus/DataValidation/ExcelDataValidationDecimal.cs index 04c9a1e..1e8e8af 100644 --- a/EPPlus/DataValidation/ExcelDataValidationDecimal.cs +++ b/EPPlus/DataValidation/ExcelDataValidationDecimal.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,79 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Globalization; + using System.Xml; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -using OfficeOpenXml.DataValidation.Formulas; using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.DataValidation.Formulas; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Data validation for decimal values - /// </summary> - public class ExcelDataValidationDecimal : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>, IExcelDataValidationDecimal - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationDecimal(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : base(worksheet, address, validationType) - { - Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path); - } +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - internal ExcelDataValidationDecimal(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path); - } +/// <summary> +/// Data validation for decimal values +/// </summary> +public class ExcelDataValidationDecimal + : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaDecimal>, + IExcelDataValidationDecimal { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationDecimal( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : base(worksheet, address, validationType) { + Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path); + } - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager">For test purposes</param> - internal ExcelDataValidationDecimal(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { - Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path); - } - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + internal ExcelDataValidationDecimal( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) { + Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path); + } + + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager">For test purposes</param> + internal ExcelDataValidationDecimal( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) { + Formula = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaDecimal(NameSpaceManager, TopNode, _formula2Path); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationFactory.cs b/EPPlus/DataValidation/ExcelDataValidationFactory.cs index 023cfd4..86dcba6 100644 --- a/EPPlus/DataValidation/ExcelDataValidationFactory.cs +++ b/EPPlus/DataValidation/ExcelDataValidationFactory.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,68 +13,66 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 * Raziq York Added support for Any type 2014-08-08 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Factory class for ExcelDataValidation. - /// </summary> - internal static class ExcelDataValidationFactory - { - /// <summary> - /// Creates an instance of <see cref="ExcelDataValidation"/> out of the given parameters. - /// </summary> - /// <param name="type"></param> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="itemElementNode"></param> - /// <returns></returns> - public static ExcelDataValidation Create(ExcelDataValidationType type, ExcelWorksheet worksheet, string address, XmlNode itemElementNode) - { - Require.Argument(type).IsNotNull("validationType"); - switch (type.Type) - { - case eDataValidationType.Any: - return new ExcelDataValidationAny(worksheet, address, type, itemElementNode); - case eDataValidationType.TextLength: - case eDataValidationType.Whole: - return new ExcelDataValidationInt(worksheet, address, type, itemElementNode); - case eDataValidationType.Decimal: - return new ExcelDataValidationDecimal(worksheet, address, type, itemElementNode); - case eDataValidationType.List: - return new ExcelDataValidationList(worksheet, address, type, itemElementNode); - case eDataValidationType.DateTime: - return new ExcelDataValidationDateTime(worksheet, address, type, itemElementNode); - case eDataValidationType.Time: - return new ExcelDataValidationTime(worksheet, address, type, itemElementNode); - case eDataValidationType.Custom: - return new ExcelDataValidationCustom(worksheet, address, type, itemElementNode); - default: - throw new InvalidOperationException("Non supported validationtype: " + type.Type.ToString()); - } - } +namespace OfficeOpenXml.DataValidation; + +/// <summary> +/// Factory class for ExcelDataValidation. +/// </summary> +internal static class ExcelDataValidationFactory { + /// <summary> + /// Creates an instance of <see cref="ExcelDataValidation"/> out of the given parameters. + /// </summary> + /// <param name="type"></param> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="itemElementNode"></param> + /// <returns></returns> + public static ExcelDataValidation Create( + ExcelDataValidationType type, + ExcelWorksheet worksheet, + string address, + XmlNode itemElementNode) { + Require.Argument(type).IsNotNull("validationType"); + switch (type.Type) { + case eDataValidationType.Any: + return new ExcelDataValidationAny(worksheet, address, type, itemElementNode); + case eDataValidationType.TextLength: + case eDataValidationType.Whole: + return new ExcelDataValidationInt(worksheet, address, type, itemElementNode); + case eDataValidationType.Decimal: + return new ExcelDataValidationDecimal(worksheet, address, type, itemElementNode); + case eDataValidationType.List: + return new ExcelDataValidationList(worksheet, address, type, itemElementNode); + case eDataValidationType.DateTime: + return new ExcelDataValidationDateTime(worksheet, address, type, itemElementNode); + case eDataValidationType.Time: + return new ExcelDataValidationTime(worksheet, address, type, itemElementNode); + case eDataValidationType.Custom: + return new ExcelDataValidationCustom(worksheet, address, type, itemElementNode); + default: + throw new InvalidOperationException("Non supported validationtype: " + type.Type); } + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationInt.cs b/EPPlus/DataValidation/ExcelDataValidationInt.cs index c7aac88..12cdb94 100644 --- a/EPPlus/DataValidation/ExcelDataValidationInt.cs +++ b/EPPlus/DataValidation/ExcelDataValidationInt.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,78 +13,90 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas; -using OfficeOpenXml.DataValidation.Formulas.Contracts; + using System.Xml; using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.DataValidation.Formulas; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Data validation for integer values. - /// </summary> - public class ExcelDataValidationInt : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>, IExcelDataValidationInt - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationInt(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : base(worksheet, address, validationType) - { - Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula2Path); - } +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - internal ExcelDataValidationInt(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula2Path); - } +/// <summary> +/// Data validation for integer values. +/// </summary> +public class ExcelDataValidationInt + : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaInt>, + IExcelDataValidationInt { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationInt( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : base(worksheet, address, validationType) { + Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaInt( + worksheet.NameSpaceManager, + TopNode, + _formula2Path); + } - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager">For test purposes</param> - internal ExcelDataValidationInt(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { - Formula = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula2Path); - } - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + internal ExcelDataValidationInt( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) { + Formula = new ExcelDataValidationFormulaInt(worksheet.NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaInt( + worksheet.NameSpaceManager, + TopNode, + _formula2Path); + } + + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager">For test purposes</param> + internal ExcelDataValidationInt( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) { + Formula = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaInt(NameSpaceManager, TopNode, _formula2Path); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationList.cs b/EPPlus/DataValidation/ExcelDataValidationList.cs index 6368938..e9dbdf1 100644 --- a/EPPlus/DataValidation/ExcelDataValidationList.cs +++ b/EPPlus/DataValidation/ExcelDataValidationList.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,76 +13,81 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -using OfficeOpenXml.DataValidation.Formulas; + using System.Xml; using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.DataValidation.Formulas; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// This class represents an List data validation. - /// </summary> - public class ExcelDataValidationList : ExcelDataValidationWithFormula<IExcelDataValidationFormulaList>, IExcelDataValidationList - { - - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationList(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : base(worksheet, address, validationType) - { - Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path); - } +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - internal ExcelDataValidationList(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path); - } +/// <summary> +/// This class represents an List data validation. +/// </summary> +public class ExcelDataValidationList + : ExcelDataValidationWithFormula<IExcelDataValidationFormulaList>, + IExcelDataValidationList { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationList( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : base(worksheet, address, validationType) { + Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path); + } - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager">Namespace manager, for test purposes</param> - internal ExcelDataValidationList(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { - Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path); - } - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + internal ExcelDataValidationList( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) { + Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path); + } + + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager">Namespace manager, for test purposes</param> + internal ExcelDataValidationList( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) { + Formula = new ExcelDataValidationFormulaList(NameSpaceManager, TopNode, _formula1Path); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationOperator.cs b/EPPlus/DataValidation/ExcelDataValidationOperator.cs index 55db9dd..a6f3fe2 100644 --- a/EPPlus/DataValidation/ExcelDataValidationOperator.cs +++ b/EPPlus/DataValidation/ExcelDataValidationOperator.cs
@@ -13,42 +13,36 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Operator for comparison between Formula and Formula2 in a validation. - /// </summary> - public enum ExcelDataValidationOperator - { - any, - equal, - notEqual, - lessThan, - lessThanOrEqual, - greaterThan, - greaterThanOrEqual, - between, - notBetween - } +namespace OfficeOpenXml.DataValidation; + +/// <summary> +/// Operator for comparison between Formula and Formula2 in a validation. +/// </summary> +public enum ExcelDataValidationOperator { + Any, + Equal, + NotEqual, + LessThan, + LessThanOrEqual, + GreaterThan, + GreaterThanOrEqual, + Between, + NotBetween, }
diff --git a/EPPlus/DataValidation/ExcelDataValidationTime.cs b/EPPlus/DataValidation/ExcelDataValidationTime.cs index 3a1f70b..3c37d13 100644 --- a/EPPlus/DataValidation/ExcelDataValidationTime.cs +++ b/EPPlus/DataValidation/ExcelDataValidationTime.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,79 +13,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -using OfficeOpenXml.DataValidation.Formulas; + using System.Xml; using OfficeOpenXml.DataValidation.Contracts; -using System.Runtime.CompilerServices; +using OfficeOpenXml.DataValidation.Formulas; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Validation for times (<see cref="OfficeOpenXml.DataValidation.ExcelTime"/>). - /// </summary> - public class ExcelDataValidationTime : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>, IExcelDataValidationTime - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationTime(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : base(worksheet, address, validationType) - { - Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path); - } +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - internal ExcelDataValidationTime(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path); - } +/// <summary> +/// Validation for times (<see cref="OfficeOpenXml.DataValidation.ExcelTime"/>). +/// </summary> +public class ExcelDataValidationTime + : ExcelDataValidationWithFormula2<IExcelDataValidationFormulaTime>, + IExcelDataValidationTime { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationTime( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : base(worksheet, address, validationType) { + Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path); + } - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - /// <param name="itemElementNode"></param> - /// <param name="namespaceManager"></param> - internal ExcelDataValidationTime(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { - Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path); - Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path); - } - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + internal ExcelDataValidationTime( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) { + Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path); + } + + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + /// <param name="itemElementNode"></param> + /// <param name="namespaceManager"></param> + internal ExcelDataValidationTime( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) { + Formula = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula1Path); + Formula2 = new ExcelDataValidationFormulaTime(NameSpaceManager, TopNode, _formula2Path); + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationType.cs b/EPPlus/DataValidation/ExcelDataValidationType.cs index 6ca1786..50b8571 100644 --- a/EPPlus/DataValidation/ExcelDataValidationType.cs +++ b/EPPlus/DataValidation/ExcelDataValidationType.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,307 +13,277 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 * Raziq York Added support for Any type 2014-08-08 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Enum for available data validation types - /// </summary> - public enum eDataValidationType - { - /// <summary> - /// Any value - /// </summary> - Any, - /// <summary> - /// Integer value - /// </summary> - Whole, - /// <summary> - /// Decimal values - /// </summary> - Decimal, - /// <summary> - /// List of values - /// </summary> - List, - /// <summary> - /// Text length validation - /// </summary> - TextLength, - /// <summary> - /// DateTime validation - /// </summary> - DateTime, - /// <summary> - /// Time validation - /// </summary> - Time, - /// <summary> - /// Custom validation - /// </summary> - Custom +namespace OfficeOpenXml.DataValidation; + +/// <summary> +/// Enum for available data validation types +/// </summary> +public enum eDataValidationType { + /// <summary> + /// Any value + /// </summary> + Any, + + /// <summary> + /// Integer value + /// </summary> + Whole, + + /// <summary> + /// Decimal values + /// </summary> + Decimal, + + /// <summary> + /// List of values + /// </summary> + List, + + /// <summary> + /// Text length validation + /// </summary> + TextLength, + + /// <summary> + /// DateTime validation + /// </summary> + DateTime, + + /// <summary> + /// Time validation + /// </summary> + Time, + + /// <summary> + /// Custom validation + /// </summary> + Custom, +} + +internal static class DataValidationSchemaNames { + public const string Any = ""; + public const string Whole = "whole"; + public const string Decimal = "decimal"; + public const string List = "list"; + public const string TextLength = "textLength"; + public const string Date = "date"; + public const string Time = "time"; + public const string Custom = "custom"; +} + +/// <summary> +/// Types of datavalidation +/// </summary> +public class ExcelDataValidationType { + private ExcelDataValidationType( + eDataValidationType validationType, + bool allowOperator, + string schemaName) { + Type = validationType; + AllowOperator = allowOperator; + SchemaName = schemaName; + } + + /// <summary> + /// Validation type + /// </summary> + public eDataValidationType Type { get; private set; } + + internal string SchemaName { get; private set; } + + /// <summary> + /// This type allows operator to be set + /// </summary> + internal bool AllowOperator { get; private set; } + + /// <summary> + /// Returns a validation type by <see cref="eDataValidationType"/> + /// </summary> + /// <param name="type"></param> + /// <returns></returns> + internal static ExcelDataValidationType GetByValidationType(eDataValidationType type) { + switch (type) { + case eDataValidationType.Any: + return Any; + case eDataValidationType.Whole: + return Whole; + case eDataValidationType.List: + return List; + case eDataValidationType.Decimal: + return Decimal; + case eDataValidationType.TextLength: + return TextLength; + case eDataValidationType.DateTime: + return DateTime; + case eDataValidationType.Time: + return Time; + case eDataValidationType.Custom: + return Custom; + default: + throw new InvalidOperationException("Non supported Validationtype : " + type); } + } - internal static class DataValidationSchemaNames - { - public const string Any = ""; - public const string Whole = "whole"; - public const string Decimal = "decimal"; - public const string List = "list"; - public const string TextLength = "textLength"; - public const string Date = "date"; - public const string Time = "time"; - public const string Custom = "custom"; + internal static ExcelDataValidationType GetBySchemaName(string schemaName) { + switch (schemaName) { + case DataValidationSchemaNames.Any: + return Any; + case DataValidationSchemaNames.Whole: + return Whole; + case DataValidationSchemaNames.Decimal: + return Decimal; + case DataValidationSchemaNames.List: + return List; + case DataValidationSchemaNames.TextLength: + return TextLength; + case DataValidationSchemaNames.Date: + return DateTime; + case DataValidationSchemaNames.Time: + return Time; + case DataValidationSchemaNames.Custom: + return Custom; + default: + throw new ArgumentException("Invalid schemaname: " + schemaName); } + } - /// <summary> - /// Types of datavalidation - /// </summary> - public class ExcelDataValidationType - { - private ExcelDataValidationType(eDataValidationType validationType, bool allowOperator, string schemaName) - { - Type = validationType; - AllowOperator = allowOperator; - SchemaName = schemaName; - } - - /// <summary> - /// Validation type - /// </summary> - public eDataValidationType Type - { - get; - private set; - } - - internal string SchemaName - { - get; - private set; - } - - /// <summary> - /// This type allows operator to be set - /// </summary> - internal bool AllowOperator - { - - get; - private set; - } - - /// <summary> - /// Returns a validation type by <see cref="eDataValidationType"/> - /// </summary> - /// <param name="type"></param> - /// <returns></returns> - internal static ExcelDataValidationType GetByValidationType(eDataValidationType type) - { - switch (type) - { - case eDataValidationType.Any: - return ExcelDataValidationType.Any; - case eDataValidationType.Whole: - return ExcelDataValidationType.Whole; - case eDataValidationType.List: - return ExcelDataValidationType.List; - case eDataValidationType.Decimal: - return ExcelDataValidationType.Decimal; - case eDataValidationType.TextLength: - return ExcelDataValidationType.TextLength; - case eDataValidationType.DateTime: - return ExcelDataValidationType.DateTime; - case eDataValidationType.Time: - return ExcelDataValidationType.Time; - case eDataValidationType.Custom: - return ExcelDataValidationType.Custom; - default: - throw new InvalidOperationException("Non supported Validationtype : " + type.ToString()); - } - } - - internal static ExcelDataValidationType GetBySchemaName(string schemaName) - { - switch (schemaName) - { - case DataValidationSchemaNames.Any: - return ExcelDataValidationType.Any; - case DataValidationSchemaNames.Whole: - return ExcelDataValidationType.Whole; - case DataValidationSchemaNames.Decimal: - return ExcelDataValidationType.Decimal; - case DataValidationSchemaNames.List: - return ExcelDataValidationType.List; - case DataValidationSchemaNames.TextLength: - return ExcelDataValidationType.TextLength; - case DataValidationSchemaNames.Date: - return ExcelDataValidationType.DateTime; - case DataValidationSchemaNames.Time: - return ExcelDataValidationType.Time; - case DataValidationSchemaNames.Custom: - return ExcelDataValidationType.Custom; - default: - throw new ArgumentException("Invalid schemaname: " + schemaName); - } - } - - /// <summary> - /// Overridden Equals, compares on internal validation type - /// </summary> - /// <param name="obj"></param> - /// <returns></returns> - public override bool Equals(object obj) - { - if (!(obj is ExcelDataValidationType)) - { - return false; - } - return ((ExcelDataValidationType)obj).Type == Type; - } - - /// <summary> - /// Overrides GetHashCode() - /// </summary> - /// <returns></returns> - public override int GetHashCode() - { - return base.GetHashCode(); - } - - /// <summary> - /// Integer values - /// </summary> - private static ExcelDataValidationType _any; - public static ExcelDataValidationType Any - { - get - { - if (_any == null) - { - _any = new ExcelDataValidationType(eDataValidationType.Any, false, DataValidationSchemaNames.Any); - } - return _any; - } - } - - /// <summary> - /// Integer values - /// </summary> - private static ExcelDataValidationType _whole; - public static ExcelDataValidationType Whole - { - get - { - if (_whole == null) - { - _whole = new ExcelDataValidationType(eDataValidationType.Whole, true, DataValidationSchemaNames.Whole); - } - return _whole; - } - } - - /// <summary> - /// List of allowed values - /// </summary> - private static ExcelDataValidationType _list; - public static ExcelDataValidationType List - { - get - { - if (_list == null) - { - _list = new ExcelDataValidationType(eDataValidationType.List, false, DataValidationSchemaNames.List); - } - return _list; - } - } - - private static ExcelDataValidationType _decimal; - public static ExcelDataValidationType Decimal - { - get - { - if (_decimal == null) - { - _decimal = new ExcelDataValidationType(eDataValidationType.Decimal, true, DataValidationSchemaNames.Decimal); - } - return _decimal; - } - } - - private static ExcelDataValidationType _textLength; - public static ExcelDataValidationType TextLength - { - get - { - if (_textLength == null) - { - _textLength = new ExcelDataValidationType(eDataValidationType.TextLength, true, DataValidationSchemaNames.TextLength); - } - return _textLength; - } - } - - private static ExcelDataValidationType _dateTime; - public static ExcelDataValidationType DateTime - { - get - { - if (_dateTime == null) - { - _dateTime = new ExcelDataValidationType(eDataValidationType.DateTime, true, DataValidationSchemaNames.Date); - } - return _dateTime; - } - } - - private static ExcelDataValidationType _time; - public static ExcelDataValidationType Time - { - get - { - if (_time == null) - { - _time = new ExcelDataValidationType(eDataValidationType.Time, true, DataValidationSchemaNames.Time); - } - return _time; - } - } - - private static ExcelDataValidationType _custom; - public static ExcelDataValidationType Custom - { - get - { - if (_custom == null) - { - _custom = new ExcelDataValidationType(eDataValidationType.Custom, true, DataValidationSchemaNames.Custom); - } - return _custom; - } - } + /// <summary> + /// Overridden Equals, compares on internal validation type + /// </summary> + /// <param name="obj"></param> + /// <returns></returns> + public override bool Equals(object obj) { + if (!(obj is ExcelDataValidationType)) { + return false; } + return ((ExcelDataValidationType)obj).Type == Type; + } + + /// <summary> + /// Overrides GetHashCode() + /// </summary> + /// <returns></returns> + public override int GetHashCode() { + return base.GetHashCode(); + } + + /// <summary> + /// Integer values + /// </summary> + private static ExcelDataValidationType _any; + + public static ExcelDataValidationType Any { + get { + if (_any == null) { + _any = new(eDataValidationType.Any, false, DataValidationSchemaNames.Any); + } + return _any; + } + } + + /// <summary> + /// Integer values + /// </summary> + private static ExcelDataValidationType _whole; + + public static ExcelDataValidationType Whole { + get { + if (_whole == null) { + _whole = new(eDataValidationType.Whole, true, DataValidationSchemaNames.Whole); + } + return _whole; + } + } + + /// <summary> + /// List of allowed values + /// </summary> + private static ExcelDataValidationType _list; + + public static ExcelDataValidationType List { + get { + if (_list == null) { + _list = new(eDataValidationType.List, false, DataValidationSchemaNames.List); + } + return _list; + } + } + + private static ExcelDataValidationType _decimal; + + public static ExcelDataValidationType Decimal { + get { + if (_decimal == null) { + _decimal = new(eDataValidationType.Decimal, true, DataValidationSchemaNames.Decimal); + } + return _decimal; + } + } + + private static ExcelDataValidationType _textLength; + + public static ExcelDataValidationType TextLength { + get { + if (_textLength == null) { + _textLength = new( + eDataValidationType.TextLength, + true, + DataValidationSchemaNames.TextLength); + } + return _textLength; + } + } + + private static ExcelDataValidationType _dateTime; + + public static ExcelDataValidationType DateTime { + get { + if (_dateTime == null) { + _dateTime = new(eDataValidationType.DateTime, true, DataValidationSchemaNames.Date); + } + return _dateTime; + } + } + + private static ExcelDataValidationType _time; + + public static ExcelDataValidationType Time { + get { + if (_time == null) { + _time = new(eDataValidationType.Time, true, DataValidationSchemaNames.Time); + } + return _time; + } + } + + private static ExcelDataValidationType _custom; + + public static ExcelDataValidationType Custom { + get { + if (_custom == null) { + _custom = new(eDataValidationType.Custom, true, DataValidationSchemaNames.Custom); + } + return _custom; + } + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationWarningStyle.cs b/EPPlus/DataValidation/ExcelDataValidationWarningStyle.cs index f6a0578..ae808bb 100644 --- a/EPPlus/DataValidation/ExcelDataValidationWarningStyle.cs +++ b/EPPlus/DataValidation/ExcelDataValidationWarningStyle.cs
@@ -13,49 +13,46 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// warning style, controls how Excel will handle invalid changes. - /// </summary> - public enum ExcelDataValidationWarningStyle - { - /// <summary> - /// warning style will be excluded - /// </summary> - undefined, - /// <summary> - /// stop warning style, invalid changes will not be accepted - /// </summary> - stop, - /// <summary> - /// warning will be presented when an attempt to an invalid change is done, but the change will be accepted. - /// </summary> - warning, - /// <summary> - /// information warning style. - /// </summary> - information - } +namespace OfficeOpenXml.DataValidation; + +/// <summary> +/// warning style, controls how Excel will handle invalid changes. +/// </summary> +public enum ExcelDataValidationWarningStyle { + /// <summary> + /// warning style will be excluded + /// </summary> + Undefined, + + /// <summary> + /// stop warning style, invalid changes will not be accepted + /// </summary> + Stop, + + /// <summary> + /// warning will be presented when an attempt to an invalid change is done, but the change will be accepted. + /// </summary> + Warning, + + /// <summary> + /// information warning style. + /// </summary> + Information, }
diff --git a/EPPlus/DataValidation/ExcelDataValidationWithFormula.cs b/EPPlus/DataValidation/ExcelDataValidationWithFormula.cs index 30b66d3..7c20825 100644 --- a/EPPlus/DataValidation/ExcelDataValidationWithFormula.cs +++ b/EPPlus/DataValidation/ExcelDataValidationWithFormula.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,97 +13,92 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; using System.Xml; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// A validation containing a formula - /// </summary> - /// <typeparam name="T"></typeparam> - public class ExcelDataValidationWithFormula<T> : ExcelDataValidation - where T : IExcelDataValidationFormula - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationWithFormula(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : this(worksheet, address, validationType, null) - { +namespace OfficeOpenXml.DataValidation; - } +/// <summary> +/// A validation containing a formula +/// </summary> +/// <typeparam name="T"></typeparam> +public class ExcelDataValidationWithFormula<T> : ExcelDataValidation + where T : IExcelDataValidationFormula { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationWithFormula( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : this(worksheet, address, validationType, null) {} - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet">Worksheet that owns the validation</param> - /// <param name="itemElementNode">Xml top node (dataValidations)</param> - /// <param name="validationType">Data validation type</param> - /// <param name="address">address for data validation</param> - internal ExcelDataValidationWithFormula(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet">Worksheet that owns the validation</param> + /// <param name="itemElementNode">Xml top node (dataValidations)</param> + /// <param name="validationType">Data validation type</param> + /// <param name="address">address for data validation</param> + internal ExcelDataValidationWithFormula( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) {} - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet">Worksheet that owns the validation</param> - /// <param name="itemElementNode">Xml top node (dataValidations)</param> - /// <param name="validationType">Data validation type</param> - /// <param name="address">address for data validation</param> - /// <param name="namespaceManager">for test purposes</param> - internal ExcelDataValidationWithFormula(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet">Worksheet that owns the validation</param> + /// <param name="itemElementNode">Xml top node (dataValidations)</param> + /// <param name="validationType">Data validation type</param> + /// <param name="address">address for data validation</param> + /// <param name="namespaceManager">for test purposes</param> + internal ExcelDataValidationWithFormula( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) {} - } + /// <summary> + /// Formula - Either a {T} value (except for custom validation) or a spreadsheet formula + /// </summary> + public T Formula { get; protected set; } - - /// <summary> - /// Formula - Either a {T} value (except for custom validation) or a spreadsheet formula - /// </summary> - public T Formula - { - get; - protected set; - } - - public override void Validate() - { - base.Validate(); - if (Operator == ExcelDataValidationOperator.between || Operator == ExcelDataValidationOperator.notBetween) - { - if (string.IsNullOrEmpty(Formula2Internal)) - { - throw new InvalidOperationException("Validation of " + Address.Address + " failed: Formula2 must be set if operator is 'between' or 'notBetween'"); - } - } - } + public override void Validate() { + base.Validate(); + if (Operator == ExcelDataValidationOperator.Between + || Operator == ExcelDataValidationOperator.NotBetween) { + if (string.IsNullOrEmpty(Formula2Internal)) { + throw new InvalidOperationException( + "Validation of " + + Address.Address + + " failed: Formula2 must be set if operator is 'between' or 'notBetween'"); + } } + } }
diff --git a/EPPlus/DataValidation/ExcelDataValidationWithFormula2.cs b/EPPlus/DataValidation/ExcelDataValidationWithFormula2.cs index a8fecd3..3b9b7c0 100644 --- a/EPPlus/DataValidation/ExcelDataValidationWithFormula2.cs +++ b/EPPlus/DataValidation/ExcelDataValidationWithFormula2.cs
@@ -13,79 +13,74 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; + using System.Xml; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation -{ - public class ExcelDataValidationWithFormula2<T> : ExcelDataValidationWithFormula<T> - where T : IExcelDataValidationFormula - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet"></param> - /// <param name="address"></param> - /// <param name="validationType"></param> - internal ExcelDataValidationWithFormula2(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType) - : this(worksheet, address, validationType, null) - { +namespace OfficeOpenXml.DataValidation; - } +public class ExcelDataValidationWithFormula2<T> : ExcelDataValidationWithFormula<T> + where T : IExcelDataValidationFormula { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet"></param> + /// <param name="address"></param> + /// <param name="validationType"></param> + internal ExcelDataValidationWithFormula2( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType) + : this(worksheet, address, validationType, null) {} - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet">Worksheet that owns the validation</param> - /// <param name="itemElementNode">Xml top node (dataValidations)</param> - /// <param name="validationType">Data validation type</param> - /// <param name="address">address for data validation</param> - internal ExcelDataValidationWithFormula2(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode) - : base(worksheet, address, validationType, itemElementNode) - { - - } + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet">Worksheet that owns the validation</param> + /// <param name="itemElementNode">Xml top node (dataValidations)</param> + /// <param name="validationType">Data validation type</param> + /// <param name="address">address for data validation</param> + internal ExcelDataValidationWithFormula2( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode) + : base(worksheet, address, validationType, itemElementNode) {} - /// <summary> - /// Constructor - /// </summary> - /// <param name="worksheet">Worksheet that owns the validation</param> - /// <param name="itemElementNode">Xml top node (dataValidations)</param> - /// <param name="validationType">Data validation type</param> - /// <param name="address">address for data validation</param> - /// <param name="namespaceManager">for test purposes</param> - internal ExcelDataValidationWithFormula2(ExcelWorksheet worksheet, string address, ExcelDataValidationType validationType, XmlNode itemElementNode, XmlNamespaceManager namespaceManager) - : base(worksheet, address, validationType, itemElementNode, namespaceManager) - { + /// <summary> + /// Constructor + /// </summary> + /// <param name="worksheet">Worksheet that owns the validation</param> + /// <param name="itemElementNode">Xml top node (dataValidations)</param> + /// <param name="validationType">Data validation type</param> + /// <param name="address">address for data validation</param> + /// <param name="namespaceManager">for test purposes</param> + internal ExcelDataValidationWithFormula2( + ExcelWorksheet worksheet, + string address, + ExcelDataValidationType validationType, + XmlNode itemElementNode, + XmlNamespaceManager namespaceManager) + : base(worksheet, address, validationType, itemElementNode, namespaceManager) {} - } - /// <summary> - /// Formula - Either a {T} value or a spreadsheet formula - /// </summary> - public T Formula2 - { - get; - protected set; - } - } + /// <summary> + /// Formula - Either a {T} value or a spreadsheet formula + /// </summary> + public T Formula2 { get; protected set; } }
diff --git a/EPPlus/DataValidation/ExcelTime.cs b/EPPlus/DataValidation/ExcelTime.cs index c60a5c0..783eb17 100644 --- a/EPPlus/DataValidation/ExcelTime.cs +++ b/EPPlus/DataValidation/ExcelTime.cs
@@ -13,257 +13,212 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Globalization; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Represents a time between 00:00:00 and 23:59:59 - /// </summary> - public class ExcelTime - { - private event EventHandler _timeChanged; - private readonly decimal SecondsPerDay = 3600 * 24; - private readonly decimal SecondsPerHour = 3600; - private readonly decimal SecondsPerMinute = 60; - /// <summary> - /// Max number of decimals when rounding. - /// </summary> - public const int NumberOfDecimals = 15; +namespace OfficeOpenXml.DataValidation; - /// <summary> - /// Default constructor - /// </summary> - public ExcelTime() - { +/// <summary> +/// Represents a time between 00:00:00 and 23:59:59 +/// </summary> +public class ExcelTime { + private event EventHandler TimeChangedEvent; - } + private readonly decimal SecondsPerDay = 3600 * 24; + private readonly decimal SecondsPerHour = 3600; + private readonly decimal SecondsPerMinute = 60; - /// <summary> - /// Constructor - /// </summary> - /// <param name="value">An existing time for initialization</param> - public ExcelTime(decimal value) - { - if (value < 0M) - { - throw new ArgumentException("Value cannot be less than 0"); - } - else if (value >= 1M) - { - throw new ArgumentException("Value cannot be greater or equal to 1"); - } - Init(value); - } + /// <summary> + /// Max number of decimals when rounding. + /// </summary> + public const int NumberOfDecimals = 15; - private void Init(decimal value) - { - // handle hour - decimal totalSeconds = value * SecondsPerDay; - decimal hour = Math.Floor(totalSeconds / SecondsPerHour); - Hour = (int)hour; + /// <summary> + /// Default constructor + /// </summary> + public ExcelTime() {} - // handle minute - decimal remainingSeconds = totalSeconds - (hour * SecondsPerHour); - decimal minute = Math.Floor(remainingSeconds / SecondsPerMinute); - Minute = (int)minute; - - // handle second - remainingSeconds = totalSeconds - (hour * SecondsPerHour) - (minute * SecondsPerMinute); - decimal second = Math.Round(remainingSeconds, MidpointRounding.AwayFromZero); - // Second might be rounded to 60... the SetSecond method handles that. - SetSecond((int)second); - } - - /// <summary> - /// If we are unlucky second might be rounded up to 60. This will have the minute to be raised and might affect the hour. - /// </summary> - /// <param name="value"></param> - private void SetSecond(int value) - { - if (value == 60) - { - Second = 0; - var minute = Minute + 1; - SetMinute(minute); - } - else - { - Second = value; - } - } - - private void SetMinute(int value) - { - if (value == 60) - { - Minute = 0; - var hour = Hour + 1; - SetHour(hour); - } - else - { - Minute = value; - } - } - - private void SetHour(int value) - { - if (value == 24) - { - Hour = 0; - } - } - - internal event EventHandler TimeChanged - { - add { _timeChanged += value; } - remove { _timeChanged -= value; } - } - - private void OnTimeChanged() - { - if (_timeChanged != null) - { - _timeChanged(this, EventArgs.Empty); - } - } - - private int _hour; - /// <summary> - /// Hour between 0 and 23 - /// </summary> - public int Hour - { - get - { - return _hour; - } - set - { - if (value < 0) - { - throw new InvalidOperationException("Value for hour cannot be negative"); - } - if (value > 23) - { - throw new InvalidOperationException("Value for hour cannot be greater than 23"); - } - _hour = value; - OnTimeChanged(); - } - } - - private int _minute; - /// <summary> - /// Minute between 0 and 59 - /// </summary> - public int Minute - { - get - { - return _minute; - } - set - { - if (value < 0) - { - throw new InvalidOperationException("Value for minute cannot be negative"); - } - if (value > 59) - { - throw new InvalidOperationException("Value for minute cannot be greater than 59"); - } - _minute = value; - OnTimeChanged(); - } - } - - private int? _second; - /// <summary> - /// Second between 0 and 59 - /// </summary> - public int? Second - { - get - { - return _second; - } - set - { - if (value < 0) - { - throw new InvalidOperationException("Value for second cannot be negative"); - } - if (value > 59) - { - throw new InvalidOperationException("Value for second cannot be greater than 59"); - } - _second = value; - OnTimeChanged(); - } - } - - private decimal Round(decimal value) - { - return Math.Round(value, NumberOfDecimals); - } - - private decimal ToSeconds() - { - var result = Hour * SecondsPerHour; - result += Minute * SecondsPerMinute; - result += Second ?? 0; - return (decimal)result; - } - - /// <summary> - /// Returns the excel decimal representation of a time. - /// </summary> - /// <returns></returns> - public decimal ToExcelTime() - { - var seconds = ToSeconds(); - return Round(seconds / (decimal)SecondsPerDay); - } - - /// <summary> - /// Returns the excel decimal representation of a time as a string. - /// </summary> - /// <returns></returns> - public string ToExcelString() - { - return ToExcelTime().ToString(CultureInfo.InvariantCulture); - } - - public override string ToString() - { - var second = Second ?? 0; - return string.Format("{0}:{1}:{2}", - Hour < 10 ? "0" + Hour.ToString() : Hour.ToString(), - Minute < 10 ? "0" + Minute.ToString() : Minute.ToString(), - second < 10 ? "0" + second.ToString() : second.ToString()); - } - + /// <summary> + /// Constructor + /// </summary> + /// <param name="value">An existing time for initialization</param> + public ExcelTime(decimal value) { + if (value < 0M) { + throw new ArgumentException("Value cannot be less than 0"); } + if (value >= 1M) { + throw new ArgumentException("Value cannot be greater or equal to 1"); + } + Init(value); + } + + private void Init(decimal value) { + // handle hour + decimal totalSeconds = value * SecondsPerDay; + decimal hour = Math.Floor(totalSeconds / SecondsPerHour); + Hour = (int)hour; + + // handle minute + decimal remainingSeconds = totalSeconds - (hour * SecondsPerHour); + decimal minute = Math.Floor(remainingSeconds / SecondsPerMinute); + Minute = (int)minute; + + // handle second + remainingSeconds = totalSeconds - (hour * SecondsPerHour) - (minute * SecondsPerMinute); + decimal second = Math.Round(remainingSeconds, MidpointRounding.AwayFromZero); + // Second might be rounded to 60... the SetSecond method handles that. + SetSecond((int)second); + } + + /// <summary> + /// If we are unlucky second might be rounded up to 60. This will have the minute to be raised and might affect the hour. + /// </summary> + /// <param name="value"></param> + private void SetSecond(int value) { + if (value == 60) { + Second = 0; + var minute = Minute + 1; + SetMinute(minute); + } else { + Second = value; + } + } + + private void SetMinute(int value) { + if (value == 60) { + Minute = 0; + var hour = Hour + 1; + SetHour(hour); + } else { + Minute = value; + } + } + + private void SetHour(int value) { + if (value == 24) { + Hour = 0; + } + } + + internal event EventHandler TimeChanged { + add => TimeChangedEvent += value; + remove => TimeChangedEvent -= value; + } + + private void OnTimeChanged() { + if (TimeChangedEvent != null) { + TimeChangedEvent(this, EventArgs.Empty); + } + } + + private int _hour; + + /// <summary> + /// Hour between 0 and 23 + /// </summary> + public int Hour { + get => _hour; + set { + if (value < 0) { + throw new InvalidOperationException("Value for hour cannot be negative"); + } + if (value > 23) { + throw new InvalidOperationException("Value for hour cannot be greater than 23"); + } + _hour = value; + OnTimeChanged(); + } + } + + private int _minute; + + /// <summary> + /// Minute between 0 and 59 + /// </summary> + public int Minute { + get => _minute; + set { + if (value < 0) { + throw new InvalidOperationException("Value for minute cannot be negative"); + } + if (value > 59) { + throw new InvalidOperationException("Value for minute cannot be greater than 59"); + } + _minute = value; + OnTimeChanged(); + } + } + + private int? _second; + + /// <summary> + /// Second between 0 and 59 + /// </summary> + public int? Second { + get => _second; + set { + if (value < 0) { + throw new InvalidOperationException("Value for second cannot be negative"); + } + if (value > 59) { + throw new InvalidOperationException("Value for second cannot be greater than 59"); + } + _second = value; + OnTimeChanged(); + } + } + + private decimal Round(decimal value) { + return Math.Round(value, NumberOfDecimals); + } + + private decimal ToSeconds() { + var result = Hour * SecondsPerHour; + result += Minute * SecondsPerMinute; + result += Second ?? 0; + return result; + } + + /// <summary> + /// Returns the excel decimal representation of a time. + /// </summary> + /// <returns></returns> + public decimal ToExcelTime() { + var seconds = ToSeconds(); + return Round(seconds / SecondsPerDay); + } + + /// <summary> + /// Returns the excel decimal representation of a time as a string. + /// </summary> + /// <returns></returns> + public string ToExcelString() { + return ToExcelTime().ToString(CultureInfo.InvariantCulture); + } + + public override string ToString() { + var second = Second ?? 0; + return string.Format( + "{0}:{1}:{2}", + Hour < 10 ? "0" + Hour : Hour.ToString(), + Minute < 10 ? "0" + Minute : Minute.ToString(), + second < 10 ? "0" + second : second.ToString()); + } }
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs index b25c1ad..fee785c 100644 --- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs +++ b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormula.cs
@@ -13,37 +13,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Formulas.Contracts -{ - /// <summary> - /// Interface for a data validation formula - /// </summary> - public interface IExcelDataValidationFormula - { - /// <summary> - /// An excel formula - /// </summary> - string ExcelFormula { get; set; } - } +namespace OfficeOpenXml.DataValidation.Formulas.Contracts; + +/// <summary> +/// Interface for a data validation formula +/// </summary> +public interface IExcelDataValidationFormula { + /// <summary> + /// An excel formula + /// </summary> + string ExcelFormula { get; set; } }
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs index 1380c48..2cc6df2 100644 --- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs +++ b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDateTime.cs
@@ -13,33 +13,29 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Formulas.Contracts -{ - /// <summary> - /// Validation formula interface for <see cref="DateTime"/> - /// </summary> - public interface IExcelDataValidationFormulaDateTime : IExcelDataValidationFormulaWithValue<DateTime?> - { - } -} +using System; + +namespace OfficeOpenXml.DataValidation.Formulas.Contracts; + +/// <summary> +/// Validation formula interface for <see cref="DateTime"/> +/// </summary> +public interface IExcelDataValidationFormulaDateTime + : IExcelDataValidationFormulaWithValue<DateTime?> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs index a77761e..0a87a75 100644 --- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs +++ b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaDecimal.cs
@@ -13,33 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Formulas.Contracts -{ - /// <summary> - /// Interface for a data validation formula of <see cref="System.Single">float</see> value - /// </summary> - public interface IExcelDataValidationFormulaDecimal : IExcelDataValidationFormulaWithValue<double?> - { - } -} +namespace OfficeOpenXml.DataValidation.Formulas.Contracts; + +/// <summary> +/// Interface for a data validation formula of <see cref="System.Single">float</see> value +/// </summary> +public interface IExcelDataValidationFormulaDecimal + : IExcelDataValidationFormulaWithValue<double?> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs index ba1d47c..47ecfaa 100644 --- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs +++ b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaInt.cs
@@ -13,33 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Formulas.Contracts -{ - /// <summary> - /// Interface for a data validation formula of <see cref="System.Int32"/> value - /// </summary> - public interface IExcelDataValidationFormulaInt : IExcelDataValidationFormulaWithValue<int?> - { - } -} +namespace OfficeOpenXml.DataValidation.Formulas.Contracts; + +/// <summary> +/// Interface for a data validation formula of <see cref="System.Int32"/> value +/// </summary> +public interface IExcelDataValidationFormulaInt : IExcelDataValidationFormulaWithValue<int?> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs index 2162b57..6a799b4 100644 --- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs +++ b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaList.cs
@@ -13,37 +13,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Formulas.Contracts -{ - /// <summary> - /// Interface for a data validation of list type - /// </summary> - public interface IExcelDataValidationFormulaList : IExcelDataValidationFormula - { - /// <summary> - /// A list of value strings. - /// </summary> - IList<string> Values { get; } - } +using System.Collections.Generic; + +namespace OfficeOpenXml.DataValidation.Formulas.Contracts; + +/// <summary> +/// Interface for a data validation of list type +/// </summary> +public interface IExcelDataValidationFormulaList : IExcelDataValidationFormula { + /// <summary> + /// A list of value strings. + /// </summary> + IList<string> Values { get; } }
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs index 26fc36a..a9f1f5d 100644 --- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs +++ b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaTime.cs
@@ -13,31 +13,24 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation; -namespace OfficeOpenXml.DataValidation.Formulas.Contracts -{ - public interface IExcelDataValidationFormulaTime : IExcelDataValidationFormulaWithValue<ExcelTime> - { - } -} +namespace OfficeOpenXml.DataValidation.Formulas.Contracts; + +public interface IExcelDataValidationFormulaTime + : IExcelDataValidationFormulaWithValue<ExcelTime> {}
diff --git a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs index 70b1bbc..21b937b 100644 --- a/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs +++ b/EPPlus/DataValidation/Formulas/Contracts/IExcelDataValidationFormulaWithValue.cs
@@ -13,38 +13,32 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.DataValidation.Formulas.Contracts -{ - /// <summary> - /// Interface for a formula with a value - /// </summary> - /// <typeparam name="T"></typeparam> - public interface IExcelDataValidationFormulaWithValue<T> : IExcelDataValidationFormula - { - /// <summary> - /// The value. - /// </summary> - T Value { get; set; } - } +namespace OfficeOpenXml.DataValidation.Formulas.Contracts; + +/// <summary> +/// Interface for a formula with a value +/// </summary> +/// <typeparam name="T"></typeparam> +public interface IExcelDataValidationFormulaWithValue<T> : IExcelDataValidationFormula { + /// <summary> + /// The value. + /// </summary> + T Value { get; set; } }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormula.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormula.cs index 7663192..bbc9819 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormula.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormula.cs
@@ -13,126 +13,107 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml; using OfficeOpenXml.Utils; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Formulas -{ - /// <summary> - /// Enumeration representing the state of an <see cref="ExcelDataValidationFormulaValue{T}"/> - /// </summary> - internal enum FormulaState - { - /// <summary> - /// Value is set - /// </summary> - Value, - /// <summary> - /// Formula is set - /// </summary> - Formula +namespace OfficeOpenXml.DataValidation.Formulas; + +/// <summary> +/// Enumeration representing the state of an <see cref="ExcelDataValidationFormulaValue{T}"/> +/// </summary> +internal enum FormulaState { + /// <summary> + /// Value is set + /// </summary> + Value, + + /// <summary> + /// Formula is set + /// </summary> + Formula, +} + +/// <summary> +/// Base class for a formula +/// </summary> +internal abstract class ExcelDataValidationFormula : XmlHelper { + /// <summary> + /// Constructor + /// </summary> + /// <param name="namespaceManager">Namespacemanger of the worksheet</param> + /// <param name="topNode">validation top node</param> + /// <param name="formulaPath">xml path of the current formula</param> + public ExcelDataValidationFormula( + XmlNamespaceManager namespaceManager, + XmlNode topNode, + string formulaPath) + : base(namespaceManager, topNode) { + Require.Argument(formulaPath).IsNotNullOrEmpty("formulaPath"); + FormulaPath = formulaPath; + } + + private string _formula; + + protected string FormulaPath { get; private set; } + + /// <summary> + /// State of the validationformula, i.e. tells if value or formula is set + /// </summary> + protected FormulaState State { get; set; } + + /// <summary> + /// A formula which output must match the current validation type + /// </summary> + public string ExcelFormula { + get => _formula; + set { + if (!string.IsNullOrEmpty(value)) { + ResetValue(); + State = FormulaState.Formula; + } + if (value != null && value.Length > 255) { + throw new InvalidOperationException( + "The length of a DataValidation formula cannot exceed 255 characters"); + } + //var val = SqRefUtility.ToSqRefAddress(value); + _formula = value; + SetXmlNodeString(FormulaPath, value); } + } - /// <summary> - /// Base class for a formula - /// </summary> - internal abstract class ExcelDataValidationFormula : XmlHelper - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="namespaceManager">Namespacemanger of the worksheet</param> - /// <param name="topNode">validation top node</param> - /// <param name="formulaPath">xml path of the current formula</param> - public ExcelDataValidationFormula(XmlNamespaceManager namespaceManager, XmlNode topNode, string formulaPath) - : base(namespaceManager, topNode) - { - Require.Argument(formulaPath).IsNotNullOrEmpty("formulaPath"); - FormulaPath = formulaPath; - } + internal abstract void ResetValue(); - private string _formula; - - protected string FormulaPath - { - get; - private set; - } - - /// <summary> - /// State of the validationformula, i.e. tells if value or formula is set - /// </summary> - protected FormulaState State - { - get; - set; - } - - /// <summary> - /// A formula which output must match the current validation type - /// </summary> - public string ExcelFormula - { - get - { - return _formula; - } - set - { - if (!string.IsNullOrEmpty(value)) - { - ResetValue(); - State = FormulaState.Formula; - } - if (value != null && value.Length > 255) - { - throw new InvalidOperationException("The length of a DataValidation formula cannot exceed 255 characters"); - } - //var val = SqRefUtility.ToSqRefAddress(value); - _formula = value; - SetXmlNodeString(FormulaPath, value); - } - } - - internal abstract void ResetValue(); - - /// <summary> - /// This value will be stored in the xml. Can be overridden by subclasses - /// </summary> - internal virtual string GetXmlValue() - { - if (State == FormulaState.Formula) - { - return ExcelFormula; - } - return GetValueAsString(); - } - - /// <summary> - /// Returns the value as a string. Must be implemented by subclasses - /// </summary> - /// <returns></returns> - protected abstract string GetValueAsString(); + /// <summary> + /// This value will be stored in the xml. Can be overridden by subclasses + /// </summary> + internal virtual string GetXmlValue() { + if (State == FormulaState.Formula) { + return ExcelFormula; } + return GetValueAsString(); + } + + /// <summary> + /// Returns the value as a string. Must be implemented by subclasses + /// </summary> + /// <returns></returns> + protected abstract string GetValueAsString(); }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs index 2975c8d..1072535 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaCustom.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,60 +13,55 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; + using System.Xml; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Formulas -{ - /// <summary> - /// - /// </summary> - internal class ExcelDataValidationFormulaCustom : ExcelDataValidationFormula, IExcelDataValidationFormula - { - public ExcelDataValidationFormulaCustom(XmlNamespaceManager namespaceManager, XmlNode topNode, string formulaPath) - : base(namespaceManager, topNode, formulaPath) - { - var value = GetXmlNodeString(formulaPath); - if (!string.IsNullOrEmpty(value)) - { - ExcelFormula = value; - } - State = FormulaState.Formula; - } +namespace OfficeOpenXml.DataValidation.Formulas; - internal override string GetXmlValue() - { - return ExcelFormula; - } - - protected override string GetValueAsString() - { - return ExcelFormula; - } - - internal override void ResetValue() - { - ExcelFormula = null; - } +/// <summary> +/// +/// </summary> +internal class ExcelDataValidationFormulaCustom + : ExcelDataValidationFormula, + IExcelDataValidationFormula { + public ExcelDataValidationFormulaCustom( + XmlNamespaceManager namespaceManager, + XmlNode topNode, + string formulaPath) + : base(namespaceManager, topNode, formulaPath) { + var value = GetXmlNodeString(formulaPath); + if (!string.IsNullOrEmpty(value)) { + ExcelFormula = value; } + State = FormulaState.Formula; + } + + internal override string GetXmlValue() { + return ExcelFormula; + } + + protected override string GetValueAsString() { + return ExcelFormula; + } + + internal override void ResetValue() { + ExcelFormula = null; + } }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs index 6381be8..5543046 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDateTime.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,56 +13,52 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Globalization; using System.Xml; using OfficeOpenXml.DataValidation.Formulas.Contracts; -using System.Globalization; -namespace OfficeOpenXml.DataValidation.Formulas -{ - internal class ExcelDataValidationFormulaDateTime : ExcelDataValidationFormulaValue<DateTime?>, IExcelDataValidationFormulaDateTime - { - public ExcelDataValidationFormulaDateTime(XmlNamespaceManager namespaceManager, XmlNode topNode, string formulaPath) - : base(namespaceManager, topNode, formulaPath) - { - var value = GetXmlNodeString(formulaPath); - if (!string.IsNullOrEmpty(value)) - { - double oADate = default(double); - if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out oADate)) - { - Value = DateTime.FromOADate(oADate); - } - else - { - ExcelFormula = value; - } - } - } +namespace OfficeOpenXml.DataValidation.Formulas; - protected override string GetValueAsString() - { - return Value.HasValue ? Value.Value.ToOADate().ToString(CultureInfo.InvariantCulture) : string.Empty; - } - +internal class ExcelDataValidationFormulaDateTime + : ExcelDataValidationFormulaValue<DateTime?>, + IExcelDataValidationFormulaDateTime { + public ExcelDataValidationFormulaDateTime( + XmlNamespaceManager namespaceManager, + XmlNode topNode, + string formulaPath) + : base(namespaceManager, topNode, formulaPath) { + var value = GetXmlNodeString(formulaPath); + if (!string.IsNullOrEmpty(value)) { + double oADate = default(double); + if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out oADate)) { + Value = DateTime.FromOADate(oADate); + } else { + ExcelFormula = value; + } } + } + + protected override string GetValueAsString() { + return Value.HasValue + ? Value.Value.ToOADate().ToString(CultureInfo.InvariantCulture) + : string.Empty; + } }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs index dda4d92..67b921d 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaDecimal.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,58 +13,54 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + +using System.Globalization; using System.Xml; using OfficeOpenXml.DataValidation.Formulas.Contracts; -using System.Globalization; -namespace OfficeOpenXml.DataValidation.Formulas -{ - /// <summary> - /// - /// </summary> - internal class ExcelDataValidationFormulaDecimal : ExcelDataValidationFormulaValue<double?>, IExcelDataValidationFormulaDecimal - { - public ExcelDataValidationFormulaDecimal(XmlNamespaceManager namespaceManager, XmlNode topNode, string formulaPath) - : base(namespaceManager, topNode, formulaPath) - { - var value = GetXmlNodeString(formulaPath); - if (!string.IsNullOrEmpty(value)) - { - double dValue = default(double); - if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out dValue)) - { - Value = dValue; - } - else - { - ExcelFormula = value; - } - } - } +namespace OfficeOpenXml.DataValidation.Formulas; - protected override string GetValueAsString() - { - return Value.HasValue ? Value.Value.ToString("R15", CultureInfo.InvariantCulture) : string.Empty; - } +/// <summary> +/// +/// </summary> +internal class ExcelDataValidationFormulaDecimal + : ExcelDataValidationFormulaValue<double?>, + IExcelDataValidationFormulaDecimal { + public ExcelDataValidationFormulaDecimal( + XmlNamespaceManager namespaceManager, + XmlNode topNode, + string formulaPath) + : base(namespaceManager, topNode, formulaPath) { + var value = GetXmlNodeString(formulaPath); + if (!string.IsNullOrEmpty(value)) { + double dValue = default(double); + if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out dValue)) { + Value = dValue; + } else { + ExcelFormula = value; + } } + } + + protected override string GetValueAsString() { + return Value.HasValue + ? Value.Value.ToString("R15", CultureInfo.InvariantCulture) + : string.Empty; + } }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs index c898a39..70dc8cc 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaInt.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,55 +13,48 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using System.Xml; using OfficeOpenXml.DataValidation.Formulas.Contracts; -using System.Globalization; -namespace OfficeOpenXml.DataValidation.Formulas -{ - internal class ExcelDataValidationFormulaInt : ExcelDataValidationFormulaValue<int?>, IExcelDataValidationFormulaInt - { - public ExcelDataValidationFormulaInt(XmlNamespaceManager namespaceManager, XmlNode topNode, string formulaPath) - : base(namespaceManager, topNode, formulaPath) - { - var value = GetXmlNodeString(formulaPath); - if (!string.IsNullOrEmpty(value)) - { - int intValue = default(int); - if (int.TryParse(value, out intValue)) - { - Value = intValue; - } - else - { - ExcelFormula = value; - } - } - } +namespace OfficeOpenXml.DataValidation.Formulas; - protected override string GetValueAsString() - { - return Value.HasValue ? Value.Value.ToString() : string.Empty; - } +internal class ExcelDataValidationFormulaInt + : ExcelDataValidationFormulaValue<int?>, + IExcelDataValidationFormulaInt { + public ExcelDataValidationFormulaInt( + XmlNamespaceManager namespaceManager, + XmlNode topNode, + string formulaPath) + : base(namespaceManager, topNode, formulaPath) { + var value = GetXmlNodeString(formulaPath); + if (!string.IsNullOrEmpty(value)) { + int intValue = default(int); + if (int.TryParse(value, out intValue)) { + Value = intValue; + } else { + ExcelFormula = value; + } } + } + + protected override string GetValueAsString() { + return Value.HasValue ? Value.Value.ToString() : string.Empty; + } }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs index 53527fa..bfe5301 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaList.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,235 +13,180 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; using System.Text; using System.Xml; -using OfficeOpenXml.Utils; using OfficeOpenXml.DataValidation.Formulas.Contracts; -using System.Text.RegularExpressions; -using System.Collections; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.DataValidation.Formulas -{ - internal class ExcelDataValidationFormulaList : ExcelDataValidationFormula, IExcelDataValidationFormulaList - { - #region class DataValidationList - private class DataValidationList : IList<string>, ICollection - { - private IList<string> _items = new List<string>(); - private EventHandler<EventArgs> _listChanged; +namespace OfficeOpenXml.DataValidation.Formulas; - public event EventHandler<EventArgs> ListChanged - { - add { _listChanged += value; } - remove { _listChanged -= value; } - } +internal class ExcelDataValidationFormulaList + : ExcelDataValidationFormula, + IExcelDataValidationFormulaList { + private class DataValidationList : IList<string>, ICollection { + private IList<string> _items = new List<string>(); + private EventHandler<EventArgs> _listChanged; - private void OnListChanged() - { - if (_listChanged != null) - { - _listChanged(this, EventArgs.Empty); - } - } - - #region IList members - int IList<string>.IndexOf(string item) - { - return _items.IndexOf(item); - } - - void IList<string>.Insert(int index, string item) - { - _items.Insert(index, item); - OnListChanged(); - } - - void IList<string>.RemoveAt(int index) - { - _items.RemoveAt(index); - OnListChanged(); - } - - string IList<string>.this[int index] - { - get - { - return _items[index]; - } - set - { - _items[index] = value; - OnListChanged(); - } - } - - void ICollection<string>.Add(string item) - { - _items.Add(item); - OnListChanged(); - } - - void ICollection<string>.Clear() - { - _items.Clear(); - OnListChanged(); - } - - bool ICollection<string>.Contains(string item) - { - return _items.Contains(item); - } - - void ICollection<string>.CopyTo(string[] array, int arrayIndex) - { - _items.CopyTo(array, arrayIndex); - } - - int ICollection<string>.Count - { - get { return _items.Count; } - } - - bool ICollection<string>.IsReadOnly - { - get { return false; } - } - - bool ICollection<string>.Remove(string item) - { - var retVal = _items.Remove(item); - OnListChanged(); - return retVal; - } - - IEnumerator<string> IEnumerable<string>.GetEnumerator() - { - return _items.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _items.GetEnumerator(); - } - #endregion - - public void CopyTo(Array array, int index) - { - _items.CopyTo((string[])array, index); - } - - int ICollection.Count - { - get { return _items.Count; } - } - - public bool IsSynchronized - { - get { return ((ICollection)_items).IsSynchronized; } - } - - public object SyncRoot - { - get { return ((ICollection)_items).SyncRoot; } - } - } - #endregion - - public ExcelDataValidationFormulaList(XmlNamespaceManager namespaceManager, XmlNode itemNode, string formulaPath) - : base(namespaceManager, itemNode, formulaPath) - { - Require.Argument(formulaPath).IsNotNullOrEmpty("formulaPath"); - _formulaPath = formulaPath; - var values = new DataValidationList(); - values.ListChanged += new EventHandler<EventArgs>(values_ListChanged); - Values = values; - SetInitialValues(); - } - - private string _formulaPath; - - private void SetInitialValues() - { - var @value = GetXmlNodeString(_formulaPath); - if (!string.IsNullOrEmpty(@value)) - { - if (@value.StartsWith("\"") && @value.EndsWith("\"")) - { - @value = @value.TrimStart('"').TrimEnd('"'); - var items = @value.Split(new char[]{','}, StringSplitOptions.RemoveEmptyEntries); - foreach (var item in items) - { - Values.Add(item); - } - } - else - { - ExcelFormula = @value; - } - } - } - - void values_ListChanged(object sender, EventArgs e) - { - if (Values.Count > 0) - { - State = FormulaState.Value; - } - var valuesAsString = GetValueAsString(); - // Excel supports max 255 characters in this field. - if (valuesAsString.Length > 255) - { - throw new InvalidOperationException("The total length of a DataValidation list cannot exceed 255 characters"); - } - SetXmlNodeString(_formulaPath, valuesAsString); - } - public IList<string> Values - { - get; - private set; - } - - protected override string GetValueAsString() - { - var sb = new StringBuilder(); - foreach (var val in Values) - { - if (sb.Length == 0) - { - sb.Append("\""); - sb.Append(val); - } - else - { - sb.AppendFormat(",{0}", val); - } - } - sb.Append("\""); - return sb.ToString(); - } - - internal override void ResetValue() - { - Values.Clear(); - } + public event EventHandler<EventArgs> ListChanged { + add => _listChanged += value; + remove => _listChanged -= value; } + + private void OnListChanged() { + if (_listChanged != null) { + _listChanged(this, EventArgs.Empty); + } + } + + int IList<string>.IndexOf(string item) { + return _items.IndexOf(item); + } + + void IList<string>.Insert(int index, string item) { + _items.Insert(index, item); + OnListChanged(); + } + + void IList<string>.RemoveAt(int index) { + _items.RemoveAt(index); + OnListChanged(); + } + + string IList<string>.this[int index] { + get => _items[index]; + set { + _items[index] = value; + OnListChanged(); + } + } + + void ICollection<string>.Add(string item) { + _items.Add(item); + OnListChanged(); + } + + void ICollection<string>.Clear() { + _items.Clear(); + OnListChanged(); + } + + bool ICollection<string>.Contains(string item) { + return _items.Contains(item); + } + + void ICollection<string>.CopyTo(string[] array, int arrayIndex) { + _items.CopyTo(array, arrayIndex); + } + + int ICollection<string>.Count => _items.Count; + + bool ICollection<string>.IsReadOnly => false; + + bool ICollection<string>.Remove(string item) { + var retVal = _items.Remove(item); + OnListChanged(); + return retVal; + } + + IEnumerator<string> IEnumerable<string>.GetEnumerator() { + return _items.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _items.GetEnumerator(); + } + + public void CopyTo(Array array, int index) { + _items.CopyTo((string[])array, index); + } + + int ICollection.Count => _items.Count; + + public bool IsSynchronized => ((ICollection)_items).IsSynchronized; + + public object SyncRoot => ((ICollection)_items).SyncRoot; + } + + public ExcelDataValidationFormulaList( + XmlNamespaceManager namespaceManager, + XmlNode itemNode, + string formulaPath) + : base(namespaceManager, itemNode, formulaPath) { + Require.Argument(formulaPath).IsNotNullOrEmpty("formulaPath"); + _formulaPath = formulaPath; + var values = new DataValidationList(); + values.ListChanged += values_ListChanged; + Values = values; + SetInitialValues(); + } + + private string _formulaPath; + + private void SetInitialValues() { + var value = GetXmlNodeString(_formulaPath); + if (!string.IsNullOrEmpty(value)) { + if (value.StartsWith("\"") && value.EndsWith("\"")) { + value = value.TrimStart('"').TrimEnd('"'); + var items = value.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var item in items) { + Values.Add(item); + } + } else { + ExcelFormula = value; + } + } + } + + private void values_ListChanged(object sender, EventArgs e) { + if (Values.Count > 0) { + State = FormulaState.Value; + } + var valuesAsString = GetValueAsString(); + // Excel supports max 255 characters in this field. + if (valuesAsString.Length > 255) { + throw new InvalidOperationException( + "The total length of a DataValidation list cannot exceed 255 characters"); + } + SetXmlNodeString(_formulaPath, valuesAsString); + } + + public IList<string> Values { get; private set; } + + protected override string GetValueAsString() { + var sb = new StringBuilder(); + foreach (var val in Values) { + if (sb.Length == 0) { + sb.Append("\""); + sb.Append(val); + } else { + sb.AppendFormat(",{0}", val); + } + } + sb.Append("\""); + return sb.ToString(); + } + + internal override void ResetValue() { + Values.Clear(); + } }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs index 1ee1972..38a8176 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaTime.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,76 +13,65 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.DataValidation.Formulas.Contracts; -using OfficeOpenXml.DataValidation; -using System.Xml; using System.Globalization; +using System.Xml; +using OfficeOpenXml.DataValidation.Formulas.Contracts; -namespace OfficeOpenXml.DataValidation.Formulas -{ - internal class ExcelDataValidationFormulaTime : ExcelDataValidationFormulaValue<ExcelTime>, IExcelDataValidationFormulaTime - { - public ExcelDataValidationFormulaTime(XmlNamespaceManager namespaceManager, XmlNode topNode, string formulaPath) - : base(namespaceManager, topNode, formulaPath) - { - var value = GetXmlNodeString(formulaPath); - if (!string.IsNullOrEmpty(value)) - { - decimal time = default(decimal); - if (decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out time)) - { - Value = new ExcelTime(time); - } - else - { - Value = new ExcelTime(); - ExcelFormula = value; - } - } - else - { - Value = new ExcelTime(); - } - Value.TimeChanged += new EventHandler(Value_TimeChanged); - } +namespace OfficeOpenXml.DataValidation.Formulas; - void Value_TimeChanged(object sender, EventArgs e) - { - SetXmlNodeString(FormulaPath, Value.ToExcelString()); - } - - protected override string GetValueAsString() - { - if (State == FormulaState.Value) - { - return Value.ToExcelString(); - } - return string.Empty; - } - - internal override void ResetValue() - { - Value = new ExcelTime(); - } +internal class ExcelDataValidationFormulaTime + : ExcelDataValidationFormulaValue<ExcelTime>, + IExcelDataValidationFormulaTime { + public ExcelDataValidationFormulaTime( + XmlNamespaceManager namespaceManager, + XmlNode topNode, + string formulaPath) + : base(namespaceManager, topNode, formulaPath) { + var value = GetXmlNodeString(formulaPath); + if (!string.IsNullOrEmpty(value)) { + decimal time = default(decimal); + if (decimal.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out time)) { + Value = new(time); + } else { + Value = new(); + ExcelFormula = value; + } + } else { + Value = new(); } + Value.TimeChanged += Value_TimeChanged; + } + + private void Value_TimeChanged(object sender, EventArgs e) { + SetXmlNodeString(FormulaPath, Value.ToExcelString()); + } + + protected override string GetValueAsString() { + if (State == FormulaState.Value) { + return Value.ToExcelString(); + } + return string.Empty; + } + + internal override void ResetValue() { + Value = new(); + } }
diff --git a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs index 66a7f99..8490c7a 100644 --- a/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs +++ b/EPPlus/DataValidation/Formulas/ExcelDataValidationFormulaValue.cs
@@ -13,72 +13,59 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-08 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.Utils; + using System.Xml; -namespace OfficeOpenXml.DataValidation.Formulas -{ +namespace OfficeOpenXml.DataValidation.Formulas; - /// <summary> - /// This class represents a validation formula. Its value can be specified as a value of the specified datatype or as a formula. - /// </summary> - /// <typeparam name="T"></typeparam> - internal abstract class ExcelDataValidationFormulaValue<T> : ExcelDataValidationFormula - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="namespaceManager">Namespacemanger of the worksheet</param> - /// <param name="topNode">validation top node</param> - /// <param name="formulaPath">xml path of the current formula</param> - public ExcelDataValidationFormulaValue(XmlNamespaceManager namespaceManager, XmlNode topNode, string formulaPath) - : base(namespaceManager, topNode, formulaPath) - { +/// <summary> +/// This class represents a validation formula. Its value can be specified as a value of the specified datatype or as a formula. +/// </summary> +/// <typeparam name="T"></typeparam> +internal abstract class ExcelDataValidationFormulaValue<T> : ExcelDataValidationFormula { + /// <summary> + /// Constructor + /// </summary> + /// <param name="namespaceManager">Namespacemanger of the worksheet</param> + /// <param name="topNode">validation top node</param> + /// <param name="formulaPath">xml path of the current formula</param> + public ExcelDataValidationFormulaValue( + XmlNamespaceManager namespaceManager, + XmlNode topNode, + string formulaPath) + : base(namespaceManager, topNode, formulaPath) {} - } + private T _value; - private T _value; - /// <summary> - /// Typed value - /// </summary> - public T Value - { - get - { - return _value; - } - set - { - State = FormulaState.Value; - _value = value; - SetXmlNodeString(FormulaPath, GetValueAsString()); - } - } - - internal override void ResetValue() - { - Value = default(T); - } - + /// <summary> + /// Typed value + /// </summary> + public T Value { + get => _value; + set { + State = FormulaState.Value; + _value = value; + SetXmlNodeString(FormulaPath, GetValueAsString()); } + } + + internal override void ResetValue() { + Value = default(T); + } }
diff --git a/EPPlus/DataValidation/IRangeDataValidation.cs b/EPPlus/DataValidation/IRangeDataValidation.cs index f7cb3ba..0002560 100644 --- a/EPPlus/DataValidation/IRangeDataValidation.cs +++ b/EPPlus/DataValidation/IRangeDataValidation.cs
@@ -13,73 +13,77 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-03-23 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System.Linq; -using System.Text; + using OfficeOpenXml.DataValidation.Contracts; -namespace OfficeOpenXml.DataValidation -{ - /// <summary> - /// Provides functionality for adding datavalidation to a range (<see cref="ExcelRangeBase"/>). Each method will - /// return a configurable validation. - /// </summary> - public interface IRangeDataValidation - { - /// <summary> - /// Adds a <see cref="IExcelDataValidationAny"/> to the range. - /// </summary> - /// <returns>A <see cref="ExcelDataValidationAny"/> that can be configured for any validation</returns> - IExcelDataValidationAny AddAnyDataValidation(); - /// <summary> - /// Adds a <see cref="IExcelDataValidationInt"/> to the range - /// </summary> - /// <returns>A <see cref="ExcelDataValidationInt"/> that can be configured for integer data validation</returns> - IExcelDataValidationInt AddIntegerDataValidation(); - /// <summary> - /// Adds a <see cref="ExcelDataValidationDecimal"/> to the range - /// </summary> - /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for decimal data validation</returns> - IExcelDataValidationDecimal AddDecimalDataValidation(); - /// <summary> - /// Adds a <see cref="ExcelDataValidationDateTime"/> to the range - /// </summary> - /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for datetime data validation</returns> - IExcelDataValidationDateTime AddDateTimeDataValidation(); - /// <summary> - /// Adds a <see cref="IExcelDataValidationList"/> to the range - /// </summary> - /// <returns>A <see cref="ExcelDataValidationList"/> that can be configured for datetime data validation</returns> - IExcelDataValidationList AddListDataValidation(); - /// <summary> - /// Adds a <see cref="IExcelDataValidationInt"/> regarding text length validation to the range. - /// </summary> - /// <returns></returns> - IExcelDataValidationInt AddTextLengthDataValidation(); - /// <summary> - /// Adds a <see cref="IExcelDataValidationTime"/> to the range. - /// </summary> - /// <returns>A <see cref="IExcelDataValidationTime"/> that can be configured for time data validation</returns> - IExcelDataValidationTime AddTimeDataValidation(); - /// <summary> - /// Adds a <see cref="IExcelDataValidationCustom"/> to the range. - /// </summary> - /// <returns>A <see cref="IExcelDataValidationCustom"/> that can be configured for custom validation</returns> - IExcelDataValidationCustom AddCustomDataValidation(); - } +namespace OfficeOpenXml.DataValidation; + +/// <summary> +/// Provides functionality for adding datavalidation to a range (<see cref="ExcelRangeBase"/>). Each method will +/// return a configurable validation. +/// </summary> +public interface IRangeDataValidation { + /// <summary> + /// Adds a <see cref="IExcelDataValidationAny"/> to the range. + /// </summary> + /// <returns>A <see cref="ExcelDataValidationAny"/> that can be configured for any validation</returns> + IExcelDataValidationAny AddAnyDataValidation(); + + /// <summary> + /// Adds a <see cref="IExcelDataValidationInt"/> to the range + /// </summary> + /// <returns>A <see cref="ExcelDataValidationInt"/> that can be configured for integer data validation</returns> + IExcelDataValidationInt AddIntegerDataValidation(); + + /// <summary> + /// Adds a <see cref="ExcelDataValidationDecimal"/> to the range + /// </summary> + /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for decimal data validation</returns> + IExcelDataValidationDecimal AddDecimalDataValidation(); + + /// <summary> + /// Adds a <see cref="ExcelDataValidationDateTime"/> to the range + /// </summary> + /// <returns>A <see cref="ExcelDataValidationDecimal"/> that can be configured for datetime data validation</returns> + IExcelDataValidationDateTime AddDateTimeDataValidation(); + + /// <summary> + /// Adds a <see cref="IExcelDataValidationList"/> to the range + /// </summary> + /// <returns>A <see cref="ExcelDataValidationList"/> that can be configured for datetime data validation</returns> + IExcelDataValidationList AddListDataValidation(); + + /// <summary> + /// Adds a <see cref="IExcelDataValidationInt"/> regarding text length validation to the range. + /// </summary> + /// <returns></returns> + IExcelDataValidationInt AddTextLengthDataValidation(); + + /// <summary> + /// Adds a <see cref="IExcelDataValidationTime"/> to the range. + /// </summary> + /// <returns>A <see cref="IExcelDataValidationTime"/> that can be configured for time data validation</returns> + IExcelDataValidationTime AddTimeDataValidation(); + + /// <summary> + /// Adds a <see cref="IExcelDataValidationCustom"/> to the range. + /// </summary> + /// <returns>A <see cref="IExcelDataValidationCustom"/> that can be configured for custom validation</returns> + IExcelDataValidationCustom AddCustomDataValidation(); }
diff --git a/EPPlus/DataValidation/RangeDataValidation.cs b/EPPlus/DataValidation/RangeDataValidation.cs index 90c517b..82bf95d 100644 --- a/EPPlus/DataValidation/RangeDataValidation.cs +++ b/EPPlus/DataValidation/RangeDataValidation.cs
@@ -13,82 +13,68 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-03-23 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.Utils; + using OfficeOpenXml.DataValidation.Contracts; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.DataValidation -{ - internal class RangeDataValidation : IRangeDataValidation - { - public RangeDataValidation(ExcelWorksheet worksheet, string address) - { - Require.Argument(worksheet).IsNotNull("worksheet"); - Require.Argument(address).IsNotNullOrEmpty("address"); - _worksheet = worksheet; - _address = address; - } +namespace OfficeOpenXml.DataValidation; - ExcelWorksheet _worksheet; - string _address; +internal class RangeDataValidation : IRangeDataValidation { + public RangeDataValidation(ExcelWorksheet worksheet, string address) { + Require.Argument(worksheet).IsNotNull("worksheet"); + Require.Argument(address).IsNotNullOrEmpty("address"); + _worksheet = worksheet; + _address = address; + } - public IExcelDataValidationAny AddAnyDataValidation() - { - return _worksheet.DataValidations.AddAnyValidation(_address); - } + private ExcelWorksheet _worksheet; + private string _address; - public IExcelDataValidationInt AddIntegerDataValidation() - { - return _worksheet.DataValidations.AddIntegerValidation(_address); - } + public IExcelDataValidationAny AddAnyDataValidation() { + return _worksheet.DataValidations.AddAnyValidation(_address); + } - public IExcelDataValidationDecimal AddDecimalDataValidation() - { - return _worksheet.DataValidations.AddDecimalValidation(_address); - } + public IExcelDataValidationInt AddIntegerDataValidation() { + return _worksheet.DataValidations.AddIntegerValidation(_address); + } - public IExcelDataValidationDateTime AddDateTimeDataValidation() - { - return _worksheet.DataValidations.AddDateTimeValidation(_address); - } + public IExcelDataValidationDecimal AddDecimalDataValidation() { + return _worksheet.DataValidations.AddDecimalValidation(_address); + } - public IExcelDataValidationList AddListDataValidation() - { - return _worksheet.DataValidations.AddListValidation(_address); - } + public IExcelDataValidationDateTime AddDateTimeDataValidation() { + return _worksheet.DataValidations.AddDateTimeValidation(_address); + } - public IExcelDataValidationInt AddTextLengthDataValidation() - { - return _worksheet.DataValidations.AddTextLengthValidation(_address); - } + public IExcelDataValidationList AddListDataValidation() { + return _worksheet.DataValidations.AddListValidation(_address); + } - public IExcelDataValidationTime AddTimeDataValidation() - { - return _worksheet.DataValidations.AddTimeValidation(_address); - } + public IExcelDataValidationInt AddTextLengthDataValidation() { + return _worksheet.DataValidations.AddTextLengthValidation(_address); + } - public IExcelDataValidationCustom AddCustomDataValidation() - { - return _worksheet.DataValidations.AddCustomValidation(_address); - } - } + public IExcelDataValidationTime AddTimeDataValidation() { + return _worksheet.DataValidations.AddTimeValidation(_address); + } + + public IExcelDataValidationCustom AddCustomDataValidation() { + return _worksheet.DataValidations.AddCustomValidation(_address); + } }
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs index cef41dc..df934c8 100644 --- a/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs +++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingBase.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2010-06-01 @@ -32,131 +32,121 @@ using System.Xml; -namespace OfficeOpenXml.Drawing.Vml -{ - /// <summary> - /// Horizontal Alingment - /// </summary> - public enum eTextAlignHorizontalVml - { - Left, - Center, - Right - } - /// <summary> - /// Vertical Alingment - /// </summary> - public enum eTextAlignVerticalVml - { - Top, - Center, - Bottom - } - /// <summary> - /// Linestyle - /// </summary> - public enum eLineStyleVml - { - Solid, - Round, - Square, - Dash, - DashDot, - LongDash, - LongDashDot, - LongDashDotDot - } - /// <summary> - /// Drawing object used for comments - /// </summary> - public class ExcelVmlDrawingBase : XmlHelper - { - internal ExcelVmlDrawingBase(XmlNode topNode, XmlNamespaceManager ns) : - base(ns, topNode) - { - SchemaNodeOrder = new string[] { "fill", "stroke", "shadow", "path", "textbox", "ClientData", "MoveWithCells", "SizeWithCells", "Anchor", "Locked", "AutoFill", "LockText", "TextHAlign", "TextVAlign", "Row", "Column", "Visible" }; - } - public string Id - { - get - { - return GetXmlNodeString("@id"); - } - set - { - SetXmlNodeString("@id",value); - } +namespace OfficeOpenXml.Drawing.Vml; + +/// <summary> +/// Horizontal Alingment +/// </summary> +public enum eTextAlignHorizontalVml { + Left, + Center, + Right, +} + +/// <summary> +/// Vertical Alingment +/// </summary> +public enum eTextAlignVerticalVml { + Top, + Center, + Bottom, +} + +/// <summary> +/// Linestyle +/// </summary> +public enum eLineStyleVml { + Solid, + Round, + Square, + Dash, + DashDot, + LongDash, + LongDashDot, + LongDashDotDot, +} + +/// <summary> +/// Drawing object used for comments +/// </summary> +public class ExcelVmlDrawingBase : XmlHelper { + internal ExcelVmlDrawingBase(XmlNode topNode, XmlNamespaceManager ns) + : base(ns, topNode) { + SchemaNodeOrder = new[] { + "fill", + "stroke", + "shadow", + "path", + "textbox", + "ClientData", + "MoveWithCells", + "SizeWithCells", + "Anchor", + "Locked", + "AutoFill", + "LockText", + "TextHAlign", + "TextVAlign", + "Row", + "Column", + "Visible", + }; + } + + public string Id { + get => GetXmlNodeString("@id"); + set => SetXmlNodeString("@id", value); + } + + /// <summary> + /// Alternative text to be displayed instead of a graphic. + /// </summary> + public string AlternativeText { + get => GetXmlNodeString("@alt"); + set => SetXmlNodeString("@alt", value); + } + + protected bool GetStyle(string style, string key, out string value) { + string[] styles = style.Split(';'); + foreach (string s in styles) { + if (s.IndexOf(':') > 0) { + string[] split = s.Split(':'); + if (split[0] == key) { + value = split[1]; + return true; } - /// <summary> - /// Alternative text to be displayed instead of a graphic. - /// </summary> - public string AlternativeText - { - get - { - return GetXmlNodeString("@alt"); - } - set - { - SetXmlNodeString("@alt", value); - } - } - #region "Style Handling methods" - protected bool GetStyle(string style, string key, out string value) - { - string[]styles = style.Split(';'); - foreach(string s in styles) - { - if (s.IndexOf(':') > 0) - { - string[] split = s.Split(':'); - if (split[0] == key) - { - value=split[1]; - return true; - } - } - else if (s == key) - { - value=""; - return true; - } - } - value=""; - return false; - } - protected string SetStyle(string style, string key, string value) - { - string[] styles = style.Split(';'); - string newStyle=""; - bool changed = false; - foreach (string s in styles) - { - string[] split = s.Split(':'); - if (split[0].Trim() == key) - { - if (value.Trim() != "") //If blank remove the item - { - newStyle += key + ':' + value; - } - changed = true; - } - else - { - newStyle += s; - } - newStyle += ';'; - } - if (!changed) - { - newStyle += key + ':' + value; - } - else - { - newStyle = style.Substring(0, style.Length - 1); - } - return newStyle; - } - #endregion + } else if (s == key) { + value = ""; + return true; + } } + value = ""; + return false; + } + + protected string SetStyle(string style, string key, string value) { + string[] styles = style.Split(';'); + string newStyle = ""; + bool changed = false; + foreach (string s in styles) { + string[] split = s.Split(':'); + if (split[0].Trim() == key) { + if (value.Trim() + != "") //If blank remove the item + { + newStyle += key + ':' + value; + } + changed = true; + } else { + newStyle += s; + } + newStyle += ';'; + } + if (!changed) { + newStyle += key + ':' + value; + } else { + newStyle = style.Substring(0, style.Length - 1); + } + return newStyle; + } }
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs index 5fa0e82..912214e 100644 --- a/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs +++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingBaseCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,54 +13,51 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2010-06-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; using System.Xml; +using OfficeOpenXml.Packaging; -namespace OfficeOpenXml.Drawing.Vml -{ - public class ExcelVmlDrawingBaseCollection - { - internal ExcelVmlDrawingBaseCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri) - { - VmlDrawingXml = new XmlDocument(); - VmlDrawingXml.PreserveWhitespace = false; - - NameTable nt=new NameTable(); - NameSpaceManager = new XmlNamespaceManager(nt); - NameSpaceManager.AddNamespace("v", ExcelPackage.schemaMicrosoftVml); - NameSpaceManager.AddNamespace("o", ExcelPackage.schemaMicrosoftOffice); - NameSpaceManager.AddNamespace("x", ExcelPackage.schemaMicrosoftExcel); - Uri = uri; - if (uri == null) - { - Part = null; - } - else - { - Part=pck.Package.GetPart(uri); - XmlHelper.LoadXmlSafe(VmlDrawingXml, Part.GetStream()); - } - } - internal XmlDocument VmlDrawingXml { get; set; } - internal Uri Uri { get; set; } - internal string RelId { get; set; } - internal Packaging.ZipPackagePart Part { get; set; } - internal XmlNamespaceManager NameSpaceManager { get; set; } +namespace OfficeOpenXml.Drawing.Vml; + +public class ExcelVmlDrawingBaseCollection { + internal ExcelVmlDrawingBaseCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri) { + VmlDrawingXml = new(); + VmlDrawingXml.PreserveWhitespace = false; + + NameTable nt = new NameTable(); + NameSpaceManager = new(nt); + NameSpaceManager.AddNamespace("v", ExcelPackage._schemaMicrosoftVml); + NameSpaceManager.AddNamespace("o", ExcelPackage._schemaMicrosoftOffice); + NameSpaceManager.AddNamespace("x", ExcelPackage._schemaMicrosoftExcel); + Uri = uri; + if (uri == null) { + Part = null; + } else { + Part = pck.Package.GetPart(uri); + XmlHelper.LoadXmlSafe(VmlDrawingXml, Part.GetStream()); } + } + + internal XmlDocument VmlDrawingXml { get; set; } + internal Uri Uri { get; set; } + internal string RelId { get; set; } + internal ZipPackagePart Part { get; set; } + internal XmlNamespaceManager NameSpaceManager { get; set; } }
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs index 270eb24..560529e 100644 --- a/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs +++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingComment.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,446 +13,402 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2010-06-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Xml; -using System.Globalization; using System.Drawing; +using System.Globalization; +using System.Xml; -namespace OfficeOpenXml.Drawing.Vml -{ - /// <summary> - /// Drawing object used for comments - /// </summary> - public class ExcelVmlDrawingComment : ExcelVmlDrawingBase, IRangeID - { - internal ExcelVmlDrawingComment(XmlNode topNode, ExcelRangeBase range, XmlNamespaceManager ns) : - base(topNode, ns) - { - Range = range; - SchemaNodeOrder = new string[] { "fill", "stroke", "shadow", "path", "textbox", "ClientData", "MoveWithCells", "SizeWithCells", "Anchor", "Locked", "AutoFill", "LockText", "TextHAlign", "TextVAlign", "Row", "Column", "Visible" }; - } - internal ExcelRangeBase Range { get; set; } +namespace OfficeOpenXml.Drawing.Vml; - /// <summary> - /// Address in the worksheet - /// </summary> - public string Address - { - get - { - return Range.Address; - } - } +/// <summary> +/// Drawing object used for comments +/// </summary> +public class ExcelVmlDrawingComment : ExcelVmlDrawingBase, IRangeId { + internal ExcelVmlDrawingComment(XmlNode topNode, ExcelRangeBase range, XmlNamespaceManager ns) + : base(topNode, ns) { + Range = range; + SchemaNodeOrder = new[] { + "fill", + "stroke", + "shadow", + "path", + "textbox", + "ClientData", + "MoveWithCells", + "SizeWithCells", + "Anchor", + "Locked", + "AutoFill", + "LockText", + "TextHAlign", + "TextVAlign", + "Row", + "Column", + "Visible", + }; + } - const string VERTICAL_ALIGNMENT_PATH="x:ClientData/x:TextVAlign"; - /// <summary> - /// Vertical alignment for text - /// </summary> - public eTextAlignVerticalVml VerticalAlignment - { - get - { - switch (GetXmlNodeString(VERTICAL_ALIGNMENT_PATH)) - { - case "Center": - return eTextAlignVerticalVml.Center; - case "Bottom": - return eTextAlignVerticalVml.Bottom; - default: - return eTextAlignVerticalVml.Top; - } - } - set - { - switch (value) - { - case eTextAlignVerticalVml.Center: - SetXmlNodeString(VERTICAL_ALIGNMENT_PATH, "Center"); - break; - case eTextAlignVerticalVml.Bottom: - SetXmlNodeString(VERTICAL_ALIGNMENT_PATH, "Bottom"); - break; - default: - DeleteNode(VERTICAL_ALIGNMENT_PATH); - break; - } - } - } - const string HORIZONTAL_ALIGNMENT_PATH="x:ClientData/x:TextHAlign"; - /// <summary> - /// Horizontal alignment for text - /// </summary> - public eTextAlignHorizontalVml HorizontalAlignment - { - get - { - switch (GetXmlNodeString(HORIZONTAL_ALIGNMENT_PATH)) - { - case "Center": - return eTextAlignHorizontalVml.Center; - case "Right": - return eTextAlignHorizontalVml.Right; - default: - return eTextAlignHorizontalVml.Left; - } - } - set - { - switch (value) - { - case eTextAlignHorizontalVml.Center: - SetXmlNodeString(HORIZONTAL_ALIGNMENT_PATH, "Center"); - break; - case eTextAlignHorizontalVml.Right: - SetXmlNodeString(HORIZONTAL_ALIGNMENT_PATH, "Right"); - break; - default: - DeleteNode(HORIZONTAL_ALIGNMENT_PATH); - break; - } - } - } - const string VISIBLE_PATH = "x:ClientData/x:Visible"; - /// <summary> - /// If the drawing object is visible. - /// </summary> - public bool Visible - { - get - { - return (TopNode.SelectSingleNode(VISIBLE_PATH, NameSpaceManager)!=null); - } - set - { - if (value) - { - CreateNode(VISIBLE_PATH); - Style = SetStyle(Style,"visibility", "visible"); - } - else - { - DeleteNode(VISIBLE_PATH); - Style = SetStyle(Style,"visibility", "hidden"); - } - } - } - const string BACKGROUNDCOLOR_PATH = "@fillcolor"; - const string BACKGROUNDCOLOR2_PATH = "v:fill/@color2"; - /// <summary> - /// Background color - /// </summary> - public Color BackgroundColor - { - get - { - string col = GetXmlNodeString(BACKGROUNDCOLOR_PATH); - if (col == "") - { - return Color.FromArgb(0xff, 0xff, 0xe1); - } - else - { - if(col.StartsWith("#")) col=col.Substring(1,col.Length-1); - int res; - if (int.TryParse(col,System.Globalization.NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out res)) - { - return Color.FromArgb(res); - } - else - { - return Color.Empty; - } - } - } - set - { - string color = "#" + value.ToArgb().ToString("X").Substring(2, 6); - SetXmlNodeString(BACKGROUNDCOLOR_PATH, color); - //SetXmlNode(BACKGROUNDCOLOR2_PATH, color); - } - } - const string LINESTYLE_PATH="v:stroke/@dashstyle"; - const string ENDCAP_PATH = "v:stroke/@endcap"; - /// <summary> - /// Linestyle for border - /// </summary> - public eLineStyleVml LineStyle - { - get - { - string v=GetXmlNodeString(LINESTYLE_PATH); - if (v == "") - { - return eLineStyleVml.Solid; - } - else if (v == "1 1") - { - v = GetXmlNodeString(ENDCAP_PATH); - return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true); - } - else - { - return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true); - } - } - set - { - if (value == eLineStyleVml.Round || value == eLineStyleVml.Square) - { - SetXmlNodeString(LINESTYLE_PATH, "1 1"); - if (value == eLineStyleVml.Round) - { - SetXmlNodeString(ENDCAP_PATH, "round"); - } - else - { - DeleteNode(ENDCAP_PATH); - } - } - else - { - string v = value.ToString(); - v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1, v.Length - 1); - SetXmlNodeString(LINESTYLE_PATH, v); - DeleteNode(ENDCAP_PATH); - } - } - } - const string LINECOLOR_PATH="@strokecolor"; - /// <summary> - /// Line color - /// </summary> - public Color LineColor - { - get - { - string col = GetXmlNodeString(LINECOLOR_PATH); - if (col == "") - { - return Color.Black; - } - else - { - if (col.StartsWith("#")) col = col.Substring(1, col.Length - 1); - int res; - if (int.TryParse(col, System.Globalization.NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out res)) - { - return Color.FromArgb(res); - } - else - { - return Color.Empty; - } - } - } - set - { - string color = "#" + value.ToArgb().ToString("X").Substring(2, 6); - SetXmlNodeString(LINECOLOR_PATH, color); - } - } - const string LINEWIDTH_PATH="@strokeweight"; - /// <summary> - /// Width of the border - /// </summary> - public Single LineWidth - { - get - { - string wt=GetXmlNodeString(LINEWIDTH_PATH); - if (wt == "") return (Single).75; - if(wt.EndsWith("pt")) wt=wt.Substring(0,wt.Length-2); + internal ExcelRangeBase Range { get; set; } - Single ret; - if(Single.TryParse(wt,System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret)) - { - return ret; - } - else - { - return 0; - } - } - set - { - SetXmlNodeString(LINEWIDTH_PATH, value.ToString(CultureInfo.InvariantCulture) + "pt"); - } - } - ///// <summary> - ///// Width of the Comment - ///// </summary> - //public Single Width - //{ - // get - // { - // string v; - // GetStyle("width", out v); - // if(v.EndsWith("pt")) - // { - // v = v.Substring(0, v.Length - 2); - // } - // short ret; - // if (short.TryParse(v,System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret)) - // { - // return ret; - // } - // else - // { - // return 0; - // } - // } - // set - // { - // SetStyle("width", value.ToString("N2",CultureInfo.InvariantCulture) + "pt"); - // } - //} - ///// <summary> - ///// Height of the Comment - ///// </summary> - //public Single Height - //{ - // get - // { - // string v; - // GetStyle("height", out v); - // if (v.EndsWith("pt")) - // { - // v = v.Substring(0, v.Length - 2); - // } - // short ret; - // if (short.TryParse(v, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret)) - // { - // return ret; - // } - // else - // { - // return 0; - // } - // } - // set - // { - // SetStyle("height", value.ToString("N2", CultureInfo.InvariantCulture) + "pt"); - // } - //} - const string TEXTBOX_STYLE_PATH = "v:textbox/@style"; - /// <summary> - /// Autofits the drawingobject - /// </summary> - public bool AutoFit - { - get - { - string value; - GetStyle(GetXmlNodeString(TEXTBOX_STYLE_PATH), "mso-fit-shape-to-text", out value); - return value=="t"; - } - set - { - SetXmlNodeString(TEXTBOX_STYLE_PATH, SetStyle(GetXmlNodeString(TEXTBOX_STYLE_PATH),"mso-fit-shape-to-text", value?"t":"")); - } - } - const string LOCKED_PATH = "x:ClientData/x:Locked"; - /// <summary> - /// If the object is locked when the sheet is protected - /// </summary> - public bool Locked - { - get - { - return GetXmlNodeBool(LOCKED_PATH, false); - } - set - { - SetXmlNodeBool(LOCKED_PATH, value, false); - } - } - const string LOCK_TEXT_PATH = "x:ClientData/x:LockText"; - /// <summary> - /// Specifies that the object's text is locked - /// </summary> - public bool LockText - { - get - { - return GetXmlNodeBool(LOCK_TEXT_PATH, false); - } - set - { - SetXmlNodeBool(LOCK_TEXT_PATH, value, false); - } - } - ExcelVmlDrawingPosition _from = null; - /// <summary> - /// From position. For comments only when Visible=true. - /// </summary> - public ExcelVmlDrawingPosition From - { - get - { - if (_from == null) - { - _from = new ExcelVmlDrawingPosition(NameSpaceManager, TopNode.SelectSingleNode("x:ClientData", NameSpaceManager), 0); - } - return _from; - } - } - ExcelVmlDrawingPosition _to = null; - /// <summary> - /// To position. For comments only when Visible=true. - /// </summary> - public ExcelVmlDrawingPosition To - { - get - { - if (_to == null) - { - _to = new ExcelVmlDrawingPosition(NameSpaceManager, TopNode.SelectSingleNode("x:ClientData", NameSpaceManager), 4); - } - return _to; - } - } - const string STYLE_PATH = "@style"; - internal string Style - { - get - { - return GetXmlNodeString(STYLE_PATH); - } - set - { - SetXmlNodeString(STYLE_PATH, value); - } - } - #region IRangeID Members + /// <summary> + /// Address in the worksheet + /// </summary> + public string Address => Range.Address; - ulong IRangeID.RangeID - { - get - { - return ExcelCellBase.GetCellID(Range.Worksheet.SheetID, Range.Start.Row, Range.Start.Column); - } - set - { - - } - } + private const string _verticalAlignmentPath = "x:ClientData/x:TextVAlign"; - #endregion + /// <summary> + /// Vertical alignment for text + /// </summary> + public eTextAlignVerticalVml VerticalAlignment { + get { + switch (GetXmlNodeString(_verticalAlignmentPath)) { + case "Center": + return eTextAlignVerticalVml.Center; + case "Bottom": + return eTextAlignVerticalVml.Bottom; + default: + return eTextAlignVerticalVml.Top; + } } + set { + switch (value) { + case eTextAlignVerticalVml.Center: + SetXmlNodeString(_verticalAlignmentPath, "Center"); + break; + case eTextAlignVerticalVml.Bottom: + SetXmlNodeString(_verticalAlignmentPath, "Bottom"); + break; + default: + DeleteNode(_verticalAlignmentPath); + break; + } + } + } + + private const string _horizontalAlignmentPath = "x:ClientData/x:TextHAlign"; + + /// <summary> + /// Horizontal alignment for text + /// </summary> + public eTextAlignHorizontalVml HorizontalAlignment { + get { + switch (GetXmlNodeString(_horizontalAlignmentPath)) { + case "Center": + return eTextAlignHorizontalVml.Center; + case "Right": + return eTextAlignHorizontalVml.Right; + default: + return eTextAlignHorizontalVml.Left; + } + } + set { + switch (value) { + case eTextAlignHorizontalVml.Center: + SetXmlNodeString(_horizontalAlignmentPath, "Center"); + break; + case eTextAlignHorizontalVml.Right: + SetXmlNodeString(_horizontalAlignmentPath, "Right"); + break; + default: + DeleteNode(_horizontalAlignmentPath); + break; + } + } + } + + private const string _visiblePath = "x:ClientData/x:Visible"; + + /// <summary> + /// If the drawing object is visible. + /// </summary> + public bool Visible { + get { return (TopNode.SelectSingleNode(_visiblePath, NameSpaceManager) != null); } + set { + if (value) { + CreateNode(_visiblePath); + Style = SetStyle(Style, "visibility", "visible"); + } else { + DeleteNode(_visiblePath); + Style = SetStyle(Style, "visibility", "hidden"); + } + } + } + + private const string _backgroundcolorPath = "@fillcolor"; + private const string _backgroundcolor2Path = "v:fill/@color2"; + + /// <summary> + /// Background color + /// </summary> + public Color BackgroundColor { + get { + string col = GetXmlNodeString(_backgroundcolorPath); + if (col == "") { + return Color.FromArgb(0xff, 0xff, 0xe1); + } + if (col.StartsWith("#")) { + col = col.Substring(1, col.Length - 1); + } + int res; + if (int.TryParse( + col, + NumberStyles.AllowHexSpecifier, + CultureInfo.InvariantCulture, + out res)) { + return Color.FromArgb(res); + } + return Color.Empty; + } + set { + string color = "#" + value.ToArgb().ToString("X").Substring(2, 6); + SetXmlNodeString(_backgroundcolorPath, color); + //SetXmlNode(BACKGROUNDCOLOR2_PATH, color); + } + } + + private const string _linestylePath = "v:stroke/@dashstyle"; + private const string _endcapPath = "v:stroke/@endcap"; + + /// <summary> + /// Linestyle for border + /// </summary> + public eLineStyleVml LineStyle { + get { + string v = GetXmlNodeString(_linestylePath); + if (v == "") { + return eLineStyleVml.Solid; + } + if (v == "1 1") { + v = GetXmlNodeString(_endcapPath); + return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true); + } + return (eLineStyleVml)Enum.Parse(typeof(eLineStyleVml), v, true); + } + set { + if (value == eLineStyleVml.Round || value == eLineStyleVml.Square) { + SetXmlNodeString(_linestylePath, "1 1"); + if (value == eLineStyleVml.Round) { + SetXmlNodeString(_endcapPath, "round"); + } else { + DeleteNode(_endcapPath); + } + } else { + string v = value.ToString(); + v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1, v.Length - 1); + SetXmlNodeString(_linestylePath, v); + DeleteNode(_endcapPath); + } + } + } + + private const string _linecolorPath = "@strokecolor"; + + /// <summary> + /// Line color + /// </summary> + public Color LineColor { + get { + string col = GetXmlNodeString(_linecolorPath); + if (col == "") { + return Color.Black; + } + if (col.StartsWith("#")) { + col = col.Substring(1, col.Length - 1); + } + int res; + if (int.TryParse( + col, + NumberStyles.AllowHexSpecifier, + CultureInfo.InvariantCulture, + out res)) { + return Color.FromArgb(res); + } + return Color.Empty; + } + set { + string color = "#" + value.ToArgb().ToString("X").Substring(2, 6); + SetXmlNodeString(_linecolorPath, color); + } + } + + private const string _linewidthPath = "@strokeweight"; + + /// <summary> + /// Width of the border + /// </summary> + public Single LineWidth { + get { + string wt = GetXmlNodeString(_linewidthPath); + if (wt == "") { + return (Single).75; + } + if (wt.EndsWith("pt")) { + wt = wt.Substring(0, wt.Length - 2); + } + + Single ret; + if (Single.TryParse(wt, NumberStyles.Any, CultureInfo.InvariantCulture, out ret)) { + return ret; + } + return 0; + } + set { SetXmlNodeString(_linewidthPath, value.ToString(CultureInfo.InvariantCulture) + "pt"); } + } + + ///// <summary> + ///// Width of the Comment + ///// </summary> + //public Single Width + //{ + // get + // { + // string v; + // GetStyle("width", out v); + // if(v.EndsWith("pt")) + // { + // v = v.Substring(0, v.Length - 2); + // } + // short ret; + // if (short.TryParse(v,System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret)) + // { + // return ret; + // } + // else + // { + // return 0; + // } + // } + // set + // { + // SetStyle("width", value.ToString("N2",CultureInfo.InvariantCulture) + "pt"); + // } + //} + ///// <summary> + ///// Height of the Comment + ///// </summary> + //public Single Height + //{ + // get + // { + // string v; + // GetStyle("height", out v); + // if (v.EndsWith("pt")) + // { + // v = v.Substring(0, v.Length - 2); + // } + // short ret; + // if (short.TryParse(v, System.Globalization.NumberStyles.Any, CultureInfo.InvariantCulture, out ret)) + // { + // return ret; + // } + // else + // { + // return 0; + // } + // } + // set + // { + // SetStyle("height", value.ToString("N2", CultureInfo.InvariantCulture) + "pt"); + // } + //} + private const string _textboxStylePath = "v:textbox/@style"; + + /// <summary> + /// Autofits the drawingobject + /// </summary> + public bool AutoFit { + get { + string value; + GetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", out value); + return value == "t"; + } + set { + SetXmlNodeString( + _textboxStylePath, + SetStyle(GetXmlNodeString(_textboxStylePath), "mso-fit-shape-to-text", value ? "t" : "")); + } + } + + private const string _lockedPath = "x:ClientData/x:Locked"; + + /// <summary> + /// If the object is locked when the sheet is protected + /// </summary> + public bool Locked { + get { return GetXmlNodeBool(_lockedPath, false); } + set { SetXmlNodeBool(_lockedPath, value, false); } + } + + private const string _lockTextPath = "x:ClientData/x:LockText"; + + /// <summary> + /// Specifies that the object's text is locked + /// </summary> + public bool LockText { + get { return GetXmlNodeBool(_lockTextPath, false); } + set { SetXmlNodeBool(_lockTextPath, value, false); } + } + + private ExcelVmlDrawingPosition _from; + + /// <summary> + /// From position. For comments only when Visible=true. + /// </summary> + public ExcelVmlDrawingPosition From { + get { + if (_from == null) { + _from = new( + NameSpaceManager, + TopNode.SelectSingleNode("x:ClientData", NameSpaceManager), + 0); + } + return _from; + } + } + + private ExcelVmlDrawingPosition _to; + + /// <summary> + /// To position. For comments only when Visible=true. + /// </summary> + public ExcelVmlDrawingPosition To { + get { + if (_to == null) { + _to = new(NameSpaceManager, TopNode.SelectSingleNode("x:ClientData", NameSpaceManager), 4); + } + return _to; + } + } + + private const string _stylePath = "@style"; + + internal string Style { + get { return GetXmlNodeString(_stylePath); } + set { SetXmlNodeString(_stylePath, value); } + } + + ulong IRangeId.RangeID { + get { + return ExcelCellBase.GetCellId(Range.Worksheet.SheetID, Range.Start.Row, Range.Start.Column); + } + set {} + } }
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs index 27add95..6a908e3 100644 --- a/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs +++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingCommentCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,193 +13,179 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2010-06-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; using System.Xml; -using System.Collections; -namespace OfficeOpenXml.Drawing.Vml -{ - internal class ExcelVmlDrawingCommentCollection : ExcelVmlDrawingBaseCollection, IEnumerable - { - internal RangeCollection _drawings; - internal ExcelVmlDrawingCommentCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri) : - base(pck, ws,uri) - { - if (uri == null) - { - VmlDrawingXml.LoadXml(CreateVmlDrawings()); - _drawings = new RangeCollection(new List<IRangeID>()); - } - else - { - AddDrawingsFromXml(ws); - } - } - protected void AddDrawingsFromXml(ExcelWorksheet ws) - { - var nodes = VmlDrawingXml.SelectNodes("//v:shape", NameSpaceManager); - var list = new List<IRangeID>(); - foreach (XmlNode node in nodes) - { - var rowNode = node.SelectSingleNode("x:ClientData/x:Row", NameSpaceManager); - var colNode = node.SelectSingleNode("x:ClientData/x:Column", NameSpaceManager); - if (rowNode != null && colNode != null) - { - var row = int.Parse(rowNode.InnerText) + 1; - var col = int.Parse(colNode.InnerText) + 1; - list.Add(new ExcelVmlDrawingComment(node, ws.Cells[row, col], NameSpaceManager)); - } - else - { - list.Add(new ExcelVmlDrawingComment(node, ws.Cells[1, 1], NameSpaceManager)); - } - } - list.Sort(new Comparison<IRangeID>((r1, r2) => (r1.RangeID < r2.RangeID ? -1 : r1.RangeID > r2.RangeID ? 1 : 0))); //Vml drawings are not sorted. Sort to avoid missmatches. - _drawings = new RangeCollection(list); - } - private string CreateVmlDrawings() - { - string vml=string.Format("<xml xmlns:v=\"{0}\" xmlns:o=\"{1}\" xmlns:x=\"{2}\">", - ExcelPackage.schemaMicrosoftVml, - ExcelPackage.schemaMicrosoftOffice, - ExcelPackage.schemaMicrosoftExcel); - - vml+="<o:shapelayout v:ext=\"edit\">"; - vml+="<o:idmap v:ext=\"edit\" data=\"1\"/>"; - vml+="</o:shapelayout>"; +namespace OfficeOpenXml.Drawing.Vml; - vml+="<v:shapetype id=\"_x0000_t202\" coordsize=\"21600,21600\" o:spt=\"202\" path=\"m,l,21600r21600,l21600,xe\">"; - vml+="<v:stroke joinstyle=\"miter\" />"; - vml+="<v:path gradientshapeok=\"t\" o:connecttype=\"rect\" />"; - vml+="</v:shapetype>"; - vml+= "</xml>"; +internal class ExcelVmlDrawingCommentCollection : ExcelVmlDrawingBaseCollection, IEnumerable { + internal RangeCollection _drawings; - return vml; - } - internal ExcelVmlDrawingComment Add(ExcelRangeBase cell) - { - XmlNode node = AddDrawing(cell); - var draw = new ExcelVmlDrawingComment(node, cell, NameSpaceManager); - _drawings.Add(draw); - return draw; - } - private XmlNode AddDrawing(ExcelRangeBase cell) - { - int row = cell.Start.Row, col = cell.Start.Column; - var node = VmlDrawingXml.CreateElement("v", "shape", ExcelPackage.schemaMicrosoftVml); - - var id = ExcelCellBase.GetCellID(cell.Worksheet.SheetID, cell._fromRow, cell._fromCol); - var ix = _drawings.IndexOf(id); - if (ix < 0 && (~ix < _drawings.Count)) - { - ix = ~ix; - var prevDraw = _drawings[ix] as ExcelVmlDrawingBase; - prevDraw.TopNode.ParentNode.InsertBefore(node, prevDraw.TopNode); - } - else - { - VmlDrawingXml.DocumentElement.AppendChild(node); - } - - node.SetAttribute("id", GetNewId()); - node.SetAttribute("type", "#_x0000_t202"); - node.SetAttribute("style", "position:absolute;z-index:1; visibility:hidden"); - //node.SetAttribute("style", "position:absolute; margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;z-index:1; visibility:hidden"); - node.SetAttribute("fillcolor", "#ffffe1"); - node.SetAttribute("insetmode",ExcelPackage.schemaMicrosoftOffice,"auto"); - - string vml = "<v:fill color2=\"#ffffe1\" />"; - vml += "<v:shadow on=\"t\" color=\"black\" obscured=\"t\" />"; - vml += "<v:path o:connecttype=\"none\" />"; - vml += "<v:textbox style=\"mso-direction-alt:auto\">"; - vml += "<div style=\"text-align:left\" />"; - vml += "</v:textbox>"; - vml += "<x:ClientData ObjectType=\"Note\">"; - vml += "<x:MoveWithCells />"; - vml += "<x:SizeWithCells />"; - vml += string.Format("<x:Anchor>{0}, 15, {1}, 2, {2}, 31, {3}, 1</x:Anchor>", col, row - 1, col + 2, row + 3); - vml += "<x:AutoFill>False</x:AutoFill>"; - vml += string.Format("<x:Row>{0}</x:Row>", row - 1); ; - vml += string.Format("<x:Column>{0}</x:Column>", col - 1); - vml += "</x:ClientData>"; - - node.InnerXml = vml; - return node; - } - int _nextID = 0; - /// <summary> - /// returns the next drawing id. - /// </summary> - /// <returns></returns> - internal string GetNewId() - { - if (_nextID == 0) - { - foreach (ExcelVmlDrawingComment draw in this) - { - if (draw.Id.Length > 3 && draw.Id.StartsWith("vml")) - { - int id; - if (int.TryParse(draw.Id.Substring(3, draw.Id.Length - 3), out id)) - { - if (id > _nextID) - { - _nextID = id; - } - } - } - } - } - _nextID++; - return "vml" + _nextID.ToString(); - } - internal ExcelVmlDrawingBase this[ulong rangeID] - { - get - { - return _drawings[rangeID] as ExcelVmlDrawingComment; - } - } - internal bool ContainsKey(ulong rangeID) - { - return _drawings.ContainsKey(rangeID); - } - internal int Count - { - get - { - return _drawings.Count; - } - } - #region IEnumerable Members - - #endregion - - public IEnumerator GetEnumerator() - { - return _drawings; - } - - IEnumerator IEnumerable.GetEnumerator() - { - return _drawings; - } + internal ExcelVmlDrawingCommentCollection(ExcelPackage pck, ExcelWorksheet ws, Uri uri) + : base(pck, ws, uri) { + if (uri == null) { + VmlDrawingXml.LoadXml(CreateVmlDrawings()); + _drawings = new(new()); + } else { + AddDrawingsFromXml(ws); } + } + + protected void AddDrawingsFromXml(ExcelWorksheet ws) { + var nodes = VmlDrawingXml.SelectNodes("//v:shape", NameSpaceManager); + var list = new List<IRangeId>(); + foreach (XmlNode node in nodes) { + var rowNode = node.SelectSingleNode("x:ClientData/x:Row", NameSpaceManager); + var colNode = node.SelectSingleNode("x:ClientData/x:Column", NameSpaceManager); + if (rowNode != null && colNode != null) { + var row = int.Parse(rowNode.InnerText) + 1; + var col = int.Parse(colNode.InnerText) + 1; + list.Add(new ExcelVmlDrawingComment(node, ws.Cells[row, col], NameSpaceManager)); + } else { + list.Add(new ExcelVmlDrawingComment(node, ws.Cells[1, 1], NameSpaceManager)); + } + } + list.Sort((r1, r2) => + (r1.RangeID < r2.RangeID + ? -1 + : r1.RangeID > r2.RangeID + ? 1 + : 0)); //Vml drawings are not sorted. Sort to avoid missmatches. + _drawings = new(list); + } + + private string CreateVmlDrawings() { + string vml = string.Format( + "<xml xmlns:v=\"{0}\" xmlns:o=\"{1}\" xmlns:x=\"{2}\">", + ExcelPackage._schemaMicrosoftVml, + ExcelPackage._schemaMicrosoftOffice, + ExcelPackage._schemaMicrosoftExcel); + + vml += "<o:shapelayout v:ext=\"edit\">"; + vml += "<o:idmap v:ext=\"edit\" data=\"1\"/>"; + vml += "</o:shapelayout>"; + + vml += + "<v:shapetype id=\"_x0000_t202\" coordsize=\"21600,21600\" o:spt=\"202\" path=\"m,l,21600r21600,l21600,xe\">"; + vml += "<v:stroke joinstyle=\"miter\" />"; + vml += "<v:path gradientshapeok=\"t\" o:connecttype=\"rect\" />"; + vml += "</v:shapetype>"; + vml += "</xml>"; + + return vml; + } + + internal ExcelVmlDrawingComment Add(ExcelRangeBase cell) { + XmlNode node = AddDrawing(cell); + var draw = new ExcelVmlDrawingComment(node, cell, NameSpaceManager); + _drawings.Add(draw); + return draw; + } + + private XmlNode AddDrawing(ExcelRangeBase cell) { + int row = cell.Start.Row, + col = cell.Start.Column; + var node = VmlDrawingXml.CreateElement("v", "shape", ExcelPackage._schemaMicrosoftVml); + + var id = ExcelCellBase.GetCellId(cell.Worksheet.SheetID, cell._fromRow, cell._fromCol); + var ix = _drawings.IndexOf(id); + if (ix < 0 && (~ix < _drawings.Count)) { + ix = ~ix; + var prevDraw = _drawings[ix] as ExcelVmlDrawingBase; + prevDraw.TopNode.ParentNode.InsertBefore(node, prevDraw.TopNode); + } else { + VmlDrawingXml.DocumentElement.AppendChild(node); + } + + node.SetAttribute("id", GetNewId()); + node.SetAttribute("type", "#_x0000_t202"); + node.SetAttribute("style", "position:absolute;z-index:1; visibility:hidden"); + //node.SetAttribute("style", "position:absolute; margin-left:59.25pt;margin-top:1.5pt;width:108pt;height:59.25pt;z-index:1; visibility:hidden"); + node.SetAttribute("fillcolor", "#ffffe1"); + node.SetAttribute("insetmode", ExcelPackage._schemaMicrosoftOffice, "auto"); + + string vml = "<v:fill color2=\"#ffffe1\" />"; + vml += "<v:shadow on=\"t\" color=\"black\" obscured=\"t\" />"; + vml += "<v:path o:connecttype=\"none\" />"; + vml += "<v:textbox style=\"mso-direction-alt:auto\">"; + vml += "<div style=\"text-align:left\" />"; + vml += "</v:textbox>"; + vml += "<x:ClientData ObjectType=\"Note\">"; + vml += "<x:MoveWithCells />"; + vml += "<x:SizeWithCells />"; + vml += string.Format( + "<x:Anchor>{0}, 15, {1}, 2, {2}, 31, {3}, 1</x:Anchor>", + col, + row - 1, + col + 2, + row + 3); + vml += "<x:AutoFill>False</x:AutoFill>"; + vml += string.Format("<x:Row>{0}</x:Row>", row - 1); + ; + vml += string.Format("<x:Column>{0}</x:Column>", col - 1); + vml += "</x:ClientData>"; + + node.InnerXml = vml; + return node; + } + + private int _nextID; + + /// <summary> + /// returns the next drawing id. + /// </summary> + /// <returns></returns> + internal string GetNewId() { + if (_nextID == 0) { + foreach (ExcelVmlDrawingComment draw in this) { + if (draw.Id.Length > 3 && draw.Id.StartsWith("vml")) { + int id; + if (int.TryParse(draw.Id.Substring(3, draw.Id.Length - 3), out id)) { + if (id > _nextID) { + _nextID = id; + } + } + } + } + } + _nextID++; + return "vml" + _nextID; + } + + internal ExcelVmlDrawingBase this[ulong rangeId] => _drawings[rangeId] as ExcelVmlDrawingComment; + + internal bool ContainsKey(ulong rangeId) { + return _drawings.ContainsKey(rangeId); + } + + internal int Count { + get { return _drawings.Count; } + } + + public IEnumerator GetEnumerator() { + return _drawings; + } + + IEnumerator IEnumerable.GetEnumerator() { + return _drawings; + } }
diff --git a/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs b/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs index bd3d1b4..755fad0 100644 --- a/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs +++ b/EPPlus/Drawing/Vml/ExcelVmlDrawingPosition.cs
@@ -13,121 +13,91 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2010-06-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; using System.Xml; -namespace OfficeOpenXml.Drawing.Vml -{ - /// <summary> - /// The position of a VML drawing. Used for comments - /// </summary> - public class ExcelVmlDrawingPosition : XmlHelper - { - int _startPos; - internal ExcelVmlDrawingPosition(XmlNamespaceManager ns, XmlNode topNode, int startPos) : - base(ns, topNode) - { - _startPos = startPos; - } - /// <summary> - /// Row. Zero based - /// </summary> - public int Row - { - get - { - return GetNumber(2); - } - set - { - SetNumber(2, value); - } - } - /// <summary> - /// Row offset in pixels. Zero based - /// </summary> - public int RowOffset - { - get - { - return GetNumber(3); - } - set - { - SetNumber(3, value); - } - } - /// <summary> - /// Column. Zero based - /// </summary> - public int Column - { - get - { - return GetNumber(0); - } - set - { - SetNumber(0, value); - } - } - /// <summary> - /// Column offset. Zero based - /// </summary> - public int ColumnOffset - { - get - { - return GetNumber(1); - } - set - { - SetNumber(1, value); - } - } - private void SetNumber(int pos, int value) - { - string anchor = GetXmlNodeString("x:Anchor"); - string[] numbers = anchor.Split(','); - if (numbers.Length == 8) - { - numbers[_startPos + pos] = value.ToString(); - } - else - { - throw (new Exception("Anchor element is invalid in vmlDrawing")); - } - SetXmlNodeString("x:Anchor", string.Join(",",numbers)); - } - private int GetNumber(int pos) - { - string anchor = GetXmlNodeString("x:Anchor"); - string[] numbers = anchor.Split(','); - if (numbers.Length == 8) - { - int ret; - if (int.TryParse(numbers[_startPos + pos], out ret)) - { - return ret; - } - } - throw(new Exception("Anchor element is invalid in vmlDrawing")); - } +namespace OfficeOpenXml.Drawing.Vml; + +/// <summary> +/// The position of a VML drawing. Used for comments +/// </summary> +public class ExcelVmlDrawingPosition : XmlHelper { + private int _startPos; + + internal ExcelVmlDrawingPosition(XmlNamespaceManager ns, XmlNode topNode, int startPos) + : base(ns, topNode) { + _startPos = startPos; + } + + /// <summary> + /// Row. Zero based + /// </summary> + public int Row { + get => GetNumber(2); + set => SetNumber(2, value); + } + + /// <summary> + /// Row offset in pixels. Zero based + /// </summary> + public int RowOffset { + get => GetNumber(3); + set => SetNumber(3, value); + } + + /// <summary> + /// Column. Zero based + /// </summary> + public int Column { + get => GetNumber(0); + set => SetNumber(0, value); + } + + /// <summary> + /// Column offset. Zero based + /// </summary> + public int ColumnOffset { + get => GetNumber(1); + set => SetNumber(1, value); + } + + private void SetNumber(int pos, int value) { + string anchor = GetXmlNodeString("x:Anchor"); + string[] numbers = anchor.Split(','); + if (numbers.Length == 8) { + numbers[_startPos + pos] = value.ToString(); + } else { + throw (new("Anchor element is invalid in vmlDrawing")); } + SetXmlNodeString("x:Anchor", string.Join(",", numbers)); + } + + private int GetNumber(int pos) { + string anchor = GetXmlNodeString("x:Anchor"); + string[] numbers = anchor.Split(','); + if (numbers.Length == 8) { + int ret; + if (int.TryParse(numbers[_startPos + pos], out ret)) { + return ret; + } + } + throw (new("Anchor element is invalid in vmlDrawing")); + } }
diff --git a/EPPlus/EPPlusSDK.csproj b/EPPlus/EPPlusSDK.csproj index c81fe9a..00f19ed 100644 --- a/EPPlus/EPPlusSDK.csproj +++ b/EPPlus/EPPlusSDK.csproj
@@ -10,11 +10,11 @@ <ImplicitUsings>disable</ImplicitUsings> </PropertyGroup> <ItemGroup> - <PackageReference Include="Microsoft.CSharp" Version="4.7.0" /> - <PackageReference Include="System.CodeDom" Version="5.0.0" /> - <PackageReference Include="System.Drawing.Common" Version="6.0.0" /> - <PackageReference Include="System.Security.Cryptography.Pkcs" Version="5.0.1" /> - <PackageReference Include="System.Security.Permissions" Version="5.0.0" /> - <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" /> + <PackageReference Include="Microsoft.CSharp" Version="4.7.0"/> + <PackageReference Include="System.CodeDom" Version="5.0.0"/> + <PackageReference Include="System.Drawing.Common" Version="6.0.0"/> + <PackageReference Include="System.Security.Cryptography.Pkcs" Version="5.0.1"/> + <PackageReference Include="System.Security.Permissions" Version="5.0.0"/> + <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0"/> </ItemGroup> </Project>
diff --git a/EPPlus/ExcelAddress.cs b/EPPlus/ExcelAddress.cs index 70f3012..54e5460 100644 --- a/EPPlus/ExcelAddress.cs +++ b/EPPlus/ExcelAddress.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,1414 +13,1342 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 18-MAR-2010 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Text.RegularExpressions; -namespace OfficeOpenXml -{ - public class ExcelTableAddress - { - public string Name { get; set; } - public string ColumnSpan { get; set; } - public bool IsAll { get; set; } - public bool IsHeader { get; set; } - public bool IsData { get; set; } - public bool IsTotals { get; set; } - public bool IsThisRow { get; set; } +namespace OfficeOpenXml; + +public class ExcelTableAddress { + public string Name { get; set; } + + public string ColumnSpan { get; set; } + + public bool IsAll { get; set; } + + public bool IsHeader { get; set; } + + public bool IsData { get; set; } + + public bool IsTotals { get; set; } + + public bool IsThisRow { get; set; } +} + +/// <summary> +/// A range address +/// </summary> +/// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> +public class ExcelAddressBase : ExcelCellBase { + protected internal int _fromRow = -1, + _toRow, + _fromCol, + _toCol; + protected internal bool _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed; + protected internal string _wb; + protected internal string _ws; + protected internal string _address; + + protected internal event EventHandler AddressChange; + + internal enum eAddressCollition { + No, + Partly, + Inside, + Equal, + } + + internal enum eShiftType { + Right, + Down, + EntireRow, + EntireColumn, + } + + internal ExcelAddressBase() {} + + /// <summary> + /// Creates an Address object + /// </summary> + /// <param name="fromRow">start row</param> + /// <param name="fromCol">start column</param> + /// <param name="toRow">End row</param> + /// <param name="toColumn">End column</param> + public ExcelAddressBase(int fromRow, int fromCol, int toRow, int toColumn) { + _fromRow = fromRow; + _toRow = toRow; + _fromCol = fromCol; + _toCol = toColumn; + Validate(); + + _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol); + } + + /// <summary> + /// Creates an Address object + /// </summary> + /// <param name="fromRow">start row</param> + /// <param name="fromCol">start column</param> + /// <param name="toRow">End row</param> + /// <param name="toColumn">End column</param> + /// <param name="fromRowFixed">start row fixed</param> + /// <param name="fromColFixed">start column fixed</param> + /// <param name="toRowFixed">End row fixed</param> + /// <param name="toColFixed">End column fixed</param> + public ExcelAddressBase( + int fromRow, + int fromCol, + int toRow, + int toColumn, + bool fromRowFixed, + bool fromColFixed, + bool toRowFixed, + bool toColFixed) { + _fromRow = fromRow; + _toRow = toRow; + _fromCol = fromCol; + _toCol = toColumn; + _fromRowFixed = fromRowFixed; + _fromColFixed = fromColFixed; + _toRowFixed = toRowFixed; + _toColFixed = toColFixed; + Validate(); + + _address = GetAddress( + _fromRow, + _fromCol, + _toRow, + _toCol, + _fromRowFixed, + fromColFixed, + _toRowFixed, + _toColFixed); + } + + /// <summary> + /// Creates an Address object + /// </summary> + /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> + /// <param name="address">The Excel Address</param> + public ExcelAddressBase(string address) { + SetAddress(address); + } + + /// <summary> + /// Creates an Address object + /// </summary> + /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> + /// <param name="address">The Excel Address</param> + /// <param name="pck">Reference to the package to find information about tables and names</param> + /// <param name="referenceAddress">The address</param> + public ExcelAddressBase(string address, ExcelPackage pck, ExcelAddressBase referenceAddress) { + SetAddress(address); + SetRcFromTable(pck, referenceAddress); + } + + internal void SetRcFromTable(ExcelPackage pck, ExcelAddressBase referenceAddress) { + if (string.IsNullOrEmpty(_wb) && Table != null) { + foreach (var ws in pck.Workbook.Worksheets) { + foreach (var t in ws.Tables) { + if (t.Name.Equals(Table.Name, StringComparison.InvariantCultureIgnoreCase)) { + _ws = ws.Name; + if (Table.IsAll) { + _fromRow = t.Address._fromRow; + _toRow = t.Address._toRow; + } else { + if (Table.IsThisRow) { + if (referenceAddress == null) { + _fromRow = -1; + _toRow = -1; + } else { + _fromRow = referenceAddress._fromRow; + _toRow = _fromRow; + } + } else if (Table.IsHeader && Table.IsData) { + _fromRow = t.Address._fromRow; + _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow; + } else if (Table.IsData && Table.IsTotals) { + _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow; + _toRow = t.Address._toRow; + } else if (Table.IsHeader) { + _fromRow = t.ShowHeader ? t.Address._fromRow : -1; + _toRow = t.ShowHeader ? t.Address._fromRow : -1; + } else if (Table.IsTotals) { + _fromRow = t.ShowTotal ? t.Address._toRow : -1; + _toRow = t.ShowTotal ? t.Address._toRow : -1; + } else { + _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow; + _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow; + } + } + + if (string.IsNullOrEmpty(Table.ColumnSpan)) { + _fromCol = t.Address._fromCol; + _toCol = t.Address._toCol; + return; + } + var col = t.Address._fromCol; + var cols = Table.ColumnSpan.Split(':'); + foreach (var c in t.Columns) { + if (_fromCol <= 0 + && cols[0] + .Equals( + c.Name, + StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case + { + _fromCol = col; + if (cols.Length == 1) { + _toCol = _fromCol; + return; + } + } else if (cols.Length > 1 + && _fromCol > 0 + && cols[1] + .Equals( + c.Name, + StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case + { + _toCol = col; + return; + } + + col++; + } + } + } + } } - /// <summary> - /// A range address - /// </summary> - /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> - public class ExcelAddressBase : ExcelCellBase + } + + /// <summary> + /// Address is an defined name + /// </summary> + /// <param name="address">the name</param> + /// <param name="isName">Should always be true</param> + internal ExcelAddressBase(string address, bool isName) { + if (isName) { + _address = address; + _fromRow = -1; + _fromCol = -1; + _toRow = -1; + _toCol = -1; + _start = null; + _end = null; + } else { + SetAddress(address); + } + } + + protected internal void SetAddress(string address) { + address = address.Trim(); + if (address.StartsWith("'")) { + SetWbWs(address); + } else if (address.StartsWith( + "[")) //Remove any external reference { - internal protected int _fromRow=-1, _toRow, _fromCol, _toCol; - protected internal bool _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed; - internal protected string _wb; - internal protected string _ws; - internal protected string _address; - internal protected event EventHandler AddressChange; + SetWbWs(address); + } else { + _address = address; + } + if (_address.IndexOfAny(new[] { ',', '!', '[' }) > -1) { + //Advanced address. Including Sheet or multi or table. + ExtractAddress(_address); + } else { + //Simple address + GetRowColFromAddress( + _address, + out _fromRow, + out _fromCol, + out _toRow, + out _toCol, + out _fromRowFixed, + out _fromColFixed, + out _toRowFixed, + out _toColFixed); + _addresses = null; + _start = null; + _end = null; + } + _address = address; + Validate(); + } - internal enum eAddressCollition - { - No, - Partly, - Inside, - Equal - } - internal enum eShiftType - { - Right, - Down, - EntireRow, - EntireColumn - } - #region "Constructors" - internal ExcelAddressBase() - { - } - /// <summary> - /// Creates an Address object - /// </summary> - /// <param name="fromRow">start row</param> - /// <param name="fromCol">start column</param> - /// <param name="toRow">End row</param> - /// <param name="toColumn">End column</param> - public ExcelAddressBase(int fromRow, int fromCol, int toRow, int toColumn) - { - _fromRow = fromRow; - _toRow = toRow; - _fromCol = fromCol; - _toCol = toColumn; - Validate(); + internal void ChangeAddress() { + if (AddressChange != null) { + AddressChange(this, new()); + } + } - _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol); - } - /// <summary> - /// Creates an Address object - /// </summary> - /// <param name="fromRow">start row</param> - /// <param name="fromCol">start column</param> - /// <param name="toRow">End row</param> - /// <param name="toColumn">End column</param> - /// <param name="fromRowFixed">start row fixed</param> - /// <param name="fromColFixed">start column fixed</param> - /// <param name="toRowFixed">End row fixed</param> - /// <param name="toColFixed">End column fixed</param> - public ExcelAddressBase(int fromRow, int fromCol, int toRow, int toColumn, bool fromRowFixed, bool fromColFixed, bool toRowFixed, bool toColFixed) - { - _fromRow = fromRow; - _toRow = toRow; - _fromCol = fromCol; - _toCol = toColumn; - _fromRowFixed = fromRowFixed; - _fromColFixed = fromColFixed; - _toRowFixed = toRowFixed; - _toColFixed = toColFixed; - Validate(); + private void SetWbWs(string address) { + int pos = 0; - _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol, _fromRowFixed, fromColFixed, _toRowFixed, _toColFixed ); - } - /// <summary> - /// Creates an Address object - /// </summary> - /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> - /// <param name="address">The Excel Address</param> - public ExcelAddressBase(string address) - { - SetAddress(address); - } - /// <summary> - /// Creates an Address object - /// </summary> - /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> - /// <param name="address">The Excel Address</param> - /// <param name="pck">Reference to the package to find information about tables and names</param> - /// <param name="referenceAddress">The address</param> - public ExcelAddressBase(string address, ExcelPackage pck, ExcelAddressBase referenceAddress) - { - SetAddress(address); - SetRCFromTable(pck, referenceAddress); - } + // Get Workbook, if any + if (address[pos] == '[') { + pos = address.IndexOf("]"); + _wb = address.Substring(1, pos - 1); + pos++; + } else { + _wb = ""; + } - internal void SetRCFromTable(ExcelPackage pck, ExcelAddressBase referenceAddress) - { - if (string.IsNullOrEmpty(_wb) && Table != null) - { - foreach (var ws in pck.Workbook.Worksheets) - { - foreach (var t in ws.Tables) - { - if (t.Name.Equals(Table.Name, StringComparison.InvariantCultureIgnoreCase)) - { - _ws = ws.Name; - if (Table.IsAll) - { - _fromRow = t.Address._fromRow; - _toRow = t.Address._toRow; - } - else - { - if (Table.IsThisRow) - { - if (referenceAddress == null) - { - _fromRow = -1; - _toRow = -1; - } - else - { - _fromRow = referenceAddress._fromRow; - _toRow = _fromRow; - } - } - else if (Table.IsHeader && Table.IsData) - { - _fromRow = t.Address._fromRow; - _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow; - } - else if (Table.IsData && Table.IsTotals) - { - _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow; - _toRow = t.Address._toRow; - } - else if (Table.IsHeader) - { - _fromRow = t.ShowHeader ? t.Address._fromRow : -1; - _toRow = t.ShowHeader ? t.Address._fromRow : -1; - } - else if (Table.IsTotals) - { - _fromRow = t.ShowTotal ? t.Address._toRow : -1; - _toRow = t.ShowTotal ? t.Address._toRow : -1; - } - else - { - _fromRow = t.ShowHeader ? t.Address._fromRow + 1 : t.Address._fromRow; - _toRow = t.ShowTotal ? t.Address._toRow - 1 : t.Address._toRow; - } - } + // Get Worksheet + if (address[pos] == '\'') { + int startPos = pos; + pos = address.IndexOf("'", pos + 1); + while (pos < address.Length && address[pos + 1] == '\'') { + pos = address.IndexOf("'", pos + 2); + } + _ws = address.Substring(startPos + 1, pos - startPos - 1).Replace("''", "'"); + pos++; + } else { + int startPos = pos; + pos = address.IndexOf("!", pos); + if (pos > -1) { + _ws = address.Substring(startPos, pos - startPos); + } + } - if (string.IsNullOrEmpty(Table.ColumnSpan)) - { - _fromCol = t.Address._fromCol; - _toCol = t.Address._toCol; - return; - } - else - { - var col = t.Address._fromCol; - var cols = Table.ColumnSpan.Split(':'); - foreach (var c in t.Columns) - { - if (_fromCol <= 0 && cols[0].Equals(c.Name, StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case - { - _fromCol = col; - if (cols.Length == 1) - { - _toCol = _fromCol; - return; - } - } - else if (cols.Length > 1 && _fromCol > 0 && cols[1].Equals(c.Name, StringComparison.InvariantCultureIgnoreCase)) //Issue15063 Add invariant igore case - { - _toCol = col; - return; - } + // Get Address + pos = address.IndexOf("!", pos); + if (pos > -1) { + _address = address.Substring(pos + 1); + } else { + _address = ""; + } + } - col++; - } - } - } - } + internal void ChangeWorksheet(string wsName, string newWs) { + if (_ws == wsName) { + _ws = newWs; + } + var fullAddress = GetAddress(); + + if (Addresses != null) { + foreach (var a in Addresses) { + if (a._ws == wsName) { + a._ws = newWs; + fullAddress += "," + a.GetAddress(); + } else { + fullAddress += "," + a._address; + } + } + } + _address = fullAddress; + } + + private string GetAddress() { + var adr = ""; + if (string.IsNullOrEmpty(_wb)) { + adr = "[" + _wb + "]"; + } + + if (string.IsNullOrEmpty(_ws)) { + adr += string.Format("'{0}'!", _ws); + } + adr += GetAddress(_fromRow, _fromCol, _toRow, _toCol); + return adr; + } + + private ExcelCellAddress _start; + + /// <summary> + /// Gets the row and column of the top left cell. + /// </summary> + /// <value>The start row column.</value> + public ExcelCellAddress Start { + get { + if (_start == null) { + _start = new(_fromRow, _fromCol); + } + return _start; + } + } + + private ExcelCellAddress _end; + + /// <summary> + /// Gets the row and column of the bottom right cell. + /// </summary> + /// <value>The end row column.</value> + public ExcelCellAddress End { + get { + if (_end == null) { + _end = new(_toRow, _toCol); + } + return _end; + } + } + + private ExcelTableAddress _table; + + public ExcelTableAddress Table => _table; + + /// <summary> + /// The address for the range + /// </summary> + public virtual string Address { + get { return _address; } + } + + /// <summary> + /// If the address is a defined name + /// </summary> + public bool IsName { + get { return _fromRow < 0; } + } + + /// <summary> + /// Returns the address text + /// </summary> + /// <returns></returns> + public override string ToString() { + return _address; + } + + private string _firstAddress; + + /// <summary> + /// returns the first address if the address is a multi address. + /// A1:A2,B1:B2 returns A1:A2 + /// </summary> + internal string FirstAddress { + get { + if (string.IsNullOrEmpty(_firstAddress)) { + return _address; + } + return _firstAddress; + } + } + + internal string AddressSpaceSeparated { + get { + return _address.Replace(',', ' '); //Conditional formatting and a few other places use space as separator for mulit addresses. + } + } + + /// <summary> + /// Validate the address + /// </summary> + protected void Validate() { + if (_fromRow > _toRow || _fromCol > _toCol) { + throw new ArgumentOutOfRangeException( + "Start cell Address must be less or equal to End cell address"); + } + } + + internal string WorkSheet { + get { return _ws; } + } + + protected internal List<ExcelAddress> _addresses; + + internal virtual List<ExcelAddress> Addresses { + get { return _addresses; } + } + + private bool ExtractAddress(string fullAddress) { + var brackPos = new Stack<int>(); + var bracketParts = new List<string>(); + string first = "", + second = ""; + bool isText = false, + hasSheet = false; + try { + if (fullAddress == "#REF!") { + SetAddress(ref fullAddress, ref second, ref hasSheet); + return true; + } + if (fullAddress.StartsWith("!")) { + // invalid address! + return false; + } + for (int i = 0; i < fullAddress.Length; i++) { + var c = fullAddress[i]; + if (c == '\'') { + if (isText && i + 1 < fullAddress.Length && fullAddress[i] == '\'') { + if (hasSheet) { + second += c; + } else { + first += c; + } + } + isText = !isText; + } else { + if (brackPos.Count > 0) { + if (c == '[' && !isText) { + brackPos.Push(i); + } else if (c == ']' && !isText) { + if (brackPos.Count > 0) { + var from = brackPos.Pop(); + bracketParts.Add(fullAddress.Substring(from + 1, i - from - 1)); + + if (brackPos.Count == 0) { + HandleBrackets(first, second, bracketParts); } - } - } - - /// <summary> - /// Address is an defined name - /// </summary> - /// <param name="address">the name</param> - /// <param name="isName">Should always be true</param> - internal ExcelAddressBase(string address, bool isName) - { - if (isName) - { - _address = address; - _fromRow = -1; - _fromCol = -1; - _toRow = -1; - _toCol = -1; - _start = null; - _end = null; - } - else - { - SetAddress(address); - } - } - - protected internal void SetAddress(string address) - { - address = address.Trim(); - if (address.StartsWith("'")) - { - SetWbWs(address); - } - else if (address.StartsWith("[")) //Remove any external reference - { - SetWbWs(address); - } - else - { - _address = address; - } - if(_address.IndexOfAny(new char[] {',','!', '['}) > -1) - { - //Advanced address. Including Sheet or multi or table. - ExtractAddress(_address); - } - else - { - //Simple address - GetRowColFromAddress(_address, out _fromRow, out _fromCol, out _toRow, out _toCol, out _fromRowFixed, out _fromColFixed, out _toRowFixed, out _toColFixed); - _addresses = null; - _start = null; - _end = null; - } - _address = address; - Validate(); - } - internal void ChangeAddress() - { - if (AddressChange != null) - { - AddressChange(this, new EventArgs()); - } - } - private void SetWbWs(string address) - { - int pos = 0; - - // Get Workbook, if any - if (address[pos] == '[') - { - pos = address.IndexOf("]"); - _wb = address.Substring(1, pos - 1); - pos++; - } - else - { - _wb = ""; - } - - // Get Worksheet - if (address[pos] == '\'') - { - int startPos = pos; - pos = address.IndexOf("'", pos + 1); - while (pos < address.Length && address[pos + 1] == '\'') - { - pos = address.IndexOf("'", pos + 2); - } - _ws = address.Substring(startPos + 1, pos - startPos - 1).Replace("''", "'"); - pos++; - } - else - { - int startPos = pos; - pos = address.IndexOf("!", pos); - if (pos > -1) - { - _ws = address.Substring(startPos, pos - startPos); - } - } - - // Get Address - pos = address.IndexOf("!", pos); - if (pos > -1) - { - _address = address.Substring(pos + 1); - } - else - { - _address = ""; - } - } - internal void ChangeWorksheet(string wsName, string newWs) - { - if (_ws == wsName) _ws = newWs; - var fullAddress = GetAddress(); - - if (Addresses != null) - { - foreach (var a in Addresses) - { - if (a._ws == wsName) - { - a._ws = newWs; - fullAddress += "," + a.GetAddress(); - } - else - { - fullAddress += "," + a._address; - } - } - } - _address = fullAddress; - } - - private string GetAddress() - { - var adr = ""; - if (string.IsNullOrEmpty(_wb)) - { - adr = "[" + _wb + "]"; - } - - if (string.IsNullOrEmpty(_ws)) - { - adr += string.Format("'{0}'!", _ws); - } - adr += GetAddress(_fromRow, _fromCol, _toRow, _toCol); - return adr; - } - - ExcelCellAddress _start = null; - #endregion - /// <summary> - /// Gets the row and column of the top left cell. - /// </summary> - /// <value>The start row column.</value> - public ExcelCellAddress Start - { - get - { - if (_start == null) - { - _start = new ExcelCellAddress(_fromRow, _fromCol); - } - return _start; - } - } - ExcelCellAddress _end = null; - /// <summary> - /// Gets the row and column of the bottom right cell. - /// </summary> - /// <value>The end row column.</value> - public ExcelCellAddress End - { - get - { - if (_end == null) - { - _end = new ExcelCellAddress(_toRow, _toCol); - } - return _end; - } - } - ExcelTableAddress _table=null; - public ExcelTableAddress Table - { - get - { - return _table; - } - } - - /// <summary> - /// The address for the range - /// </summary> - public virtual string Address - { - get - { - return _address; - } - } - /// <summary> - /// If the address is a defined name - /// </summary> - public bool IsName - { - get - { - return _fromRow < 0; - } - } - /// <summary> - /// Returns the address text - /// </summary> - /// <returns></returns> - public override string ToString() - { - return _address; - } - string _firstAddress; - /// <summary> - /// returns the first address if the address is a multi address. - /// A1:A2,B1:B2 returns A1:A2 - /// </summary> - internal string FirstAddress - { - get - { - if (string.IsNullOrEmpty(_firstAddress)) - { - return _address; - } - else - { - return _firstAddress; - } - } - } - internal string AddressSpaceSeparated - { - get - { - return _address.Replace(',', ' '); //Conditional formatting and a few other places use space as separator for mulit addresses. - } - } - /// <summary> - /// Validate the address - /// </summary> - protected void Validate() - { - if (_fromRow > _toRow || _fromCol > _toCol) - { - throw new ArgumentOutOfRangeException("Start cell Address must be less or equal to End cell address"); - } - } - internal string WorkSheet - { - get - { - return _ws; - } - } - internal protected List<ExcelAddress> _addresses = null; - internal virtual List<ExcelAddress> Addresses - { - get - { - return _addresses; - } - } - - private bool ExtractAddress(string fullAddress) - { - var brackPos=new Stack<int>(); - var bracketParts=new List<string>(); - string first="", second=""; - bool isText=false, hasSheet=false; - try - { - if (fullAddress == "#REF!") - { - SetAddress(ref fullAddress, ref second, ref hasSheet); - return true; - } - else if (fullAddress.StartsWith("!")) - { - // invalid address! - return false; - } - for (int i = 0; i < fullAddress.Length; i++) - { - var c = fullAddress[i]; - if (c == '\'') - { - if (isText && i + 1 < fullAddress.Length && fullAddress[i] == '\'') - { - if (hasSheet) - { - second += c; - } - else - { - first += c; - } - } - isText = !isText; - } - else - { - if (brackPos.Count > 0) - { - if (c == '[' && !isText) - { - brackPos.Push(i); - } - else if (c == ']' && !isText) - { - if (brackPos.Count > 0) - { - var from = brackPos.Pop(); - bracketParts.Add(fullAddress.Substring(from + 1, i - from - 1)); - - if (brackPos.Count == 0) - { - HandleBrackets(first, second, bracketParts); - } - } - else - { - //Invalid address! - return false; - } - } - } - else if (c == '[' && !isText) - { - brackPos.Push(i); - } - else if (c == '!' && !isText && !first.EndsWith("#REF") && !second.EndsWith("#REF")) - { - hasSheet = true; - } - else if (c == ',' && !isText) - { - SetAddress(ref first, ref second, ref hasSheet); - } - else - { - if (hasSheet) - { - second += c; - } - else - { - first += c; - } - } - } - } - if (Table == null) - { - SetAddress(ref first, ref second, ref hasSheet); - } - return true; - } - catch - { + } else { + //Invalid address! return false; + } } + } else if (c == '[' && !isText) { + brackPos.Push(i); + } else if (c == '!' && !isText && !first.EndsWith("#REF") && !second.EndsWith("#REF")) { + hasSheet = true; + } else if (c == ',' && !isText) { + SetAddress(ref first, ref second, ref hasSheet); + } else { + if (hasSheet) { + second += c; + } else { + first += c; + } + } } + } + if (Table == null) { + SetAddress(ref first, ref second, ref hasSheet); + } + return true; + } catch { + return false; + } + } - private void HandleBrackets(string first, string second, List<string> bracketParts) - { - if(!string.IsNullOrEmpty(first)) - { - _table = new ExcelTableAddress(); - Table.Name = first; - foreach (var s in bracketParts) - { - if(s.IndexOf("[")<0) - { - switch(s.ToLower(CultureInfo.InvariantCulture)) - { - case "#all": - _table.IsAll = true; - break; - case "#headers": - _table.IsHeader = true; - break; - case "#data": - _table.IsData = true; - break; - case "#totals": - _table.IsTotals = true; - break; - case "#this row": - _table.IsThisRow = true; - break; - default: - if(string.IsNullOrEmpty(_table.ColumnSpan)) - { - _table.ColumnSpan=s; - } - else - { - _table.ColumnSpan += ":" + s; - } - break; - } - } - } - } + private void HandleBrackets(string first, string second, List<string> bracketParts) { + if (!string.IsNullOrEmpty(first)) { + _table = new(); + Table.Name = first; + foreach (var s in bracketParts) { + if (s.IndexOf("[") < 0) { + switch (s.ToLower(CultureInfo.InvariantCulture)) { + case "#all": + _table.IsAll = true; + break; + case "#headers": + _table.IsHeader = true; + break; + case "#data": + _table.IsData = true; + break; + case "#totals": + _table.IsTotals = true; + break; + case "#this row": + _table.IsThisRow = true; + break; + default: + if (string.IsNullOrEmpty(_table.ColumnSpan)) { + _table.ColumnSpan = s; + } else { + _table.ColumnSpan += ":" + s; + } + break; + } } - #region Address manipulation methods - internal eAddressCollition Collide(ExcelAddressBase address) - { - if (address.WorkSheet != WorkSheet && address.WorkSheet!=null) - { - return eAddressCollition.No; - } + } + } + } - if (address._fromRow > _toRow || address._fromCol > _toCol - || - _fromRow > address._toRow || _fromCol > address._toCol) - { - return eAddressCollition.No; - } - else if (address._fromRow == _fromRow && address._fromCol == _fromCol && - address._toRow == _toRow && address._toCol == _toCol) - { - return eAddressCollition.Equal; - } - else if (address._fromRow >= _fromRow && address._toRow <= _toRow && - address._fromCol >= _fromCol && address._toCol <= _toCol) - { - return eAddressCollition.Inside; - } - else - return eAddressCollition.Partly; - } - internal ExcelAddressBase AddRow(int row, int rows, bool setFixed=false) - { - if (row > _toRow) - { - return this; - } - else if (row <= _fromRow) - { - return new ExcelAddressBase((setFixed && _fromRowFixed ? _fromRow : _fromRow + rows), _fromCol, (setFixed && _toRowFixed ? _toRow : _toRow + rows), _toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - else - { - return new ExcelAddressBase(_fromRow, _fromCol, (setFixed && _toRowFixed ? _toRow : _toRow + rows), _toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - } - internal ExcelAddressBase DeleteRow(int row, int rows, bool setFixed = false) - { - if (row > _toRow) //After - { - return this; - } - else if (row+rows <= _fromRow) //Before - { - return new ExcelAddressBase((setFixed && _fromRowFixed ? _fromRow : _fromRow - rows), _fromCol, (setFixed && _toRowFixed ? _toRow : _toRow - rows), _toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - else if (row <= _fromRow && row + rows > _toRow) //Inside - { - return null; - } - else //Partly - { - if (row <= _fromRow) - { - return new ExcelAddressBase(row, _fromCol, (setFixed && _toRowFixed ? _toRow : _toRow - rows), _toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - else - { - return new ExcelAddressBase(_fromRow, _fromCol, (setFixed && _toRowFixed ? _toRow : _toRow - rows < row ? row - 1 : _toRow - rows), _toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - } - } - internal ExcelAddressBase AddColumn(int col, int cols, bool setFixed = false) - { - if (col > _toCol) - { - return this; - } - else if (col <= _fromCol) - { - return new ExcelAddressBase(_fromRow, (setFixed && _fromColFixed ? _fromCol : _fromCol + cols), _toRow, (setFixed && _toColFixed ? _toCol : _toCol + cols), _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - else - { - return new ExcelAddressBase(_fromRow, _fromCol, _toRow, (setFixed && _toColFixed ? _toCol : _toCol + cols), _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - } - internal ExcelAddressBase DeleteColumn(int col, int cols, bool setFixed = false) - { - if (col > _toCol) //After - { - return this; - } - else if (col + cols <= _fromCol) //Before - { - return new ExcelAddressBase(_fromRow, (setFixed && _fromColFixed ? _fromCol : _fromCol - cols), _toRow, (setFixed && _toColFixed ? _toCol :_toCol - cols), _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - else if (col <= _fromCol && col + cols > _toCol) //Inside - { - return null; - } - else //Partly - { - if (col <= _fromCol) - { - return new ExcelAddressBase(_fromRow, col, _toRow, (setFixed && _toColFixed ? _toCol : _toCol - cols), _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - else - { - return new ExcelAddressBase(_fromRow, _fromCol, _toRow, (setFixed && _toColFixed ? _toCol :_toCol - cols < col ? col - 1 : _toCol - cols), _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - } - } - internal ExcelAddressBase Insert(ExcelAddressBase address, eShiftType Shift/*, out ExcelAddressBase topAddress, out ExcelAddressBase leftAddress, out ExcelAddressBase rightAddress, out ExcelAddressBase bottomAddress*/) - { - //Before or after, no change - //if ((_toRow > address._fromRow && _toCol > address.column) || - // (_fromRow > address._toRow && column > address._toCol)) - if(_toRow < address._fromRow || _toCol < address._fromCol || (_fromRow > address._toRow && _fromCol > address._toCol)) - { - //topAddress = null; - //leftAddress = null; - //rightAddress = null; - //bottomAddress = null; - return this; - } + internal eAddressCollition Collide(ExcelAddressBase address) { + if (address.WorkSheet != WorkSheet && address.WorkSheet != null) { + return eAddressCollition.No; + } - int rows = address.Rows; - int cols = address.Columns; - string retAddress = ""; - if (Shift==eShiftType.Right) - { - if (address._fromRow > _fromRow) - { - retAddress = GetAddress(_fromRow, _fromCol, address._fromRow, _toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - if(address._fromCol > _fromCol) - { - retAddress = GetAddress(_fromRow < address._fromRow ? _fromRow : address._fromRow, _fromCol, address._fromRow, _toCol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - } - } - if (_toRow < address._fromRow) - { - if (_fromRow < address._fromRow) - { + if (address._fromRow > _toRow + || address._fromCol > _toCol + || _fromRow > address._toRow + || _fromCol > address._toCol) { + return eAddressCollition.No; + } + if (address._fromRow == _fromRow + && address._fromCol == _fromCol + && address._toRow == _toRow + && address._toCol == _toCol) { + return eAddressCollition.Equal; + } + if (address._fromRow >= _fromRow + && address._toRow <= _toRow + && address._fromCol >= _fromCol + && address._toCol <= _toCol) { + return eAddressCollition.Inside; + } + return eAddressCollition.Partly; + } - } - else - { - } - } - return null; + internal ExcelAddressBase AddRow(int row, int rows, bool setFixed = false) { + if (row > _toRow) { + return this; + } + if (row <= _fromRow) { + return new( + (setFixed && _fromRowFixed ? _fromRow : _fromRow + rows), + _fromCol, + (setFixed && _toRowFixed ? _toRow : _toRow + rows), + _toCol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + return new( + _fromRow, + _fromCol, + (setFixed && _toRowFixed ? _toRow : _toRow + rows), + _toCol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + + internal ExcelAddressBase DeleteRow(int row, int rows, bool setFixed = false) { + if (row + > _toRow) //After + { + return this; + } + if (row + rows + <= _fromRow) //Before + { + return new( + (setFixed && _fromRowFixed ? _fromRow : _fromRow - rows), + _fromCol, + (setFixed && _toRowFixed ? _toRow : _toRow - rows), + _toCol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + if (row <= _fromRow + && row + rows + > _toRow) //Inside + { + return null; + } //Partly + if (row <= _fromRow) { + return new( + row, + _fromCol, + (setFixed && _toRowFixed ? _toRow : _toRow - rows), + _toCol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + return new( + _fromRow, + _fromCol, + (setFixed && _toRowFixed + ? _toRow + : _toRow - rows < row + ? row - 1 + : _toRow - rows), + _toCol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + + internal ExcelAddressBase AddColumn(int col, int cols, bool setFixed = false) { + if (col > _toCol) { + return this; + } + if (col <= _fromCol) { + return new( + _fromRow, + (setFixed && _fromColFixed ? _fromCol : _fromCol + cols), + _toRow, + (setFixed && _toColFixed ? _toCol : _toCol + cols), + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + return new( + _fromRow, + _fromCol, + _toRow, + (setFixed && _toColFixed ? _toCol : _toCol + cols), + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + + internal ExcelAddressBase DeleteColumn(int col, int cols, bool setFixed = false) { + if (col + > _toCol) //After + { + return this; + } + if (col + cols + <= _fromCol) //Before + { + return new( + _fromRow, + (setFixed && _fromColFixed ? _fromCol : _fromCol - cols), + _toRow, + (setFixed && _toColFixed ? _toCol : _toCol - cols), + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + if (col <= _fromCol + && col + cols + > _toCol) //Inside + { + return null; + } //Partly + if (col <= _fromCol) { + return new( + _fromRow, + col, + _toRow, + (setFixed && _toColFixed ? _toCol : _toCol - cols), + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + return new( + _fromRow, + _fromCol, + _toRow, + (setFixed && _toColFixed + ? _toCol + : _toCol - cols < col + ? col - 1 + : _toCol - cols), + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + + internal ExcelAddressBase Insert( + ExcelAddressBase address, + eShiftType shift /*, out ExcelAddressBase topAddress, out ExcelAddressBase leftAddress, out ExcelAddressBase rightAddress, out ExcelAddressBase bottomAddress*/) { + //Before or after, no change + //if ((_toRow > address._fromRow && _toCol > address.column) || + // (_fromRow > address._toRow && column > address._toCol)) + if (_toRow < address._fromRow + || _toCol < address._fromCol + || (_fromRow > address._toRow && _fromCol > address._toCol)) { + //topAddress = null; + //leftAddress = null; + //rightAddress = null; + //bottomAddress = null; + return this; + } + + int rows = address.Rows; + int cols = address.Columns; + string retAddress = ""; + if (shift == eShiftType.Right) { + if (address._fromRow > _fromRow) { + retAddress = GetAddress( + _fromRow, + _fromCol, + address._fromRow, + _toCol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + if (address._fromCol > _fromCol) { + retAddress = GetAddress( + _fromRow < address._fromRow ? _fromRow : address._fromRow, + _fromCol, + address._fromRow, + _toCol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + } + } + if (_toRow < address._fromRow) { + if (_fromRow < address._fromRow) {} + } + return null; + } + + private void SetAddress(ref string first, ref string second, ref bool hasSheet) { + string ws, + address; + if (hasSheet) { + ws = first; + address = second; + first = ""; + second = ""; + } else { + address = first; + ws = ""; + first = ""; + } + hasSheet = false; + if (string.IsNullOrEmpty(_firstAddress)) { + if (string.IsNullOrEmpty(_ws) || !string.IsNullOrEmpty(ws)) { + _ws = ws; + } + _firstAddress = address; + GetRowColFromAddress( + address, + out _fromRow, + out _fromCol, + out _toRow, + out _toCol, + out _fromRowFixed, + out _fromColFixed, + out _toRowFixed, + out _toColFixed); + } else { + if (_addresses == null) { + _addresses = new(); + } + _addresses.Add(new(_ws, address)); + } + } + + internal enum AddressType { + Invalid, + InternalAddress, + ExternalAddress, + InternalName, + ExternalName, + Formula, + } + + internal static AddressType IsValid(string address) { + double d; + if (address == "#REF!") { + return AddressType.Invalid; + } + if (double.TryParse( + address, + NumberStyles.Any, + CultureInfo.InvariantCulture, + out d)) //A double, no valid address + { + return AddressType.Invalid; + } + if (IsFormula(address)) { + return AddressType.Formula; + } + string wb, + ws, + intAddress; + if (SplitAddress(address, out wb, out ws, out intAddress)) { + if (intAddress.Contains( + "[")) //Table reference + { + return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress; + } + if (intAddress.Contains(",")) { + intAddress = intAddress.Substring(0, intAddress.IndexOf(',')); + } + if (IsAddress(intAddress)) { + return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress; + } + return string.IsNullOrEmpty(wb) ? AddressType.InternalName : AddressType.ExternalName; + } + return AddressType.Invalid; + + //if(string.IsNullOrEmpty(wb)); + //ExcelAddress a = new ExcelAddress(Address); + //if (Address.IndexOf('!') > 0) + //{ + // string[] split = Address.Split('!'); + // if (split.Length == 2) + // { + // ws = split[0]; + // Address = split[1]; + // } + // else if (split.Length == 3 && split[1] == "#REF" && split[2] == "") + // { + // ws = split[0]; + // Address = "#REF!"; + // if (ws.StartsWith("[") && ws.IndexOf("]") > 1) + // { + // return AddressType.ExternalAddress; + // } + // else + // { + // return AddressType.InternalAddress; + // } + // } + // else + // { + // return AddressType.Invalid; + // } + //} + //int _fromRow, column, _toRow, _toCol; + //if (ExcelAddressBase.GetRowColFromAddress(Address, out _fromRow, out column, out _toRow, out _toCol)) + //{ + // if (_fromRow > 0 && column > 0 && _toRow <= ExcelPackage.MaxRows && _toCol <= ExcelPackage.MaxColumns) + // { + // if (ws.StartsWith("[") && ws.IndexOf("]") > 1) + // { + // return AddressType.ExternalAddress; + // } + // else + // { + // return AddressType.InternalAddress; + // } + // } + // else + // { + // return AddressType.Invalid; + // } + //} + //else + //{ + // if(IsValidName(Address)) + // { + // if (ws.StartsWith("[") && ws.IndexOf("]") > 1) + // { + // return AddressType.ExternalName; + // } + // else + // { + // return AddressType.InternalName; + // } + // } + // else + // { + // return AddressType.Invalid; + // } + //} + } + + private static bool IsAddress(string intAddress) { + if (string.IsNullOrEmpty(intAddress)) { + return false; + } + var cells = intAddress.Split(':'); + int fromRow, + toRow, + fromCol, + toCol; + + if (!GetRowCol(cells[0], out fromRow, out fromCol, false)) { + return false; + } + if (cells.Length > 1) { + if (!GetRowCol(cells[1], out toRow, out toCol, false)) { + return false; + } + } else { + toRow = fromRow; + toCol = fromCol; + } + if (fromRow <= toRow + && fromCol <= toCol + && fromCol > -1 + && toCol <= ExcelPackage.MaxColumns + && fromRow > -1 + && toRow <= ExcelPackage.MaxRows) { + return true; + } + return false; + } + + private static bool SplitAddress( + string address, + out string wb, + out string ws, + out string intAddress) { + wb = ""; + ws = ""; + intAddress = ""; + var text = ""; + bool isText = false; + var brackPos = -1; + for (int i = 0; i < address.Length; i++) { + if (address[i] == '\'') { + isText = !isText; + if (i > 0 && address[i - 1] == '\'') { + text += "'"; } - #endregion - private void SetAddress(ref string first, ref string second, ref bool hasSheet) - { - string ws, address; - if (hasSheet) - { - ws = first; - address = second; - first = ""; - second = ""; - } - else - { - address = first; - ws = ""; - first = ""; - } - hasSheet = false; - if (string.IsNullOrEmpty(_firstAddress)) - { - if(string.IsNullOrEmpty(_ws) || !string.IsNullOrEmpty(ws)) _ws = ws; - _firstAddress = address; - GetRowColFromAddress(address, out _fromRow, out _fromCol, out _toRow, out _toCol, out _fromRowFixed, out _fromColFixed, out _toRowFixed, out _toColFixed); - } - else - { - if (_addresses == null) _addresses = new List<ExcelAddress>(); - _addresses.Add(new ExcelAddress(_ws, address)); - } + } else { + if (address[i] == '!' && !isText) { + if (text.Length > 0 && text[0] == '[') { + wb = text.Substring(1, text.IndexOf("]") - 1); + ws = text.Substring(text.IndexOf("]") + 1); + } else { + ws = text; + } + intAddress = address.Substring(i + 1); + return true; } - internal enum AddressType - { - Invalid, - InternalAddress, - ExternalAddress, - InternalName, - ExternalName, - Formula - } - - internal static AddressType IsValid(string Address) - { - double d; - if (Address == "#REF!") - { - return AddressType.Invalid; - } - else if(double.TryParse(Address, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) //A double, no valid address - { - return AddressType.Invalid; - } - else if (IsFormula(Address)) - { - return AddressType.Formula; - } - else - { - string wb, ws, intAddress; - if(SplitAddress(Address, out wb, out ws, out intAddress)) - { - if(intAddress.Contains("[")) //Table reference - { - return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress; - } - else if(intAddress.Contains(",")) - { - intAddress=intAddress.Substring(0, intAddress.IndexOf(',')); - } - if(IsAddress(intAddress)) - { - return string.IsNullOrEmpty(wb) ? AddressType.InternalAddress : AddressType.ExternalAddress; - } - else - { - return string.IsNullOrEmpty(wb) ? AddressType.InternalName : AddressType.ExternalName; - } - } - else - { - return AddressType.Invalid; - } - - //if(string.IsNullOrEmpty(wb)); - - } - //ExcelAddress a = new ExcelAddress(Address); - //if (Address.IndexOf('!') > 0) - //{ - // string[] split = Address.Split('!'); - // if (split.Length == 2) - // { - // ws = split[0]; - // Address = split[1]; - // } - // else if (split.Length == 3 && split[1] == "#REF" && split[2] == "") - // { - // ws = split[0]; - // Address = "#REF!"; - // if (ws.StartsWith("[") && ws.IndexOf("]") > 1) - // { - // return AddressType.ExternalAddress; - // } - // else - // { - // return AddressType.InternalAddress; - // } - // } - // else - // { - // return AddressType.Invalid; - // } - //} - //int _fromRow, column, _toRow, _toCol; - //if (ExcelAddressBase.GetRowColFromAddress(Address, out _fromRow, out column, out _toRow, out _toCol)) - //{ - // if (_fromRow > 0 && column > 0 && _toRow <= ExcelPackage.MaxRows && _toCol <= ExcelPackage.MaxColumns) - // { - // if (ws.StartsWith("[") && ws.IndexOf("]") > 1) - // { - // return AddressType.ExternalAddress; - // } - // else - // { - // return AddressType.InternalAddress; - // } - // } - // else - // { - // return AddressType.Invalid; - // } - //} - //else - //{ - // if(IsValidName(Address)) - // { - // if (ws.StartsWith("[") && ws.IndexOf("]") > 1) - // { - // return AddressType.ExternalName; - // } - // else - // { - // return AddressType.InternalName; - // } - // } - // else - // { - // return AddressType.Invalid; - // } - //} - - } - - private static bool IsAddress(string intAddress) - { - if(string.IsNullOrEmpty(intAddress)) return false; - var cells = intAddress.Split(':'); - int fromRow,toRow, fromCol, toCol; - - if(!GetRowCol(cells[0], out fromRow, out fromCol, false)) - { - return false; - } - if (cells.Length > 1) - { - if (!GetRowCol(cells[1], out toRow, out toCol, false)) - { - return false; - } - } - else - { - toRow = fromRow; - toCol = fromCol; - } - if( fromRow <= toRow && - fromCol <= toCol && - fromCol > -1 && - toCol <= ExcelPackage.MaxColumns && - fromRow > -1 && - toRow <= ExcelPackage.MaxRows) - { - return true; - } - else - { - return false; - } - } - - private static bool SplitAddress(string Address, out string wb, out string ws, out string intAddress) - { - wb = ""; - ws = ""; - intAddress = ""; - var text = ""; - bool isText = false; - var brackPos=-1; - for (int i = 0; i < Address.Length; i++) - { - if (Address[i] == '\'') - { - isText = !isText; - if(i>0 && Address[i-1]=='\'') - { - text += "'"; - } - } - else - { - if(Address[i]=='!' && !isText) - { - if (text.Length>0 && text[0] == '[') - { - wb = text.Substring(1, text.IndexOf("]") - 1); - ws = text.Substring(text.IndexOf("]") + 1); - } - else - { - ws=text; - } - intAddress=Address.Substring(i+1); - return true; - } - else - { - if(Address[i]=='[' && !isText) - { - if (i > 0) //Table reference return full address; - { - intAddress=Address; - return true; - } - brackPos=i; - } - else if(Address[i]==']' && !isText) - { - if (brackPos > -1) - { - wb = text; - text = ""; - } - else - { - return false; - } - } - else - { - text+=Address[i]; - } - } - } - } - intAddress = text; + if (address[i] == '[' && !isText) { + if (i + > 0) //Table reference return full address; + { + intAddress = address; return true; - } - - private static bool IsFormula(string address) - { - var isText = false; - for (int i = 0; i < address.Length; i++) - { - if (address[i] == '\'') - { - isText = !isText; - } - else - { - if (isText==false && address.Substring(i, 1).IndexOfAny(new char[] { '(', ')', '+', '-', '*', '/', '.', '=', '^', '&', '%', '\"' }) > -1) - { - return true; - } - } - } + } + brackPos = i; + } else if (address[i] == ']' && !isText) { + if (brackPos > -1) { + wb = text; + text = ""; + } else { return false; + } + } else { + text += address[i]; } - - private static bool IsValidName(string address) - { - if (Regex.IsMatch(address, "[^0-9./*-+,½!\"@#£%&/{}()\\[\\]=?`^~':;<>|][^/*-+,½!\"@#£%&/{}()\\[\\]=?`^~':;<>|]*")) - { - return true; - } - else - { - return false; - } - } - - public int Rows - { - get - { - return _toRow - _fromRow+1; - } - } - public int Columns - { - get - { - return _toCol - _fromCol + 1; - } - } - - internal bool IsMultiCell() - { - return (_fromRow < _fromCol || _fromCol < _toCol); - } - internal static String GetWorkbookPart(string address) - { - var ix = 0; - if (address[0] == '[') - { - ix = address.IndexOf(']') + 1; - if (ix > 0) - { - return address.Substring(1, ix - 2); - } - } - return ""; - } - internal static string GetWorksheetPart(string address, string defaultWorkSheet) - { - int ix=0; - return GetWorksheetPart(address, defaultWorkSheet, ref ix); - } - internal static string GetWorksheetPart(string address, string defaultWorkSheet, ref int endIx) - { - if(address=="") return defaultWorkSheet; - var ix = 0; - if (address[0] == '[') - { - ix = address.IndexOf(']')+1; - } - if (ix > 0 && ix < address.Length) - { - if (address[ix] == '\'') - { - return GetString(address, ix, out endIx); - } - else - { - var ixEnd = address.IndexOf('!',ix); - if(ixEnd>ix) - { - return address.Substring(ix, ixEnd-ix); - } - else - { - return defaultWorkSheet; - } - } - } - else - { - return defaultWorkSheet; - } - } - internal static string GetAddressPart(string address) - { - var ix=0; - GetWorksheetPart(address, "", ref ix); - if(ix<address.Length) - { - if (address[ix] == '!') - { - return address.Substring(ix + 1); - } - else - { - return ""; - } - } - else - { - return ""; - } - - } - internal static void SplitAddress(string fullAddress, out string wb, out string ws, out string address, string defaultWorksheet="") - { - wb = GetWorkbookPart(fullAddress); - int ix=0; - ws = GetWorksheetPart(fullAddress, defaultWorksheet, ref ix); - if (ix < fullAddress.Length) - { - if (fullAddress[ix] == '!') - { - address = fullAddress.Substring(ix + 1); - } - else - { - address = fullAddress.Substring(ix); - } - } - else - { - address=""; - } - } - private static string GetString(string address, int ix, out int endIx) - { - var strIx = address.IndexOf("''"); - var prevStrIx = ix; - while(strIx > -1) - { - prevStrIx = strIx; - strIx = address.IndexOf("''"); - } - endIx = address.IndexOf("'"); - return address.Substring(ix, endIx - ix).Replace("''","'"); - } - - internal bool IsValidRowCol() - { - return !(_fromRow > _toRow || - _fromCol > _toCol || - _fromRow < 1 || - _fromCol < 1 || - _toRow > ExcelPackage.MaxRows || - _toCol > ExcelPackage.MaxColumns); - } + } } - /// <summary> - /// Range address with the address property readonly - /// </summary> - public class ExcelAddress : ExcelAddressBase - { - internal ExcelAddress() - : base() - { + intAddress = text; + return true; + } + private static bool IsFormula(string address) { + var isText = false; + for (int i = 0; i < address.Length; i++) { + if (address[i] == '\'') { + isText = !isText; + } else { + if (isText == false + && address + .Substring(i, 1) + .IndexOfAny(new[] { '(', ')', '+', '-', '*', '/', '.', '=', '^', '&', '%', '\"' }) + > -1) { + return true; } - - public ExcelAddress(int fromRow, int fromCol, int toRow, int toColumn) - : base(fromRow, fromCol, toRow, toColumn) - { - _ws = ""; - } - public ExcelAddress(string address) - : base(address) - { - } - - internal ExcelAddress(string ws, string address) - : base(address) - { - if (string.IsNullOrEmpty(_ws)) _ws = ws; - } - internal ExcelAddress(string ws, string address, bool isName) - : base(address, isName) - { - if (string.IsNullOrEmpty(_ws)) _ws = ws; - } - - public ExcelAddress(string Address, ExcelPackage package, ExcelAddressBase referenceAddress) : - base(Address, package, referenceAddress) - { - - } - /// <summary> - /// The address for the range - /// </summary> - /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> - public new string Address - { - get - { - if (string.IsNullOrEmpty(_address) && _fromRow>0) - { - _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol); - } - return _address; - } - set - { - SetAddress(value); - base.ChangeAddress(); - } - } + } } - public class ExcelFormulaAddress : ExcelAddressBase - { - bool _fromRowFixed, _toRowFixed, _fromColFixed, _toColFixed; - internal ExcelFormulaAddress() - : base() - { - } + return false; + } - public ExcelFormulaAddress(int fromRow, int fromCol, int toRow, int toColumn) - : base(fromRow, fromCol, toRow, toColumn) - { - _ws = ""; - } - public ExcelFormulaAddress(string address) - : base(address) - { - SetFixed(); - } - - internal ExcelFormulaAddress(string ws, string address) - : base(address) - { - if (string.IsNullOrEmpty(_ws)) _ws = ws; - SetFixed(); - } - internal ExcelFormulaAddress(string ws, string address, bool isName) - : base(address, isName) - { - if (string.IsNullOrEmpty(_ws)) _ws = ws; - if(!isName) - SetFixed(); - } - - private void SetFixed() - { - if (Address.IndexOf("[") >= 0) return; - var address=FirstAddress; - if(_fromRow==_toRow && _fromCol==_toCol) - { - GetFixed(address, out _fromRowFixed, out _fromColFixed); - } - else - { - var cells = address.Split(':'); - GetFixed(cells[0], out _fromRowFixed, out _fromColFixed); - GetFixed(cells[1], out _toRowFixed, out _toColFixed); - } - } - - private void GetFixed(string address, out bool rowFixed, out bool colFixed) - { - rowFixed=colFixed=false; - var ix=address.IndexOf('$'); - while(ix>-1) - { - ix++; - if(ix < address.Length) - { - if(address[ix]>='0' && address[ix]<='9') - { - rowFixed=true; - break; - } - else - { - colFixed=true; - } - } - ix = address.IndexOf('$', ix); - } - } - /// <summary> - /// The address for the range - /// </summary> - /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> - public new string Address - { - get - { - if (string.IsNullOrEmpty(_address) && _fromRow>0) - { - _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol, _fromRowFixed, _toRowFixed, _fromColFixed, _toColFixed); - } - return _address; - } - set - { - SetAddress(value); - base.ChangeAddress(); - SetFixed(); - } - } - internal new List<ExcelFormulaAddress> _addresses; - public new List<ExcelFormulaAddress> Addresses - { - get - { - if (_addresses == null) - { - _addresses = new List<ExcelFormulaAddress>(); - } - return _addresses; - - } - } - internal string GetOffset(int row, int column) - { - int fromRow = _fromRow, fromCol = _fromCol, toRow = _toRow, tocol = _toCol; - var isMulti = (fromRow != toRow || fromCol != tocol); - if (!_fromRowFixed) - { - fromRow += row; - } - if (!_fromColFixed) - { - fromCol += column; - } - if (isMulti) - { - if (!_toRowFixed) - { - toRow += row; - } - if (!_toColFixed) - { - tocol += column; - } - } - else - { - toRow = fromRow; - tocol = fromCol; - } - string a = GetAddress(fromRow, fromCol, toRow, tocol, _fromRowFixed, _fromColFixed, _toRowFixed, _toColFixed); - if (Addresses != null) - { - foreach (var sa in Addresses) - { - a+="," + sa.GetOffset(row, column); - } - } - return a; - } + private static bool IsValidName(string address) { + if (Regex.IsMatch( + address, + "[^0-9./*-+,½!\"@#£%&/{}()\\[\\]=?`^~':;<>|][^/*-+,½!\"@#£%&/{}()\\[\\]=?`^~':;<>|]*")) { + return true; } + return false; + } + + public int Rows { + get { return _toRow - _fromRow + 1; } + } + + public int Columns { + get { return _toCol - _fromCol + 1; } + } + + internal bool IsMultiCell() { + return (_fromRow < _fromCol || _fromCol < _toCol); + } + + internal static String GetWorkbookPart(string address) { + var ix = 0; + if (address[0] == '[') { + ix = address.IndexOf(']') + 1; + if (ix > 0) { + return address.Substring(1, ix - 2); + } + } + return ""; + } + + internal static string GetWorksheetPart(string address, string defaultWorkSheet) { + int ix = 0; + return GetWorksheetPart(address, defaultWorkSheet, ref ix); + } + + internal static string GetWorksheetPart(string address, string defaultWorkSheet, ref int endIx) { + if (address == "") { + return defaultWorkSheet; + } + var ix = 0; + if (address[0] == '[') { + ix = address.IndexOf(']') + 1; + } + if (ix > 0 && ix < address.Length) { + if (address[ix] == '\'') { + return GetString(address, ix, out endIx); + } + var ixEnd = address.IndexOf('!', ix); + if (ixEnd > ix) { + return address.Substring(ix, ixEnd - ix); + } + return defaultWorkSheet; + } + return defaultWorkSheet; + } + + internal static string GetAddressPart(string address) { + var ix = 0; + GetWorksheetPart(address, "", ref ix); + if (ix < address.Length) { + if (address[ix] == '!') { + return address.Substring(ix + 1); + } + return ""; + } + return ""; + } + + internal static void SplitAddress( + string fullAddress, + out string wb, + out string ws, + out string address, + string defaultWorksheet = "") { + wb = GetWorkbookPart(fullAddress); + int ix = 0; + ws = GetWorksheetPart(fullAddress, defaultWorksheet, ref ix); + if (ix < fullAddress.Length) { + if (fullAddress[ix] == '!') { + address = fullAddress.Substring(ix + 1); + } else { + address = fullAddress.Substring(ix); + } + } else { + address = ""; + } + } + + private static string GetString(string address, int ix, out int endIx) { + var strIx = address.IndexOf("''"); + var prevStrIx = ix; + while (strIx > -1) { + prevStrIx = strIx; + strIx = address.IndexOf("''"); + } + endIx = address.IndexOf("'"); + return address.Substring(ix, endIx - ix).Replace("''", "'"); + } + + internal bool IsValidRowCol() { + return !(_fromRow > _toRow + || _fromCol > _toCol + || _fromRow < 1 + || _fromCol < 1 + || _toRow > ExcelPackage.MaxRows + || _toCol > ExcelPackage.MaxColumns); + } +} + +/// <summary> +/// Range address with the address property readonly +/// </summary> +public class ExcelAddress : ExcelAddressBase { + internal ExcelAddress() {} + + public ExcelAddress(int fromRow, int fromCol, int toRow, int toColumn) + : base(fromRow, fromCol, toRow, toColumn) { + _ws = ""; + } + + public ExcelAddress(string address) + : base(address) {} + + internal ExcelAddress(string ws, string address) + : base(address) { + if (string.IsNullOrEmpty(_ws)) { + _ws = ws; + } + } + + internal ExcelAddress(string ws, string address, bool isName) + : base(address, isName) { + if (string.IsNullOrEmpty(_ws)) { + _ws = ws; + } + } + + public ExcelAddress(string address, ExcelPackage package, ExcelAddressBase referenceAddress) + : base(address, package, referenceAddress) {} + + /// <summary> + /// The address for the range + /// </summary> + /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> + public new string Address { + get { + if (string.IsNullOrEmpty(_address) && _fromRow > 0) { + _address = GetAddress(_fromRow, _fromCol, _toRow, _toCol); + } + return _address; + } + set { + SetAddress(value); + ChangeAddress(); + } + } +} + +public class ExcelFormulaAddress : ExcelAddressBase { + private bool _fromRowFixed, + _toRowFixed, + _fromColFixed, + _toColFixed; + + internal ExcelFormulaAddress() {} + + public ExcelFormulaAddress(int fromRow, int fromCol, int toRow, int toColumn) + : base(fromRow, fromCol, toRow, toColumn) { + _ws = ""; + } + + public ExcelFormulaAddress(string address) + : base(address) { + SetFixed(); + } + + internal ExcelFormulaAddress(string ws, string address) + : base(address) { + if (string.IsNullOrEmpty(_ws)) { + _ws = ws; + } + SetFixed(); + } + + internal ExcelFormulaAddress(string ws, string address, bool isName) + : base(address, isName) { + if (string.IsNullOrEmpty(_ws)) { + _ws = ws; + } + if (!isName) { + SetFixed(); + } + } + + private void SetFixed() { + if (Address.IndexOf("[") >= 0) { + return; + } + var address = FirstAddress; + if (_fromRow == _toRow && _fromCol == _toCol) { + GetFixed(address, out _fromRowFixed, out _fromColFixed); + } else { + var cells = address.Split(':'); + GetFixed(cells[0], out _fromRowFixed, out _fromColFixed); + GetFixed(cells[1], out _toRowFixed, out _toColFixed); + } + } + + private void GetFixed(string address, out bool rowFixed, out bool colFixed) { + rowFixed = colFixed = false; + var ix = address.IndexOf('$'); + while (ix > -1) { + ix++; + if (ix < address.Length) { + if (address[ix] >= '0' && address[ix] <= '9') { + rowFixed = true; + break; + } + colFixed = true; + } + ix = address.IndexOf('$', ix); + } + } + + /// <summary> + /// The address for the range + /// </summary> + /// <remarks>Examples of addresses are "A1" "B1:C2" "A:A" "1:1" "A1:E2,G3:G5" </remarks> + public new string Address { + get { + if (string.IsNullOrEmpty(_address) && _fromRow > 0) { + _address = GetAddress( + _fromRow, + _fromCol, + _toRow, + _toCol, + _fromRowFixed, + _toRowFixed, + _fromColFixed, + _toColFixed); + } + return _address; + } + set { + SetAddress(value); + ChangeAddress(); + SetFixed(); + } + } + + internal new List<ExcelFormulaAddress> _addresses; + + public new List<ExcelFormulaAddress> Addresses { + get { + if (_addresses == null) { + _addresses = new(); + } + return _addresses; + } + } + + internal string GetOffset(int row, int column) { + int fromRow = _fromRow, + fromCol = _fromCol, + toRow = _toRow, + tocol = _toCol; + var isMulti = (fromRow != toRow || fromCol != tocol); + if (!_fromRowFixed) { + fromRow += row; + } + if (!_fromColFixed) { + fromCol += column; + } + if (isMulti) { + if (!_toRowFixed) { + toRow += row; + } + if (!_toColFixed) { + tocol += column; + } + } else { + toRow = fromRow; + tocol = fromCol; + } + string a = GetAddress( + fromRow, + fromCol, + toRow, + tocol, + _fromRowFixed, + _fromColFixed, + _toRowFixed, + _toColFixed); + if (Addresses != null) { + foreach (var sa in Addresses) { + a += "," + sa.GetOffset(row, column); + } + } + return a; + } }
diff --git a/EPPlus/ExcelCellAddress.cs b/EPPlus/ExcelCellAddress.cs index 99433ef..b765a73 100644 --- a/EPPlus/ExcelCellAddress.cs +++ b/EPPlus/ExcelCellAddress.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,143 +13,121 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Starnuto Di Topo & Jan Källman Initial Release 2010-03-14 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -namespace OfficeOpenXml -{ - /// <summary> - /// A single cell address - /// </summary> - public class ExcelCellAddress - { - public ExcelCellAddress() - : this(1, 1) - { +namespace OfficeOpenXml; - } +/// <summary> +/// A single cell address +/// </summary> +public class ExcelCellAddress { + public ExcelCellAddress() + : this(1, 1) {} - private int _row; - private int _column; - private string _address; - /// <summary> - /// Initializes a new instance of the ExcelCellAddress class. - /// </summary> - /// <param name="row">The row.</param> - /// <param name="column">The column.</param> - public ExcelCellAddress(int row, int column) - { - this.Row = row; - this.Column = column; - } - /// <summary> - /// Initializes a new instance of the ExcelCellAddress class. - /// </summary> - ///<param name="address">The address</param> - public ExcelCellAddress(string address) - { - this.Address = address; - } - /// <summary> - /// Row - /// </summary> - public int Row - { - get - { - return this._row; - } - private set - { - if (value <= 0) - { - throw new ArgumentOutOfRangeException("value", "Row cannot be less than 1."); - } - this._row = value; - if(_column>0) - _address = ExcelCellBase.GetAddress(_row, _column); - else - _address = "#REF!"; - } - } - /// <summary> - /// Column - /// </summary> - public int Column - { - get - { - return this._column; - } - private set - { - if (value <= 0) - { - throw new ArgumentOutOfRangeException("value", "Column cannot be less than 1."); - } - this._column = value; - if (_row > 0) - _address = ExcelCellBase.GetAddress(_row, _column); - else - _address = "#REF!"; - } - } - /// <summary> - /// Celladdress - /// </summary> - public string Address - { - get - { - return _address; - } - internal set - { - _address = value; - ExcelCellBase.GetRowColFromAddress(_address, out _row, out _column); - } - } - /// <summary> - /// If the address is an invalid reference (#REF!) - /// </summary> - public bool IsRef - { - get - { - return _row <= 0; - } - } + private int _row; + private int _column; + private string _address; - /// <summary> - /// Returns the letter corresponding to the supplied 1-based column index. - /// </summary> - /// <param name="column">Index of the column (1-based)</param> - /// <returns>The corresponding letter, like A for 1.</returns> - public static string GetColumnLetter(int column) - { - if (column > ExcelPackage.MaxColumns || column < 1) - { - throw new InvalidOperationException("Invalid 1-based column index: " + column + ". Valid range is 1 to " + ExcelPackage.MaxColumns); - } - return ExcelCellBase.GetColumnLetter(column); - } + /// <summary> + /// Initializes a new instance of the ExcelCellAddress class. + /// </summary> + /// <param name="row">The row.</param> + /// <param name="column">The column.</param> + public ExcelCellAddress(int row, int column) { + Row = row; + Column = column; + } + + /// <summary> + /// Initializes a new instance of the ExcelCellAddress class. + /// </summary> + ///<param name="address">The address</param> + public ExcelCellAddress(string address) { + Address = address; + } + + /// <summary> + /// Row + /// </summary> + public int Row { + get => _row; + private set { + if (value <= 0) { + throw new ArgumentOutOfRangeException("value", "Row cannot be less than 1."); + } + _row = value; + if (_column > 0) { + _address = ExcelCellBase.GetAddress(_row, _column); + } else { + _address = "#REF!"; + } } -} + } + /// <summary> + /// Column + /// </summary> + public int Column { + get => _column; + private set { + if (value <= 0) { + throw new ArgumentOutOfRangeException("value", "Column cannot be less than 1."); + } + _column = value; + if (_row > 0) { + _address = ExcelCellBase.GetAddress(_row, _column); + } else { + _address = "#REF!"; + } + } + } + + /// <summary> + /// Celladdress + /// </summary> + public string Address { + get => _address; + internal set { + _address = value; + ExcelCellBase.GetRowColFromAddress(_address, out _row, out _column); + } + } + + /// <summary> + /// If the address is an invalid reference (#REF!) + /// </summary> + public bool IsRef => _row <= 0; + + /// <summary> + /// Returns the letter corresponding to the supplied 1-based column index. + /// </summary> + /// <param name="column">Index of the column (1-based)</param> + /// <returns>The corresponding letter, like A for 1.</returns> + public static string GetColumnLetter(int column) { + if (column > ExcelPackage.MaxColumns || column < 1) { + throw new InvalidOperationException( + "Invalid 1-based column index: " + + column + + ". Valid range is 1 to " + + ExcelPackage.MaxColumns); + } + return ExcelCellBase.GetColumnLetter(column); + } +}
diff --git a/EPPlus/ExcelCellBase.cs b/EPPlus/ExcelCellBase.cs index e7a8f25..36e1450 100644 --- a/EPPlus/ExcelCellBase.cs +++ b/EPPlus/ExcelCellBase.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,1457 +13,1368 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Globalization; -using System.Text; -using OfficeOpenXml.Style; -using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -using System.Linq; -using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml -{ - /// <summary> - /// Base class containing cell address manipulating methods. - /// </summary> - public abstract class ExcelCellBase - { - #region "public functions" - /// <summary> - /// Get the sheet, row and column from the CellID - /// </summary> - /// <param name="cellID"></param> - /// <param name="sheet"></param> - /// <param name="row"></param> - /// <param name="col"></param> - static internal void SplitCellID(ulong cellID, out int sheet, out int row, out int col) - { - sheet = (int)(cellID % 0x8000); - col = ((int)(cellID >> 15) & 0x3FF); - row = ((int)(cellID >> 29)); - } - /// <summary> - /// Get the cellID for the cell. - /// </summary> - /// <param name="SheetID"></param> - /// <param name="row"></param> - /// <param name="col"></param> - /// <returns></returns> - internal static ulong GetCellID(int SheetID, int row, int col) - { - return ((ulong)SheetID) + (((ulong)col) << 15) + (((ulong)row) << 29); - } - #endregion - #region "Formula Functions" - private delegate string dlgTransl(string part, int row, int col, int rowIncr, int colIncr); - #region R1C1 Functions" - /// <summary> - /// Translates a R1C1 to an absolut address/Formula - /// </summary> - /// <param name="value">Address</param> - /// <param name="row">Current row</param> - /// <param name="col">Current column</param> - /// <returns>The RC address</returns> - public static string TranslateFromR1C1(string value, int row, int col) - { - return Translate(value, ToAbs, row, col, -1, -1); - } +using OfficeOpenXml.FormulaParsing.Excel.Functions; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; - /// <summary> - /// Translates a R1C1 to an absolut address/Formula: Version 1 - /// </summary> - /// <param name="value">Address</param> - /// <param name="row">Current row</param> - /// <param name="col">Current column</param> - /// <returns>The RC address</returns> - public static string TranslateFromR1C1_V1(string value, int row, int col) - { - return Translate_V1(value, ToAbs_V1, row, col, -1, -1); - } +namespace OfficeOpenXml; - /// <summary> - /// Translates a absolut address to R1C1 Format - /// </summary> - /// <param name="value">R1C1 Address</param> - /// <param name="row">Current row</param> - /// <param name="col">Current column</param> - /// <returns>The absolut address/Formula</returns> - public static string TranslateToR1C1(string value, int row, int col) - { - return Translate(value, ToR1C1, row, col, -1, -1); - } +/// <summary> +/// Base class containing cell address manipulating methods. +/// </summary> +public abstract class ExcelCellBase { + /// <summary> + /// Get the sheet, row and column from the CellID + /// </summary> + /// <param name="cellId"></param> + /// <param name="sheet"></param> + /// <param name="row"></param> + /// <param name="col"></param> + static internal void SplitCellId(ulong cellId, out int sheet, out int row, out int col) { + sheet = (int)(cellId % 0x8000); + col = ((int)(cellId >> 15) & 0x3FF); + row = ((int)(cellId >> 29)); + } - /// <summary> - /// Translates a absolute address to R1C1 Format : Version 1 - /// </summary> - /// <param name="value">R1C1 Address</param> - /// <param name="row">Current row</param> - /// <param name="col">Current column</param> - /// <returns>The absolut address/Formula</returns> - public static string TranslateToR1C1_V1(string value, int row, int col) - { - return Translate_V1(value, ToR1C1_V1, row, col, -1, -1); - } + /// <summary> + /// Get the cellID for the cell. + /// </summary> + /// <param name="sheetId"></param> + /// <param name="row"></param> + /// <param name="col"></param> + /// <returns></returns> + internal static ulong GetCellId(int sheetId, int row, int col) { + return ((ulong)sheetId) + (((ulong)col) << 15) + (((ulong)row) << 29); + } - /// <summary> - /// Translates betweein R1C1 or absolute addresses : Version 1 - /// </summary> - /// <param name="value">The addresss/function</param> - /// <param name="addressTranslator">The translating function</param> - /// <param name="row"></param> - /// <param name="col"></param> - /// <param name="rowIncr"></param> - /// <param name="colIncr"></param> - /// <returns></returns> - private static string Translate(string value, dlgTransl addressTranslator, int row, int col, int rowIncr, int colIncr) - { - if (value == "") - return ""; - bool isText = false; - string ret = ""; - string part = ""; - char prevTQ = (char)0; - for (int pos = 0; pos < value.Length; pos++) - { - char c = value[pos]; - if (c == '"' || c=='\'') - { - if (isText == true && prevTQ != c) - { - ret += c; - continue; - } + private delegate string AddressTranslator( + string part, + int row, + int col, + int rowIncr, + int colIncr); - if (isText == false && part != "" && prevTQ==c) - { - ret += addressTranslator(part, row, col, rowIncr, colIncr); - part = ""; - prevTQ = (char)0; - } - prevTQ = c; - isText = !isText; - ret += c; - } - else if (isText) - { - ret += c; - } - else - { - if ((c == '-' || c == '+' || c == '*' || c == '/' || - c == '=' || c == '^' || c == ',' || c == ':' || - c == '<' || c == '>' || c == '(' || c == ')' || c == '!' || - c == ' ' || c == '&' || c == '%') && - (pos == 0 || value[pos - 1] != '[')) //Last part to allow for R1C1 style [-x] - { - ret += addressTranslator(part, row, col, rowIncr, colIncr) + c; - part = ""; - } - else - { - part += c; - } - } - } - if (part != "") - { - ret += addressTranslator(part, row, col, rowIncr, colIncr); - } - return ret; - } + /// <summary> + /// Translates a R1C1 to an absolut address/Formula + /// </summary> + /// <param name="value">Address</param> + /// <param name="row">Current row</param> + /// <param name="col">Current column</param> + /// <returns>The RC address</returns> + public static string TranslateFromR1C1(string value, int row, int col) { + return Translate(value, ToAbs, row, col, -1, -1); + } - private static string Translate_V1(string value, dlgTransl addressTranslator, int row, int col, int rowIncr, int colIncr) - { - if (value == "") - return ""; - bool isText = false; - string ret = ""; - string part = ""; - char prevTQ = (char)0; - value = value.Replace("\n", ""); // Eliminate new line characters in the formula - for (int pos = 0; pos < value.Length; pos++) - { - char c = value[pos]; - if (c == '"' || c == '\'') - { - if (isText == true && prevTQ != c) - { - ret += c; - continue; - } + /// <summary> + /// Translates a R1C1 to an absolut address/Formula: Version 1 + /// </summary> + /// <param name="value">Address</param> + /// <param name="row">Current row</param> + /// <param name="col">Current column</param> + /// <returns>The RC address</returns> + public static string TranslateFromR1C1_V1(string value, int row, int col) { + return Translate_V1(value, ToAbs_V1, row, col, -1, -1); + } - if (isText == false && part != "" && prevTQ == c) - { - ret += addressTranslator(part, row, col, rowIncr, colIncr); - part = ""; - prevTQ = (char)0; - } - prevTQ = c; - isText = !isText; - ret += c; - } - else if (isText) - { - ret += c; - } - else if (c == ':') // Keep Range expressions together - { - part += c; - } - else - { - if ((c == '-' || c == '+' || c == '*' || c == '/' || - c == '=' || c == '^' || c == ',' || - c == '<' || c == '>' || c == '(' || c == ')' || c == '!' || - c == ' ' || c == '&' || c == '%') && - (pos == 0 || value[pos - 1] != '[')) //Last part to allow for R1C1 style [-x] - { - ret += addressTranslator(part, row, col, rowIncr, colIncr) + c; - part = ""; - } - else - { - part += c; - } - } - } - if (part != "") - { - ret += addressTranslator(part, row, col, rowIncr, colIncr); - } - return ret; - } + /// <summary> + /// Translates a absolut address to R1C1 Format + /// </summary> + /// <param name="value">R1C1 Address</param> + /// <param name="row">Current row</param> + /// <param name="col">Current column</param> + /// <returns>The absolut address/Formula</returns> + public static string TranslateToR1C1(string value, int row, int col) { + return Translate(value, ToR1C1, row, col, -1, -1); + } - /// <summary> - /// Translate to R1C1 - /// </summary> - /// <param name="part">the value to be translated</param> - /// <param name="row"></param> - /// <param name="col"></param> - /// <param name="rowIncr"></param> - /// <param name="colIncr"></param> - /// <returns></returns> - private static string ToR1C1(string part, int row, int col, int rowIncr, int colIncr) - { - int addrRow, addrCol; - string Ret = "R"; - if (GetRowCol(part, out addrRow, out addrCol, false)) - { - if (addrRow == 0 || addrCol == 0) - { - return part; - } - if (part.IndexOf('$', 1) > 0) - { - Ret += addrRow.ToString(); - } - else if (addrRow - row != 0) - { - Ret += string.Format("[{0}]", addrRow - row); - } + /// <summary> + /// Translates a absolute address to R1C1 Format : Version 1 + /// </summary> + /// <param name="value">R1C1 Address</param> + /// <param name="row">Current row</param> + /// <param name="col">Current column</param> + /// <returns>The absolut address/Formula</returns> + public static string TranslateToR1C1_V1(string value, int row, int col) { + return Translate_V1(value, ToR1C1_V1, row, col, -1, -1); + } - if (part.StartsWith("$")) - { - return Ret + "C" + addrCol; - } - else if (addrCol - col != 0) - { - return Ret + "C" + string.Format("[{0}]", addrCol - col); - } - else - { - return Ret + "C"; - } - } - else - { - return part; - } - } - - private static string ToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) - { - int addrRow, addrCol; - - // Handle range expressions - if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) - { - return RangeToR1C1_V1(part, row, col, rowIncr, colIncr); - } - - string Ret = "R"; - if (GetRowCol(part, out addrRow, out addrCol, false)) - { - if (addrRow == 0 || addrCol == 0) - { - return part; - } - if (part.IndexOf('$', 1) > 0) - { - Ret += addrRow.ToString(); - } - else if (addrRow - row != 0) - { - Ret += string.Format("[{0}]", addrRow - row); - } - - if (part.StartsWith("$")) - { - return Ret + "C" + addrCol; - } - else if (addrCol - col != 0) - { - return Ret + "C" + string.Format("[{0}]", addrCol - col); - } - else - { - return Ret + "C"; - } - } - else - { - return part; - } - } - - private static string RangeToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) - { - // Split range expression - string[] cellValues = part.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); - - // Convert range expressions - string result = ""; - result += RangeCellToR1C1_V1(cellValues[0], row, col, rowIncr, colIncr); - result += ":"; - result += (cellValues.Length > 1) ? RangeCellToR1C1_V1(cellValues[1], row, col, rowIncr, colIncr) : ""; - - // Return converted range expression - return result; - } - - private static string RangeCellToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) - { - int addrRow, addrCol; - bool fixedRow, fixedCol; - - string result = ""; - if (GetRowCol_V1(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol)) - { - if (addrRow > 0) - { - result += "R"; - if (fixedRow) - { - // Absolute row - result += addrRow.ToString(); - } - else if (addrRow - row != 0) - { - // Relative row - result += string.Format("[{0}]", addrRow - row); - } - } - - if (addrCol > 0) - { - result += "C"; - if (fixedCol) - { - // Absolute column - result += addrCol; - } - else if (addrCol - col != 0) - { - // Relative column - result += string.Format("[{0}]", addrCol - col); - } - } - return result; - } - else - { - return part; - } - } - /// <summary> - /// Translates to absolute address - /// </summary> - /// <param name="part"></param> - /// <param name="row"></param> - /// <param name="col"></param> - /// <param name="rowIncr"></param> - /// <param name="colIncr"></param> - /// <returns></returns> - /// - - - private static string ToAbs(string part, int row, int col, int rowIncr, int colIncr) - { - string check = part.ToUpper(CultureInfo.InvariantCulture); - - int rStart = check.IndexOf("R"); - if (rStart != 0) - return part; - if (part.Length == 1) //R - { - return GetAddress(row, col); - } - - int cStart = check.IndexOf("C"); - bool absoluteRow, absoluteCol; - if (cStart == -1) - { - int RNum = GetRC(part, row, out absoluteRow); - if (RNum > int.MinValue) - { - return GetAddress(RNum, absoluteRow, col, false); - } - else - { - return part; - } - } - else - { - int RNum = GetRC(part.Substring(1, cStart - 1), row, out absoluteRow); - int CNum = GetRC(part.Substring(cStart + 1, part.Length - cStart - 1), col, out absoluteCol); - if (RNum > int.MinValue && CNum > int.MinValue) - { - return GetAddress(RNum, absoluteRow, CNum, absoluteCol); - } - else - { - return part; - } - } - } - - private static string ToAbs_V1(string part, int row, int col, int rowIncr, int colIncr) - { - bool absoluteCol = false; - bool absoluteRow = false; - int colNum = -1; - int rowNum = -1; - int num; - int numLength; - int pos = 0; - - - // Handle range expressions - if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) - { - return RangeToA1_V1(part, row, col, rowIncr, colIncr); - } - - // Ensure part is present - if (string.IsNullOrWhiteSpace(part)) - return ""; - - // Convert to upper case - string check = part.ToUpper(CultureInfo.InvariantCulture); - - // Parse "R", if any - if (pos < part.Length && check[pos] == 'R') - { - pos += 1; - - if (pos >= part.Length) - { - // Only "R" present - absoluteRow = false; - rowNum = row; - } - else if (pos < part.Length && check[pos] == 'C') - { - // "R" followed by "C" - absoluteRow = false; - rowNum = row; - } - else if (pos < part.Length && check[pos] == '[') - { - // "R" followed by relative row number - pos += 1; - num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); - if (num == Int32.MinValue) - return part; - pos += numLength; - - if (pos < part.Length && check[pos] == ']') - { - pos += 1; - } - else - { - return part; - } - - absoluteRow = false; - rowNum = row + num; - - } - else if (pos < part.Length) - { - // "R" followed by absolute row number - num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); - if (rowNum == Int32.MinValue) - return part; - pos += numLength; - - absoluteRow = true; - rowNum = num; - } - } - - // Parse "C", if any - if (pos < part.Length && check[pos] == 'C') - { - pos += 1; - - if (pos >= part.Length) - { - // Only "C" present - absoluteCol = false; - colNum = col; - } - else if (pos < part.Length && check[pos] == '[') - { - // "C" followed by relative column number - pos += 1; - num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); - if (num == Int32.MinValue) - return part; - pos += numLength; - - if (pos < part.Length && check[pos] == ']') - { - pos += 1; - } - else - { - return part; - } - - absoluteCol = false; - colNum = col + num; - - } - else if (pos < part.Length) - { - // "C" followed by absolute column number - num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); - if (num == Int32.MinValue) - return part; - pos += numLength; - - absoluteCol = true; - colNum = num; - } - } - - // Ensure nothing remains unparsed - if (pos < part.Length) - return part; - - // Exit if neither row nor column is present - if ((rowNum == Int32.MinValue) && (colNum == Int32.MinValue)) - return part; - - // Append column - string result = ""; - if (colNum >= 0) - { - if (absoluteCol) - result += "$"; - result += GetColumnLetter(colNum); - } - - // Append row - if (rowNum >= 0) - { - if (absoluteRow) - result += "$"; - result += rowNum.ToString(); - } - - // Return result - return result; - } - - private static int GetNumber_V1(string value, out int length) - { - // Get number length - length = 0; - - // Ensure value is present - if (string.IsNullOrWhiteSpace(value)) - return Int32.MinValue; - - // Check for sign - if ((length < value.Length) && ((value[length] == '-') || (value[length] == '+'))) - { - length += 1; - } - - // Get number length - while (length < value.Length && value[length] >= '0' && value[length] <= '9') - { - length += 1; - } - - // No number found - if (length == 0) - return Int32.MinValue; - - // Return number value - int result; - return (int.TryParse(value.Substring(0, length), out result)) ? result : Int32.MinValue; - } - - private static string RangeToA1_V1(string part, int row, int col, int rowIncr, int colIncr) - { - // Split range expression - string[] cellValues = part.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); - - // Convert range expressions - string result = ""; - result += ToAbs_V1(cellValues[0], row, col, rowIncr, colIncr); - result += ":"; - result += ToAbs_V1(cellValues[1], row, col, rowIncr, colIncr); - - // Return converted range expression - return result; - } - - private static string RangeCellToA1_V1(string part, int row, int col, int rowIncr, int colIncr) - { - int addrRow, addrCol; - bool fixedRow, fixedCol; - - string result = ""; - if (GetRowCol_V1(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol)) - { - if (addrRow > 0) - { - result += "R"; - if (fixedRow) - { - // Absolute row - result += addrRow.ToString(); - } - else if (addrRow - row != 0) - { - // Relative row - result += string.Format("[{0}]", addrRow - row); - } - } - - if (addrCol > 0) - { - result += "C"; - if (fixedCol) - { - // Absolute column - result += addrCol; - } - else if (addrCol - col != 0) - { - // Relative column - result += string.Format("[{0}]", addrCol - col); - } - } - return result; - } - else - { - return part; - } - } - - /// <summary> - /// Adds or subtracts a row or column to an address - /// </summary> - /// <param name="Address"></param> - /// <param name="row"></param> - /// <param name="col"></param> - /// <param name="rowIncr"></param> - /// <param name="colIncr"></param> - /// <returns></returns> - private static string AddToRowColumnTranslator(string Address, int row, int col, int rowIncr, int colIncr) - { - int fromRow, fromCol; - if (Address == "#REF!") - { - return Address; - } - if (GetRowCol(Address, out fromRow, out fromCol, false)) - { - if (fromRow == 0 || fromCol == 0) - { - return Address; - } - if (rowIncr != 0 && row != 0 && fromRow >= row && Address.IndexOf('$', 1) == -1) - { - if (fromRow < row - rowIncr) - { - return "#REF!"; - } - - fromRow = fromRow + rowIncr; - } - - if (colIncr != 0 && col != 0 && fromCol >= col && Address.StartsWith("$") == false) - { - if (fromCol < col - colIncr) - { - return "#REF!"; - } - - fromCol = fromCol + colIncr; - } - - Address = GetAddress(fromRow, Address.IndexOf('$', 1) > -1, fromCol, Address.StartsWith("$")); - } - return Address; - } - - /// <summary> - /// Returns with brackets if the value is negative - /// </summary> - /// <param name="v">The value</param> - /// <returns></returns> - private static string GetRCFmt(int v) - { - return (v < 0 ? string.Format("[{0}]", v) : v > 0 ? v.ToString() : ""); - } - /// <summary> - /// Get the offset value for RC format - /// </summary> - /// <param name="value"></param> - /// <param name="OffsetValue"></param> - /// <param name="fixedAddr"></param> - /// <returns></returns> - /// - private static int GetRC(string value, int OffsetValue, out bool fixedAddr) - { - if (value == "") - { - fixedAddr = false; - return OffsetValue; - } - int num; - if (value[0] == '[' && value[value.Length - 1] == ']') //Offset? - { - fixedAddr = false; - if (int.TryParse(value.Substring(1, value.Length - 2), out num)) - { - return (OffsetValue + num); - } - else - { - return int.MinValue; - } - } - else - { - // Absolute address - fixedAddr = true; - if (int.TryParse(value, out num)) - { - return num; - } - else - { - return int.MinValue; - } - } - } - - private static int GetRC_V1(string value, int OffsetValue, out bool fixedAddr) - { - if ((value == "") || (value == "R") || (value == "C")) - { - // Relative address with no offset - fixedAddr = false; - return OffsetValue; - } - int num; - if (value[1] == '[' && value[value.Length - 1] == ']') //Offset? - { - // Relative address - fixedAddr = false; - if (int.TryParse(value.Substring(2, value.Length - 3), out num)) - { - return (OffsetValue + num); - } - else - { - return int.MinValue; - } - } - else - { - // Absolute address - fixedAddr = true; - if (int.TryParse(value.Substring(1, value.Length - 1), out num)) - { - return num; - } - else - { - return int.MinValue; - } - } - } - #endregion - #region "Address Functions" - #region GetColumnLetter - /// <summary> - /// Returns the character representation of the numbered column - /// </summary> - /// <param name="iColumnNumber">The number of the column</param> - /// <returns>The letter representing the column</returns> - protected internal static string GetColumnLetter(int iColumnNumber) - { - return GetColumnLetter(iColumnNumber, false); - } - protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) - { - - if (iColumnNumber < 1) - { - //throw new Exception("Column number is out of range"); - return "#REF!"; - } - - string sCol = ""; - do - { - sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol; - iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26; - } - while (iColumnNumber > 0); - return fixedCol ? "$" + sCol : sCol; - } - #endregion - - internal static bool GetRowColFromAddress(string CellAddress, out int FromRow, out int FromColumn, out int ToRow, out int ToColumn) - { - bool fixedFromRow, fixedFromColumn, fixedToRow, fixedToColumn; - return GetRowColFromAddress(CellAddress, out FromRow, out FromColumn, out ToRow, out ToColumn, out fixedFromRow, out fixedFromColumn, out fixedToRow, out fixedToColumn); - } - /// <summary> - /// Get the row/columns for a Cell-address - /// </summary> - /// <param name="CellAddress">The address</param> - /// <param name="FromRow">Returns the to column</param> - /// <param name="FromColumn">Returns the from column</param> - /// <param name="ToRow">Returns the to row</param> - /// <param name="ToColumn">Returns the from row</param> - /// <param name="fixedFromRow">Is the from row fixed?</param> - /// <param name="fixedFromColumn">Is the from column fixed?</param> - /// <param name="fixedToRow">Is the to row fixed?</param> - /// <param name="fixedToColumn">Is the to column fixed?</param> - /// <returns></returns> - internal static bool GetRowColFromAddress(string CellAddress, out int FromRow, out int FromColumn, out int ToRow, out int ToColumn, out bool fixedFromRow, out bool fixedFromColumn, out bool fixedToRow, out bool fixedToColumn) - { - bool ret; - if (CellAddress.IndexOf('[') > 0) //External reference or reference to Table or Pivottable. - { - FromRow = -1; - FromColumn = -1; - ToRow = -1; - ToColumn = -1; - fixedFromRow = false; - fixedFromColumn = false; - fixedToRow= false; - fixedToColumn = false; - return false; - } - - CellAddress = CellAddress.ToUpper(CultureInfo.InvariantCulture); - //This one can be removed when the worksheet Select format is fixed - if (CellAddress.IndexOf(' ') > 0) - { - CellAddress = CellAddress.Substring(0, CellAddress.IndexOf(' ')); - } - - if (CellAddress.IndexOf(':') < 0) - { - ret = GetRowColFromAddress(CellAddress, out FromRow, out FromColumn, out fixedFromRow, out fixedFromColumn); - ToColumn = FromColumn; - ToRow = FromRow; - fixedToRow = fixedFromRow; - fixedToColumn = fixedFromColumn; - } - else - { - string[] cells = CellAddress.Split(':'); - ret = GetRowColFromAddress(cells[0], out FromRow, out FromColumn, out fixedFromRow, out fixedFromColumn); - if (ret) - ret = GetRowColFromAddress(cells[1], out ToRow, out ToColumn, out fixedToRow, out fixedToColumn); - else - { - GetRowColFromAddress(cells[1], out ToRow, out ToColumn, out fixedToRow, out fixedToColumn); - } - - if (FromColumn <= 0) - FromColumn = 1; - if (FromRow <= 0) - FromRow = 1; - if (ToColumn <= 0) - ToColumn = ExcelPackage.MaxColumns; - if (ToRow <= 0) - ToRow = ExcelPackage.MaxRows; - } - return ret; - } - /// <summary> - /// Get the row/column for n Cell-address - /// </summary> - /// <param name="CellAddress">The address</param> - /// <param name="Row">Returns Tthe row</param> - /// <param name="Column">Returns the column</param> - /// <returns>true if valid</returns> - internal static bool GetRowColFromAddress(string CellAddress, out int Row, out int Column) - { - return GetRowCol(CellAddress, out Row, out Column, true); - } - internal static bool GetRowColFromAddress(string CellAddress, out int row, out int col, out bool fixedRow, out bool fixedCol) - { - return GetRowCol(CellAddress, out row, out col, true, out fixedRow, out fixedCol); - } - - /// <summary> - /// Get the row/column for a Cell-address - /// </summary> - /// <param name="address">the address</param> - /// <param name="row">returns the row</param> - /// <param name="col">returns the column</param> - /// <param name="throwException">throw exception if invalid, otherwise returns false</param> - /// <returns></returns> - internal static bool GetRowCol(string address, out int row, out int col, bool throwException) - { - bool fixedRow, fixedCol; - return GetRowCol(address, out row, out col, throwException, out fixedRow, out fixedCol); - } - internal static bool GetRowCol(string address, out int row, out int col, bool throwException, out bool fixedRow, out bool fixedCol) - { - bool colPart = true; - int colStartIx = 0; - int colLength = 0; - col = 0; - row = 0; - fixedRow = false; - fixedCol = false; - - if (address.EndsWith("#REF!")) - { - row = 0; - col = 0; - return true; - } - - int sheetMarkerIndex = address.IndexOf('!'); - if (sheetMarkerIndex >= 0) - { - colStartIx = sheetMarkerIndex + 1; - } - address = address.ToUpper(CultureInfo.InvariantCulture); - for (int i = colStartIx; i < address.Length; i++) - { - char c = address[i]; - if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) - { - col *= 26; - col += ((int)c) - 64; - colLength++; - } - else if (c >= '0' && c <= '9') - { - row *= 10; - row += ((int)c) - 48; - colPart = false; - } - else if (c == '$') - { - if (i == colStartIx) - { - colStartIx++; - fixedCol = true; - } - else - { - colPart = false; - fixedRow = true; - } - } - else - { - row = 0; - col = 0; - if (throwException) - { - throw (new Exception(string.Format("Invalid Address format {0}", address))); - } - else - { - return false; - } - } - } - return row != 0 || col != 0; - } - - internal static bool GetRowCol_V1(string address, out int row, out int col, bool throwException, out bool fixedRow, out bool fixedCol) - { - bool colPart = true; - bool isFixed = false; - int colStartIx = 0; - int colLength = 0; - col = 0; - row = 0; - fixedRow = false; - fixedCol = false; - - if (address.EndsWith("#REF!")) - { - row = 0; - col = 0; - return true; - } - - int sheetMarkerIndex = address.IndexOf('!'); - if (sheetMarkerIndex >= 0) - { - colStartIx = sheetMarkerIndex + 1; - } - address = address.ToUpper(CultureInfo.InvariantCulture); - for (int i = colStartIx; i < address.Length; i++) - { - char c = address[i]; - if (c == '$') - { - // Absolute address - isFixed = true; - } - else if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) - { - // Column portion of address - if (isFixed) - { - fixedCol = true; - isFixed = false; - } - - col *= 26; - col += ((int)c) - 64; - colLength++; - } - else if (c >= '0' && c <= '9') - { - // Row portion of address - if (isFixed) - { - fixedRow = true; - isFixed = false; - } - - row *= 10; - row += ((int)c) - 48; - colPart = false; - } - else - { - row = 0; - col = 0; - if (throwException) - { - throw (new Exception(string.Format("Invalid Address format {0}", address))); - } - else - { - return false; - } - } - } - return row != 0 || col != 0; - } - - private static int GetColumn(string sCol) - { - int col = 0; - int len = sCol.Length - 1; - for (int i = len; i >= 0; i--) - { - col += (((int)sCol[i]) - 64) * (int)(Math.Pow(26, len - i)); - } - return col; - } - #region GetAddress - /// <summary> - /// Returns the AlphaNumeric representation that Excel expects for a Cell Address - /// </summary> - /// <param name="Row">The number of the row</param> - /// <param name="Column">The number of the column in the worksheet</param> - /// <returns>The cell address in the format A1</returns> - public static string GetAddress(int Row, int Column) - { - return GetAddress(Row, Column,false); - } - /// <summary> - /// Returns the AlphaNumeric representation that Excel expects for a Cell Address - /// </summary> - /// <param name="Row">The number of the row</param> - /// <param name="Column">The number of the column in the worksheet</param> - /// <param name="AbsoluteRow">Absolute row</param> - /// <param name="AbsoluteCol">Absolute column</param> - /// <returns>The cell address in the format A1</returns> - public static string GetAddress(int Row, bool AbsoluteRow, int Column, bool AbsoluteCol) - { - return ( AbsoluteCol ? "$" : "") + GetColumnLetter(Column) + ( AbsoluteRow ? "$" : "") + Row.ToString(); - } - /// <summary> - /// Returns the AlphaNumeric representation that Excel expects for a Cell Address - /// </summary> - /// <param name="Row">The number of the row</param> - /// <param name="Column">The number of the column in the worksheet</param> - /// <param name="Absolute">Get an absolute address ($A$1)</param> - /// <returns>The cell address in the format A1</returns> - public static string GetAddress(int Row, int Column, bool Absolute) - { - if (Row == 0 || Column == 0) - { - return "#REF!"; - } - if (Absolute) - { - return ("$" + GetColumnLetter(Column) + "$" + Row.ToString()); - } - else - { - return (GetColumnLetter(Column) + Row.ToString()); - } - } - /// <summary> - /// Returns the AlphaNumeric representation that Excel expects for a Cell Address - /// </summary> - /// <param name="FromRow">From row number</param> - /// <param name="FromColumn">From column number</param> - /// <param name="ToRow">To row number</param> - /// <param name="ToColumn">From column number</param> - /// <returns>The cell address in the format A1</returns> - public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn) - { - return GetAddress(FromRow, FromColumn, ToRow, ToColumn, false); - } - /// <summary> - /// Returns the AlphaNumeric representation that Excel expects for a Cell Address - /// </summary> - /// <param name="FromRow">From row number</param> - /// <param name="FromColumn">From column number</param> - /// <param name="ToRow">To row number</param> - /// <param name="ToColumn">From column number</param> - /// <param name="Absolute">if true address is absolute (like $A$1)</param> - /// <returns>The cell address in the format A1</returns> - public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn, bool Absolute) - { - if (FromRow == ToRow && FromColumn == ToColumn) - { - return GetAddress(FromRow, FromColumn, Absolute); - } - else - { - if (FromRow == 1 && ToRow == ExcelPackage.MaxRows) - { - var absChar = Absolute ? "$" : ""; - return absChar + GetColumnLetter(FromColumn) + ":" + absChar + GetColumnLetter(ToColumn); - } - else if(FromColumn==1 && ToColumn==ExcelPackage.MaxColumns) - { - var absChar = Absolute ? "$" : ""; - return absChar + FromRow.ToString() + ":" + absChar + ToRow.ToString(); - } - else - { - return GetAddress(FromRow, FromColumn, Absolute) + ":" + GetAddress(ToRow, ToColumn, Absolute); - } - } - } - /// <summary> - /// Returns the AlphaNumeric representation that Excel expects for a Cell Address - /// </summary> - /// <param name="FromRow">From row number</param> - /// <param name="FromColumn">From column number</param> - /// <param name="ToRow">To row number</param> - /// <param name="ToColumn">From column number</param> - /// <param name="FixedFromColumn"></param> - /// <param name="FixedFromRow"></param> - /// <param name="FixedToColumn"></param> - /// <param name="FixedToRow"></param> - /// <returns>The cell address in the format A1</returns> - public static string GetAddress(int FromRow, int FromColumn, int ToRow, int ToColumn, bool FixedFromRow, bool FixedFromColumn, bool FixedToRow, bool FixedToColumn) - { - if (FromRow == ToRow && FromColumn == ToColumn) - { - return GetAddress(FromRow, FixedFromRow, FromColumn, FixedFromColumn); - } - else - { - if (FromRow == 1 && ToRow == ExcelPackage.MaxRows) - { - return GetColumnLetter(FromColumn, FixedFromColumn) + ":" + GetColumnLetter(ToColumn, FixedToColumn); - } - else if (FromColumn == 1 && ToColumn == ExcelPackage.MaxColumns) - { - return (FixedFromRow ? "$":"") + FromRow.ToString() + ":" + (FixedToRow ? "$":"") + ToRow.ToString(); - } - else - { - return GetAddress(FromRow, FixedFromRow, FromColumn, FixedFromColumn) + ":" + GetAddress(ToRow, FixedToRow, ToColumn, FixedToColumn); - } - } - } - /// <summary> - /// Get the full address including the worksheet name - /// </summary> - /// <param name="worksheetName">The name of the worksheet</param> - /// <param name="address">The address</param> - /// <returns>The full address</returns> - public static string GetFullAddress(string worksheetName, string address) - { - return GetFullAddress(worksheetName, address, true); - } - internal static string GetFullAddress(string worksheetName, string address, bool fullRowCol) - { - if (address.IndexOf("!") == -1 || address=="#REF!") - { - if (fullRowCol) - { - string[] cells = address.Split(':'); - if (cells.Length > 0) - { - address = string.Format("'{0}'!{1}", worksheetName, cells[0]); - if (cells.Length > 1) - { - address += string.Format(":{0}", cells[1]); - } - } - } - else - { - var a = new ExcelAddressBase(address); - if ((a._fromRow == 1 && a._toRow == ExcelPackage.MaxRows) || (a._fromCol == 1 && a._toCol == ExcelPackage.MaxColumns)) - { - address = string.Format("'{0}'!{1}{2}:{3}{4}", worksheetName, ExcelAddress.GetColumnLetter(a._fromCol), a._fromRow, ExcelAddress.GetColumnLetter(a._toCol), a._toRow); - } - else - { - address=GetFullAddress(worksheetName, address, true); - } - } - } - return address; - } - #endregion - #region IsValidCellAddress - public static bool IsValidAddress(string address) - { - address = address.ToUpper(CultureInfo.InvariantCulture); - string r1 = "", c1 = "", r2 = "", c2 = ""; - bool isSecond = false; - for (int i = 0; i < address.Length; i++) - { - if (address[i] >= 'A' && address[i] <= 'Z') - { - if (isSecond == false) - { - if (r1 != "") return false; - c1 += address[i]; - if (c1.Length > 3) return false; - } - else - { - if (r2 != "") return false; - c2 += address[i]; - if (c2.Length > 3) return false; - } - } - else if (address[i] >= '0' && address[i] <= '9') - { - if (isSecond == false) - { - r1 += address[i]; - if (r1.Length > 7) return false; - } - else - { - r2 += address[i]; - if (r2.Length > 7) return false; - } - } - else if (address[i] == ':') - { - isSecond=true; - } - else if (address[i] == '$') - { - if (i == address.Length - 1 || address[i + 1] == ':') - { - return false; - } - } - else - { - return false; - } - } - - if (r1!="" && c1!="" && r2 == "" && c2 == "") //Single Cell - { - return (GetColumn(c1)<=ExcelPackage.MaxColumns && int.Parse(r1)<=ExcelPackage.MaxRows); - } - else if (r1 != "" && r2 != "" && c1 != "" && c2 != "") //Range - { - var iR2 = int.Parse(r2); - var iC2 = GetColumn(c2); - - return GetColumn(c1) <= iC2 && int.Parse(r1) <= iR2 && - iC2 <= ExcelPackage.MaxColumns && iR2 <= ExcelPackage.MaxRows; - - } - else if (r1 == "" && r2 == "" && c1 != "" && c2 != "") //Full Column - { - var c2n=GetColumn(c2); - return (GetColumn(c1) <= c2n && c2n <= ExcelPackage.MaxColumns); - } - else if (r1 != "" && r2 != "" && c1 == "" && c2 == "") - { - var iR2 = int.Parse(r2); - - return int.Parse(r1) <= iR2 && iR2 <= ExcelPackage.MaxRows; - } - else - { - return false; - } - } - /// <summary> - /// Checks that a cell address (e.g. A5) is valid. - /// </summary> - /// <param name="cellAddress">The alphanumeric cell address</param> - /// <returns>True if the cell address is valid</returns> - public static bool IsValidCellAddress(string cellAddress) - { - bool result = false; - try - { - int row, col; - if (GetRowColFromAddress(cellAddress, out row, out col)) - { - if (row > 0 && col > 0 && row <= ExcelPackage.MaxRows && col <= ExcelPackage.MaxColumns) - result = true; - else - result = false; - } - } - catch { } - return result; - } - #endregion - #region UpdateFormulaReferences - /// <summary> - /// Updates the Excel formula so that all the cellAddresses are incremented by the row and column increments - /// if they fall after the afterRow and afterColumn. - /// Supports inserting rows and columns into existing templates. - /// </summary> - /// <param name="Formula">The Excel formula</param> - /// <param name="rowIncrement">The amount to increment the cell reference by</param> - /// <param name="colIncrement">The amount to increment the cell reference by</param> - /// <param name="afterRow">Only change rows after this row</param> - /// <param name="afterColumn">Only change columns after this column</param> - /// <returns></returns> - internal static string UpdateFormulaReferences(string Formula, int rowIncrement, int colIncrement, int afterRow, int afterColumn, bool setFixed=false) - { - //return Translate(Formula, AddToRowColumnTranslator, afterRow, afterColumn, rowIncrement, colIncrement); - var d=new Dictionary<string, object>(); - try - { - var sct = new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty); - var tokens = sct.Tokenize(Formula); - String f = ""; - foreach (var t in tokens) - { - if (t.TokenType == TokenType.ExcelAddress) - { - var a = new ExcelAddressBase(t.Value); - - if (!String.IsNullOrEmpty(a._ws)) // Bug 15339 - { - // This is from a different worksheet, thus no update is required - f += a.Address; - continue; - } - - if (rowIncrement > 0) - { - a = a.AddRow(afterRow, rowIncrement, setFixed); - } - else if (rowIncrement < 0) - { - a = a.DeleteRow(afterRow, -rowIncrement, setFixed); - } - if (colIncrement > 0) - { - a = a.AddColumn(afterColumn, colIncrement, setFixed); - } - else if (colIncrement < 0) - { - a = a.DeleteColumn(afterColumn, -colIncrement, setFixed); - } - if (a == null || !a.IsValidRowCol()) - { - f += "#REF!"; - } - else - { - f += a.Address; - } - - - } - else - { - f += t.Value; - } - } - return f; - } - catch //Invalid formula, skip updateing addresses - { - return Formula; - } - } - - #endregion - #endregion - #endregion + /// <summary> + /// Translates betweein R1C1 or absolute addresses : Version 1 + /// </summary> + /// <param name="value">The addresss/function</param> + /// <param name="addressTranslator">The translating function</param> + /// <param name="row"></param> + /// <param name="col"></param> + /// <param name="rowIncr"></param> + /// <param name="colIncr"></param> + /// <returns></returns> + private static string Translate( + string value, + AddressTranslator addressTranslator, + int row, + int col, + int rowIncr, + int colIncr) { + if (value == "") { + return ""; } + bool isText = false; + string ret = ""; + string part = ""; + char prevTq = (char)0; + for (int pos = 0; pos < value.Length; pos++) { + char c = value[pos]; + if (c == '"' || c == '\'') { + if (isText && prevTq != c) { + ret += c; + continue; + } + + if (isText == false && part != "" && prevTq == c) { + ret += addressTranslator(part, row, col, rowIncr, colIncr); + part = ""; + prevTq = (char)0; + } + prevTq = c; + isText = !isText; + ret += c; + } else if (isText) { + ret += c; + } else { + if ((c == '-' + || c == '+' + || c == '*' + || c == '/' + || c == '=' + || c == '^' + || c == ',' + || c == ':' + || c == '<' + || c == '>' + || c == '(' + || c == ')' + || c == '!' + || c == ' ' + || c == '&' + || c == '%') + && (pos == 0 + || value[pos - 1] + != '[')) //Last part to allow for R1C1 style [-x] + { + ret += addressTranslator(part, row, col, rowIncr, colIncr) + c; + part = ""; + } else { + part += c; + } + } + } + if (part != "") { + ret += addressTranslator(part, row, col, rowIncr, colIncr); + } + return ret; + } + + private static string Translate_V1( + string value, + AddressTranslator addressTranslator, + int row, + int col, + int rowIncr, + int colIncr) { + if (value == "") { + return ""; + } + bool isText = false; + string ret = ""; + string part = ""; + char prevTq = (char)0; + value = value.Replace("\n", ""); // Eliminate new line characters in the formula + for (int pos = 0; pos < value.Length; pos++) { + char c = value[pos]; + if (c == '"' || c == '\'') { + if (isText && prevTq != c) { + ret += c; + continue; + } + + if (isText == false && part != "" && prevTq == c) { + ret += addressTranslator(part, row, col, rowIncr, colIncr); + part = ""; + prevTq = (char)0; + } + prevTq = c; + isText = !isText; + ret += c; + } else if (isText) { + ret += c; + } else if (c + == ':') // Keep Range expressions together + { + part += c; + } else { + if ((c == '-' + || c == '+' + || c == '*' + || c == '/' + || c == '=' + || c == '^' + || c == ',' + || c == '<' + || c == '>' + || c == '(' + || c == ')' + || c == '!' + || c == ' ' + || c == '&' + || c == '%') + && (pos == 0 + || value[pos - 1] + != '[')) //Last part to allow for R1C1 style [-x] + { + ret += addressTranslator(part, row, col, rowIncr, colIncr) + c; + part = ""; + } else { + part += c; + } + } + } + if (part != "") { + ret += addressTranslator(part, row, col, rowIncr, colIncr); + } + return ret; + } + + /// <summary> + /// Translate to R1C1 + /// </summary> + /// <param name="part">the value to be translated</param> + /// <param name="row"></param> + /// <param name="col"></param> + /// <param name="rowIncr"></param> + /// <param name="colIncr"></param> + /// <returns></returns> + private static string ToR1C1(string part, int row, int col, int rowIncr, int colIncr) { + int addrRow, + addrCol; + string ret = "R"; + if (GetRowCol(part, out addrRow, out addrCol, false)) { + if (addrRow == 0 || addrCol == 0) { + return part; + } + if (part.IndexOf('$', 1) > 0) { + ret += addrRow.ToString(); + } else if (addrRow - row != 0) { + ret += string.Format("[{0}]", addrRow - row); + } + + if (part.StartsWith("$")) { + return ret + "C" + addrCol; + } + if (addrCol - col != 0) { + return ret + "C" + string.Format("[{0}]", addrCol - col); + } + return ret + "C"; + } + return part; + } + + private static string ToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) { + int addrRow, + addrCol; + + // Handle range expressions + if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) { + return RangeToR1C1_V1(part, row, col, rowIncr, colIncr); + } + + string ret = "R"; + if (GetRowCol(part, out addrRow, out addrCol, false)) { + if (addrRow == 0 || addrCol == 0) { + return part; + } + if (part.IndexOf('$', 1) > 0) { + ret += addrRow.ToString(); + } else if (addrRow - row != 0) { + ret += string.Format("[{0}]", addrRow - row); + } + + if (part.StartsWith("$")) { + return ret + "C" + addrCol; + } + if (addrCol - col != 0) { + return ret + "C" + string.Format("[{0}]", addrCol - col); + } + return ret + "C"; + } + return part; + } + + private static string RangeToR1C1_V1(string part, int row, int col, int rowIncr, int colIncr) { + // Split range expression + string[] cellValues = part.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + + // Convert range expressions + string result = ""; + result += RangeCellToR1C1_V1(cellValues[0], row, col, rowIncr, colIncr); + result += ":"; + result += + (cellValues.Length > 1) + ? RangeCellToR1C1_V1(cellValues[1], row, col, rowIncr, colIncr) + : ""; + + // Return converted range expression + return result; + } + + private static string RangeCellToR1C1_V1( + string part, + int row, + int col, + int rowIncr, + int colIncr) { + int addrRow, + addrCol; + bool fixedRow, + fixedCol; + + string result = ""; + if (GetRowCol_V1(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol)) { + if (addrRow > 0) { + result += "R"; + if (fixedRow) { + // Absolute row + result += addrRow.ToString(); + } else if (addrRow - row != 0) { + // Relative row + result += string.Format("[{0}]", addrRow - row); + } + } + + if (addrCol > 0) { + result += "C"; + if (fixedCol) { + // Absolute column + result += addrCol; + } else if (addrCol - col != 0) { + // Relative column + result += string.Format("[{0}]", addrCol - col); + } + } + return result; + } + return part; + } + + /// <summary> + /// Translates to absolute address + /// </summary> + /// <param name="part"></param> + /// <param name="row"></param> + /// <param name="col"></param> + /// <param name="rowIncr"></param> + /// <param name="colIncr"></param> + /// <returns></returns> + /// + private static string ToAbs(string part, int row, int col, int rowIncr, int colIncr) { + string check = part.ToUpper(CultureInfo.InvariantCulture); + + int rStart = check.IndexOf("R"); + if (rStart != 0) { + return part; + } + if (part.Length + == 1) //R + { + return GetAddress(row, col); + } + + int cStart = check.IndexOf("C"); + bool absoluteRow, + absoluteCol; + if (cStart == -1) { + int rNum = GetRc(part, row, out absoluteRow); + if (rNum > int.MinValue) { + return GetAddress(rNum, absoluteRow, col, false); + } + return part; + } else { + int rNum = GetRc(part.Substring(1, cStart - 1), row, out absoluteRow); + int cNum = GetRc(part.Substring(cStart + 1, part.Length - cStart - 1), col, out absoluteCol); + if (rNum > int.MinValue && cNum > int.MinValue) { + return GetAddress(rNum, absoluteRow, cNum, absoluteCol); + } + return part; + } + } + + private static string ToAbs_V1(string part, int row, int col, int rowIncr, int colIncr) { + bool absoluteCol = false; + bool absoluteRow = false; + int colNum = -1; + int rowNum = -1; + int num; + int numLength; + int pos = 0; + + // Handle range expressions + if ((part.Length > 1) && (part.IndexOf(':', 1) > 0)) { + return RangeToA1_V1(part, row, col, rowIncr, colIncr); + } + + // Ensure part is present + if (string.IsNullOrWhiteSpace(part)) { + return ""; + } + + // Convert to upper case + string check = part.ToUpper(CultureInfo.InvariantCulture); + + // Parse "R", if any + if (pos < part.Length && check[pos] == 'R') { + pos += 1; + + if (pos >= part.Length) { + // Only "R" present + absoluteRow = false; + rowNum = row; + } else if (pos < part.Length && check[pos] == 'C') { + // "R" followed by "C" + absoluteRow = false; + rowNum = row; + } else if (pos < part.Length && check[pos] == '[') { + // "R" followed by relative row number + pos += 1; + num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); + if (num == Int32.MinValue) { + return part; + } + pos += numLength; + + if (pos < part.Length && check[pos] == ']') { + pos += 1; + } else { + return part; + } + + absoluteRow = false; + rowNum = row + num; + } else if (pos < part.Length) { + // "R" followed by absolute row number + num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); + if (rowNum == Int32.MinValue) { + return part; + } + pos += numLength; + + absoluteRow = true; + rowNum = num; + } + } + + // Parse "C", if any + if (pos < part.Length && check[pos] == 'C') { + pos += 1; + + if (pos >= part.Length) { + // Only "C" present + absoluteCol = false; + colNum = col; + } else if (pos < part.Length && check[pos] == '[') { + // "C" followed by relative column number + pos += 1; + num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); + if (num == Int32.MinValue) { + return part; + } + pos += numLength; + + if (pos < part.Length && check[pos] == ']') { + pos += 1; + } else { + return part; + } + + absoluteCol = false; + colNum = col + num; + } else if (pos < part.Length) { + // "C" followed by absolute column number + num = GetNumber_V1(check.Substring(pos, part.Length - pos), out numLength); + if (num == Int32.MinValue) { + return part; + } + pos += numLength; + + absoluteCol = true; + colNum = num; + } + } + + // Ensure nothing remains unparsed + if (pos < part.Length) { + return part; + } + + // Exit if neither row nor column is present + if ((rowNum == Int32.MinValue) && (colNum == Int32.MinValue)) { + return part; + } + + // Append column + string result = ""; + if (colNum >= 0) { + if (absoluteCol) { + result += "$"; + } + result += GetColumnLetter(colNum); + } + + // Append row + if (rowNum >= 0) { + if (absoluteRow) { + result += "$"; + } + result += rowNum.ToString(); + } + + // Return result + return result; + } + + private static int GetNumber_V1(string value, out int length) { + // Get number length + length = 0; + + // Ensure value is present + if (string.IsNullOrWhiteSpace(value)) { + return Int32.MinValue; + } + + // Check for sign + if ((length < value.Length) && ((value[length] == '-') || (value[length] == '+'))) { + length += 1; + } + + // Get number length + while (length < value.Length && value[length] >= '0' && value[length] <= '9') { + length += 1; + } + + // No number found + if (length == 0) { + return Int32.MinValue; + } + + // Return number value + int result; + return (int.TryParse(value.Substring(0, length), out result)) ? result : Int32.MinValue; + } + + private static string RangeToA1_V1(string part, int row, int col, int rowIncr, int colIncr) { + // Split range expression + string[] cellValues = part.Split(new[] { ':' }, StringSplitOptions.RemoveEmptyEntries); + + // Convert range expressions + string result = ""; + result += ToAbs_V1(cellValues[0], row, col, rowIncr, colIncr); + result += ":"; + result += ToAbs_V1(cellValues[1], row, col, rowIncr, colIncr); + + // Return converted range expression + return result; + } + + private static string RangeCellToA1_V1(string part, int row, int col, int rowIncr, int colIncr) { + int addrRow, + addrCol; + bool fixedRow, + fixedCol; + + string result = ""; + if (GetRowCol_V1(part, out addrRow, out addrCol, false, out fixedRow, out fixedCol)) { + if (addrRow > 0) { + result += "R"; + if (fixedRow) { + // Absolute row + result += addrRow.ToString(); + } else if (addrRow - row != 0) { + // Relative row + result += string.Format("[{0}]", addrRow - row); + } + } + + if (addrCol > 0) { + result += "C"; + if (fixedCol) { + // Absolute column + result += addrCol; + } else if (addrCol - col != 0) { + // Relative column + result += string.Format("[{0}]", addrCol - col); + } + } + return result; + } + return part; + } + + /// <summary> + /// Adds or subtracts a row or column to an address + /// </summary> + /// <param name="address"></param> + /// <param name="row"></param> + /// <param name="col"></param> + /// <param name="rowIncr"></param> + /// <param name="colIncr"></param> + /// <returns></returns> + private static string AddToRowColumnTranslator( + string address, + int row, + int col, + int rowIncr, + int colIncr) { + int fromRow, + fromCol; + if (address == "#REF!") { + return address; + } + if (GetRowCol(address, out fromRow, out fromCol, false)) { + if (fromRow == 0 || fromCol == 0) { + return address; + } + if (rowIncr != 0 && row != 0 && fromRow >= row && address.IndexOf('$', 1) == -1) { + if (fromRow < row - rowIncr) { + return "#REF!"; + } + + fromRow = fromRow + rowIncr; + } + + if (colIncr != 0 && col != 0 && fromCol >= col && address.StartsWith("$") == false) { + if (fromCol < col - colIncr) { + return "#REF!"; + } + + fromCol = fromCol + colIncr; + } + + address = GetAddress(fromRow, address.IndexOf('$', 1) > -1, fromCol, address.StartsWith("$")); + } + return address; + } + + /// <summary> + /// Returns with brackets if the value is negative + /// </summary> + /// <param name="v">The value</param> + /// <returns></returns> + private static string GetRcFmt(int v) { + return (v < 0 + ? string.Format("[{0}]", v) + : v > 0 + ? v.ToString() + : ""); + } + + /// <summary> + /// Get the offset value for RC format + /// </summary> + /// <param name="value"></param> + /// <param name="offsetValue"></param> + /// <param name="fixedAddr"></param> + /// <returns></returns> + /// + private static int GetRc(string value, int offsetValue, out bool fixedAddr) { + if (value == "") { + fixedAddr = false; + return offsetValue; + } + int num; + if (value[0] == '[' + && value[value.Length - 1] + == ']') //Offset? + { + fixedAddr = false; + if (int.TryParse(value.Substring(1, value.Length - 2), out num)) { + return (offsetValue + num); + } + return int.MinValue; + } + // Absolute address + fixedAddr = true; + if (int.TryParse(value, out num)) { + return num; + } + return int.MinValue; + } + + private static int GetRC_V1(string value, int offsetValue, out bool fixedAddr) { + if ((value == "") || (value == "R") || (value == "C")) { + // Relative address with no offset + fixedAddr = false; + return offsetValue; + } + int num; + if (value[1] == '[' + && value[value.Length - 1] + == ']') //Offset? + { + // Relative address + fixedAddr = false; + if (int.TryParse(value.Substring(2, value.Length - 3), out num)) { + return (offsetValue + num); + } + return int.MinValue; + } + // Absolute address + fixedAddr = true; + if (int.TryParse(value.Substring(1, value.Length - 1), out num)) { + return num; + } + return int.MinValue; + } + + /// <summary> + /// Returns the character representation of the numbered column + /// </summary> + /// <param name="iColumnNumber">The number of the column</param> + /// <returns>The letter representing the column</returns> + protected internal static string GetColumnLetter(int iColumnNumber) { + return GetColumnLetter(iColumnNumber, false); + } + + protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) { + if (iColumnNumber < 1) { + //throw new Exception("Column number is out of range"); + return "#REF!"; + } + + string sCol = ""; + do { + sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol; + iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26; + } while (iColumnNumber > 0); + return fixedCol ? "$" + sCol : sCol; + } + + internal static bool GetRowColFromAddress( + string cellAddress, + out int fromRow, + out int fromColumn, + out int toRow, + out int toColumn) { + bool fixedFromRow, + fixedFromColumn, + fixedToRow, + fixedToColumn; + return GetRowColFromAddress( + cellAddress, + out fromRow, + out fromColumn, + out toRow, + out toColumn, + out fixedFromRow, + out fixedFromColumn, + out fixedToRow, + out fixedToColumn); + } + + /// <summary> + /// Get the row/columns for a Cell-address + /// </summary> + /// <param name="cellAddress">The address</param> + /// <param name="fromRow">Returns the to column</param> + /// <param name="fromColumn">Returns the from column</param> + /// <param name="toRow">Returns the to row</param> + /// <param name="toColumn">Returns the from row</param> + /// <param name="fixedFromRow">Is the from row fixed?</param> + /// <param name="fixedFromColumn">Is the from column fixed?</param> + /// <param name="fixedToRow">Is the to row fixed?</param> + /// <param name="fixedToColumn">Is the to column fixed?</param> + /// <returns></returns> + internal static bool GetRowColFromAddress( + string cellAddress, + out int fromRow, + out int fromColumn, + out int toRow, + out int toColumn, + out bool fixedFromRow, + out bool fixedFromColumn, + out bool fixedToRow, + out bool fixedToColumn) { + bool ret; + if (cellAddress.IndexOf('[') + > 0) //External reference or reference to Table or Pivottable. + { + fromRow = -1; + fromColumn = -1; + toRow = -1; + toColumn = -1; + fixedFromRow = false; + fixedFromColumn = false; + fixedToRow = false; + fixedToColumn = false; + return false; + } + + cellAddress = cellAddress.ToUpper(CultureInfo.InvariantCulture); + //This one can be removed when the worksheet Select format is fixed + if (cellAddress.IndexOf(' ') > 0) { + cellAddress = cellAddress.Substring(0, cellAddress.IndexOf(' ')); + } + + if (cellAddress.IndexOf(':') < 0) { + ret = GetRowColFromAddress( + cellAddress, + out fromRow, + out fromColumn, + out fixedFromRow, + out fixedFromColumn); + toColumn = fromColumn; + toRow = fromRow; + fixedToRow = fixedFromRow; + fixedToColumn = fixedFromColumn; + } else { + string[] cells = cellAddress.Split(':'); + ret = GetRowColFromAddress( + cells[0], + out fromRow, + out fromColumn, + out fixedFromRow, + out fixedFromColumn); + if (ret) { + ret = GetRowColFromAddress( + cells[1], + out toRow, + out toColumn, + out fixedToRow, + out fixedToColumn); + } else { + GetRowColFromAddress(cells[1], out toRow, out toColumn, out fixedToRow, out fixedToColumn); + } + + if (fromColumn <= 0) { + fromColumn = 1; + } + if (fromRow <= 0) { + fromRow = 1; + } + if (toColumn <= 0) { + toColumn = ExcelPackage.MaxColumns; + } + if (toRow <= 0) { + toRow = ExcelPackage.MaxRows; + } + } + return ret; + } + + /// <summary> + /// Get the row/column for n Cell-address + /// </summary> + /// <param name="cellAddress">The address</param> + /// <param name="row">Returns Tthe row</param> + /// <param name="column">Returns the column</param> + /// <returns>true if valid</returns> + internal static bool GetRowColFromAddress(string cellAddress, out int row, out int column) { + return GetRowCol(cellAddress, out row, out column, true); + } + + internal static bool GetRowColFromAddress( + string cellAddress, + out int row, + out int col, + out bool fixedRow, + out bool fixedCol) { + return GetRowCol(cellAddress, out row, out col, true, out fixedRow, out fixedCol); + } + + /// <summary> + /// Get the row/column for a Cell-address + /// </summary> + /// <param name="address">the address</param> + /// <param name="row">returns the row</param> + /// <param name="col">returns the column</param> + /// <param name="throwException">throw exception if invalid, otherwise returns false</param> + /// <returns></returns> + internal static bool GetRowCol(string address, out int row, out int col, bool throwException) { + bool fixedRow, + fixedCol; + return GetRowCol(address, out row, out col, throwException, out fixedRow, out fixedCol); + } + + internal static bool GetRowCol( + string address, + out int row, + out int col, + bool throwException, + out bool fixedRow, + out bool fixedCol) { + bool colPart = true; + int colStartIx = 0; + int colLength = 0; + col = 0; + row = 0; + fixedRow = false; + fixedCol = false; + + if (address.EndsWith("#REF!")) { + row = 0; + col = 0; + return true; + } + + int sheetMarkerIndex = address.IndexOf('!'); + if (sheetMarkerIndex >= 0) { + colStartIx = sheetMarkerIndex + 1; + } + address = address.ToUpper(CultureInfo.InvariantCulture); + for (int i = colStartIx; i < address.Length; i++) { + char c = address[i]; + if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) { + col *= 26; + col += c - 64; + colLength++; + } else if (c >= '0' && c <= '9') { + row *= 10; + row += c - 48; + colPart = false; + } else if (c == '$') { + if (i == colStartIx) { + colStartIx++; + fixedCol = true; + } else { + colPart = false; + fixedRow = true; + } + } else { + row = 0; + col = 0; + if (throwException) { + throw (new(string.Format("Invalid Address format {0}", address))); + } + return false; + } + } + return row != 0 || col != 0; + } + + internal static bool GetRowCol_V1( + string address, + out int row, + out int col, + bool throwException, + out bool fixedRow, + out bool fixedCol) { + bool colPart = true; + bool isFixed = false; + int colStartIx = 0; + int colLength = 0; + col = 0; + row = 0; + fixedRow = false; + fixedCol = false; + + if (address.EndsWith("#REF!")) { + row = 0; + col = 0; + return true; + } + + int sheetMarkerIndex = address.IndexOf('!'); + if (sheetMarkerIndex >= 0) { + colStartIx = sheetMarkerIndex + 1; + } + address = address.ToUpper(CultureInfo.InvariantCulture); + for (int i = colStartIx; i < address.Length; i++) { + char c = address[i]; + if (c == '$') { + // Absolute address + isFixed = true; + } else if (colPart && (c >= 'A' && c <= 'Z') && colLength <= 3) { + // Column portion of address + if (isFixed) { + fixedCol = true; + isFixed = false; + } + + col *= 26; + col += c - 64; + colLength++; + } else if (c >= '0' && c <= '9') { + // Row portion of address + if (isFixed) { + fixedRow = true; + isFixed = false; + } + + row *= 10; + row += c - 48; + colPart = false; + } else { + row = 0; + col = 0; + if (throwException) { + throw (new(string.Format("Invalid Address format {0}", address))); + } + return false; + } + } + return row != 0 || col != 0; + } + + private static int GetColumn(string sCol) { + int col = 0; + int len = sCol.Length - 1; + for (int i = len; i >= 0; i--) { + col += (sCol[i] - 64) * (int)(Math.Pow(26, len - i)); + } + return col; + } + + /// <summary> + /// Returns the AlphaNumeric representation that Excel expects for a Cell Address + /// </summary> + /// <param name="row">The number of the row</param> + /// <param name="column">The number of the column in the worksheet</param> + /// <returns>The cell address in the format A1</returns> + public static string GetAddress(int row, int column) { + return GetAddress(row, column, false); + } + + /// <summary> + /// Returns the AlphaNumeric representation that Excel expects for a Cell Address + /// </summary> + /// <param name="row">The number of the row</param> + /// <param name="column">The number of the column in the worksheet</param> + /// <param name="absoluteRow">Absolute row</param> + /// <param name="absoluteCol">Absolute column</param> + /// <returns>The cell address in the format A1</returns> + public static string GetAddress(int row, bool absoluteRow, int column, bool absoluteCol) { + return (absoluteCol ? "$" : "") + GetColumnLetter(column) + (absoluteRow ? "$" : "") + row; + } + + /// <summary> + /// Returns the AlphaNumeric representation that Excel expects for a Cell Address + /// </summary> + /// <param name="row">The number of the row</param> + /// <param name="column">The number of the column in the worksheet</param> + /// <param name="absolute">Get an absolute address ($A$1)</param> + /// <returns>The cell address in the format A1</returns> + public static string GetAddress(int row, int column, bool absolute) { + if (row == 0 || column == 0) { + return "#REF!"; + } + if (absolute) { + return ("$" + GetColumnLetter(column) + "$" + row); + } + return (GetColumnLetter(column) + row); + } + + /// <summary> + /// Returns the AlphaNumeric representation that Excel expects for a Cell Address + /// </summary> + /// <param name="fromRow">From row number</param> + /// <param name="fromColumn">From column number</param> + /// <param name="toRow">To row number</param> + /// <param name="toColumn">From column number</param> + /// <returns>The cell address in the format A1</returns> + public static string GetAddress(int fromRow, int fromColumn, int toRow, int toColumn) { + return GetAddress(fromRow, fromColumn, toRow, toColumn, false); + } + + /// <summary> + /// Returns the AlphaNumeric representation that Excel expects for a Cell Address + /// </summary> + /// <param name="fromRow">From row number</param> + /// <param name="fromColumn">From column number</param> + /// <param name="toRow">To row number</param> + /// <param name="toColumn">From column number</param> + /// <param name="absolute">if true address is absolute (like $A$1)</param> + /// <returns>The cell address in the format A1</returns> + public static string GetAddress( + int fromRow, + int fromColumn, + int toRow, + int toColumn, + bool absolute) { + if (fromRow == toRow && fromColumn == toColumn) { + return GetAddress(fromRow, fromColumn, absolute); + } + if (fromRow == 1 && toRow == ExcelPackage.MaxRows) { + var absChar = absolute ? "$" : ""; + return absChar + GetColumnLetter(fromColumn) + ":" + absChar + GetColumnLetter(toColumn); + } + if (fromColumn == 1 && toColumn == ExcelPackage.MaxColumns) { + var absChar = absolute ? "$" : ""; + return absChar + fromRow + ":" + absChar + toRow; + } + return GetAddress(fromRow, fromColumn, absolute) + ":" + GetAddress(toRow, toColumn, absolute); + } + + /// <summary> + /// Returns the AlphaNumeric representation that Excel expects for a Cell Address + /// </summary> + /// <param name="fromRow">From row number</param> + /// <param name="fromColumn">From column number</param> + /// <param name="toRow">To row number</param> + /// <param name="toColumn">From column number</param> + /// <param name="fixedFromColumn"></param> + /// <param name="fixedFromRow"></param> + /// <param name="fixedToColumn"></param> + /// <param name="fixedToRow"></param> + /// <returns>The cell address in the format A1</returns> + public static string GetAddress( + int fromRow, + int fromColumn, + int toRow, + int toColumn, + bool fixedFromRow, + bool fixedFromColumn, + bool fixedToRow, + bool fixedToColumn) { + if (fromRow == toRow && fromColumn == toColumn) { + return GetAddress(fromRow, fixedFromRow, fromColumn, fixedFromColumn); + } + if (fromRow == 1 && toRow == ExcelPackage.MaxRows) { + return GetColumnLetter(fromColumn, fixedFromColumn) + + ":" + + GetColumnLetter(toColumn, fixedToColumn); + } + if (fromColumn == 1 && toColumn == ExcelPackage.MaxColumns) { + return (fixedFromRow ? "$" : "") + fromRow + ":" + (fixedToRow ? "$" : "") + toRow; + } + return GetAddress(fromRow, fixedFromRow, fromColumn, fixedFromColumn) + + ":" + + GetAddress(toRow, fixedToRow, toColumn, fixedToColumn); + } + + /// <summary> + /// Get the full address including the worksheet name + /// </summary> + /// <param name="worksheetName">The name of the worksheet</param> + /// <param name="address">The address</param> + /// <returns>The full address</returns> + public static string GetFullAddress(string worksheetName, string address) { + return GetFullAddress(worksheetName, address, true); + } + + internal static string GetFullAddress(string worksheetName, string address, bool fullRowCol) { + if (address.IndexOf("!") == -1 || address == "#REF!") { + if (fullRowCol) { + string[] cells = address.Split(':'); + if (cells.Length > 0) { + address = string.Format("'{0}'!{1}", worksheetName, cells[0]); + if (cells.Length > 1) { + address += string.Format(":{0}", cells[1]); + } + } + } else { + var a = new ExcelAddressBase(address); + if ((a._fromRow == 1 && a._toRow == ExcelPackage.MaxRows) + || (a._fromCol == 1 && a._toCol == ExcelPackage.MaxColumns)) { + address = string.Format( + "'{0}'!{1}{2}:{3}{4}", + worksheetName, + GetColumnLetter(a._fromCol), + a._fromRow, + GetColumnLetter(a._toCol), + a._toRow); + } else { + address = GetFullAddress(worksheetName, address, true); + } + } + } + return address; + } + + public static bool IsValidAddress(string address) { + address = address.ToUpper(CultureInfo.InvariantCulture); + string r1 = "", + c1 = "", + r2 = "", + c2 = ""; + bool isSecond = false; + for (int i = 0; i < address.Length; i++) { + if (address[i] >= 'A' && address[i] <= 'Z') { + if (isSecond == false) { + if (r1 != "") { + return false; + } + c1 += address[i]; + if (c1.Length > 3) { + return false; + } + } else { + if (r2 != "") { + return false; + } + c2 += address[i]; + if (c2.Length > 3) { + return false; + } + } + } else if (address[i] >= '0' && address[i] <= '9') { + if (isSecond == false) { + r1 += address[i]; + if (r1.Length > 7) { + return false; + } + } else { + r2 += address[i]; + if (r2.Length > 7) { + return false; + } + } + } else if (address[i] == ':') { + isSecond = true; + } else if (address[i] == '$') { + if (i == address.Length - 1 || address[i + 1] == ':') { + return false; + } + } else { + return false; + } + } + + if (r1 != "" + && c1 != "" + && r2 == "" + && c2 + == "") //Single Cell + { + return (GetColumn(c1) <= ExcelPackage.MaxColumns && int.Parse(r1) <= ExcelPackage.MaxRows); + } + if (r1 != "" + && r2 != "" + && c1 != "" + && c2 + != "") //Range + { + var iR2 = int.Parse(r2); + var iC2 = GetColumn(c2); + + return GetColumn(c1) <= iC2 + && int.Parse(r1) <= iR2 + && iC2 <= ExcelPackage.MaxColumns + && iR2 <= ExcelPackage.MaxRows; + } + if (r1 == "" + && r2 == "" + && c1 != "" + && c2 + != "") //Full Column + { + var c2N = GetColumn(c2); + return (GetColumn(c1) <= c2N && c2N <= ExcelPackage.MaxColumns); + } + if (r1 != "" && r2 != "" && c1 == "" && c2 == "") { + var iR2 = int.Parse(r2); + + return int.Parse(r1) <= iR2 && iR2 <= ExcelPackage.MaxRows; + } + return false; + } + + /// <summary> + /// Checks that a cell address (e.g. A5) is valid. + /// </summary> + /// <param name="cellAddress">The alphanumeric cell address</param> + /// <returns>True if the cell address is valid</returns> + public static bool IsValidCellAddress(string cellAddress) { + bool result = false; + try { + int row, + col; + if (GetRowColFromAddress(cellAddress, out row, out col)) { + if (row > 0 && col > 0 && row <= ExcelPackage.MaxRows && col <= ExcelPackage.MaxColumns) { + result = true; + } else { + result = false; + } + } + } catch {} + return result; + } + + /// <summary> + /// Updates the Excel formula so that all the cellAddresses are incremented by the row and column increments + /// if they fall after the afterRow and afterColumn. + /// Supports inserting rows and columns into existing templates. + /// </summary> + /// <param name="formula">The Excel formula</param> + /// <param name="rowIncrement">The amount to increment the cell reference by</param> + /// <param name="colIncrement">The amount to increment the cell reference by</param> + /// <param name="afterRow">Only change rows after this row</param> + /// <param name="afterColumn">Only change columns after this column</param> + /// <returns></returns> + internal static string UpdateFormulaReferences( + string formula, + int rowIncrement, + int colIncrement, + int afterRow, + int afterColumn, + bool setFixed = false) { + //return Translate(Formula, AddToRowColumnTranslator, afterRow, afterColumn, rowIncrement, colIncrement); + var d = new Dictionary<string, object>(); + try { + var sct = new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty); + var tokens = sct.Tokenize(formula); + String f = ""; + foreach (var t in tokens) { + if (t.TokenType == TokenType.ExcelAddress) { + var a = new ExcelAddressBase(t.Value); + + if (!String.IsNullOrEmpty( + a._ws)) // Bug 15339 + { + // This is from a different worksheet, thus no update is required + f += a.Address; + continue; + } + + if (rowIncrement > 0) { + a = a.AddRow(afterRow, rowIncrement, setFixed); + } else if (rowIncrement < 0) { + a = a.DeleteRow(afterRow, -rowIncrement, setFixed); + } + if (colIncrement > 0) { + a = a.AddColumn(afterColumn, colIncrement, setFixed); + } else if (colIncrement < 0) { + a = a.DeleteColumn(afterColumn, -colIncrement, setFixed); + } + if (a == null || !a.IsValidRowCol()) { + f += "#REF!"; + } else { + f += a.Address; + } + } else { + f += t.Value; + } + } + return f; + } catch //Invalid formula, skip updateing addresses + { + return formula; + } + } }
diff --git a/EPPlus/ExcelColumn.cs b/EPPlus/ExcelColumn.cs index 56ea994..bb26958 100644 --- a/EPPlus/ExcelColumn.cs +++ b/EPPlus/ExcelColumn.cs
@@ -13,299 +13,242 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan K�llman Initial Release 2009-10-01 * Jan K�llman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; using System.Xml; using OfficeOpenXml.Style; -namespace OfficeOpenXml -{ - /// <summary> - /// Represents one or more columns within the worksheet - /// </summary> - public class ExcelColumn : IRangeID - { - private ExcelWorksheet _worksheet; - private XmlElement _colElement = null; - #region ExcelColumn Constructor - /// <summary> - /// Creates a new instance of the ExcelColumn class. - /// For internal use only! - /// </summary> - /// <param name="Worksheet"></param> - /// <param name="col"></param> - protected internal ExcelColumn(ExcelWorksheet Worksheet, int col) - { - _worksheet = Worksheet; - _columnMin = col; - _columnMax = col; - _width = _worksheet.DefaultColWidth; - } - #endregion - internal int _columnMin; - /// <summary> - /// Sets the first column the definition refers to. - /// </summary> - public int ColumnMin - { - get { return _columnMin; } - //set { _columnMin=value; } - } +namespace OfficeOpenXml; - internal int _columnMax; - /// <summary> - /// Sets the last column the definition refers to. - /// </summary> - public int ColumnMax - { - get { return _columnMax; } - set - { - if (value < _columnMin && value > ExcelPackage.MaxColumns) - { - throw new Exception("ColumnMax out of range"); - } +/// <summary> +/// Represents one or more columns within the worksheet +/// </summary> +public class ExcelColumn : IRangeId { + private ExcelWorksheet _worksheet; + private XmlElement _colElement = null; - var cse = new CellsStoreEnumerator<object>(_worksheet._values, 0, 0, 0, ExcelPackage.MaxColumns); - while(cse.Next()) - { - var c = cse.Value as ExcelColumn; - if (cse.Column > _columnMin && c.ColumnMax <= value && cse.Column!=_columnMin) - { - throw new Exception(string.Format("ColumnMax can not span over existing column {0}.",c.ColumnMin)); - } - } - _columnMax = value; - } - } - /// <summary> - /// Internal range id for the column - /// </summary> - internal ulong ColumnID - { - get - { - return ExcelColumn.GetColumnID(_worksheet.SheetID, ColumnMin); - } - } - #region ExcelColumn Hidden - /// <summary> - /// Allows the column to be hidden in the worksheet - /// </summary> - internal bool _hidden=false; - public bool Hidden - { - get - { - return _hidden; - } - set - { - _hidden = value; - } - } - #endregion + /// <summary> + /// Creates a new instance of the ExcelColumn class. + /// For internal use only! + /// </summary> + /// <param name="worksheet"></param> + /// <param name="col"></param> + protected internal ExcelColumn(ExcelWorksheet worksheet, int col) { + _worksheet = worksheet; + _columnMin = col; + _columnMax = col; + _width = _worksheet.DefaultColWidth; + } - #region ExcelColumn Width - internal double VisualWidth - { - get - { - if (_hidden || (Collapsed && OutlineLevel>0)) - { - return 0; - } - else - { - return _width; - } - } - } - internal double _width; - /// <summary> - /// Sets the width of the column in the worksheet - /// </summary> - public double Width - { - get - { - return _width; - } - set - { - _width = value; + internal int _columnMin; - if (_hidden && value!=0) - { - _hidden = false; - } - } - } - /// <summary> - /// If set to true a column automaticlly resize(grow wider) when a user inputs numbers in a cell. - /// </summary> - public bool BestFit - { - get; - set; - } - /// <summary> - /// If the column is collapsed in outline mode - /// </summary> - public bool Collapsed { get; set; } - /// <summary> - /// Outline level. Zero if no outline - /// </summary> - public int OutlineLevel { get; set; } - /// <summary> - /// Phonetic - /// </summary> - public bool Phonetic { get; set; } - #endregion + /// <summary> + /// Sets the first column the definition refers to. + /// </summary> + public int ColumnMin => _columnMin; - #region ExcelColumn Style - /// <summary> - /// The Style applied to the whole column. Only effects cells with no individual style set. - /// Use Range object if you want to set specific styles. - /// </summary> - public ExcelStyle Style - { - get - { - string letter = ExcelCellBase.GetColumnLetter(ColumnMin); - string endLetter = ExcelCellBase.GetColumnLetter(ColumnMax); - return _worksheet.Workbook.Styles.GetStyleObject(StyleID, _worksheet.PositionID, letter + ":" + endLetter); - } - } - internal string _styleName=""; - /// <summary> - /// Sets the style for the entire column using a style name. - /// </summary> - public string StyleName - { - get - { - return _styleName; - } - set - { - StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); - _styleName = value; - } - } - //internal int _styleID = 0; - /// <summary> - /// Sets the style for the entire column using the style ID. - /// </summary> - public int StyleID - { - get - { - return _worksheet._styles.GetValue(0, ColumnMin); - } - set - { - _worksheet._styles.SetValue(0, ColumnMin, value); - } - } - /// <summary> - /// Adds a manual page break after the column. - /// </summary> - public bool PageBreak - { - get; - set; - } - public bool Merged - { - get - { - return _worksheet.MergedCells[ColumnMin, 0] != null; - } - set - { - _worksheet.MergedCells.Add(new ExcelAddressBase(1, ColumnMin, ExcelPackage.MaxRows, ColumnMax), true); - } - } - #endregion + //set { _columnMin=value; } + internal int _columnMax; - /// <summary> - /// Returns the range of columns covered by the column definition. - /// </summary> - /// <returns>A string describing the range of columns covered by the column definition.</returns> - public override string ToString() - { - return string.Format("Column Range: {0} to {1}", _colElement.GetAttribute("min"), _colElement.GetAttribute("min")); - } - - /// <summary> - /// Get the internal RangeID - /// </summary> - /// <param name="sheetID">Sheet no</param> - /// <param name="column">Column</param> - /// <returns></returns> - internal static ulong GetColumnID(int sheetID, int column) - { - return ((ulong)sheetID) + (((ulong)column) << 15); - } + /// <summary> + /// Sets the last column the definition refers to. + /// </summary> + public int ColumnMax { + get => _columnMax; + set { + if (value < _columnMin && value > ExcelPackage.MaxColumns) { + throw new("ColumnMax out of range"); + } - #region IRangeID Members - - ulong IRangeID.RangeID - { - get - { - return ColumnID; - } - set - { - int prevColMin = _columnMin; - _columnMin = ((int)(value >> 15) & 0x3FF); - _columnMax += prevColMin - ColumnMin; - //Todo:More Validation - if (_columnMax > ExcelPackage.MaxColumns) _columnMax = ExcelPackage.MaxColumns; - } + var cse = new CellsStoreEnumerator<object>( + _worksheet._values, + 0, + 0, + 0, + ExcelPackage.MaxColumns); + while (cse.Next()) { + var c = cse.Value as ExcelColumn; + if (cse.Column > _columnMin && c.ColumnMax <= value && cse.Column != _columnMin) { + throw new(string.Format("ColumnMax can not span over existing column {0}.", c.ColumnMin)); } - - #endregion - - /// <summary> - /// Copies the current column to a new worksheet - /// </summary> - /// <param name="added">The worksheet where the copy will be created</param> - internal ExcelColumn Clone(ExcelWorksheet added) - { - return Clone(added, ColumnMin); - } - internal ExcelColumn Clone(ExcelWorksheet added, int col) - { - ExcelColumn newCol = added.Column(col); - newCol.ColumnMax = ColumnMax; - newCol.BestFit = BestFit; - newCol.Collapsed = Collapsed; - newCol.OutlineLevel = OutlineLevel; - newCol.PageBreak = PageBreak; - newCol.Phonetic = Phonetic; - newCol._styleName = _styleName; - newCol.StyleID = StyleID; - newCol.Width = Width; - newCol.Hidden = Hidden; - return newCol; - } + } + _columnMax = value; } + } + + /// <summary> + /// Internal range id for the column + /// </summary> + internal ulong ColumnID => GetColumnId(_worksheet.SheetID, ColumnMin); + + /// <summary> + /// Allows the column to be hidden in the worksheet + /// </summary> + internal bool _hidden; + public bool Hidden { + get => _hidden; + set => _hidden = value; + } + + internal double VisualWidth { + get { + if (_hidden || (Collapsed && OutlineLevel > 0)) { + return 0; + } + return _width; + } + } + internal double _width; + + /// <summary> + /// Sets the width of the column in the worksheet + /// </summary> + public double Width { + get => _width; + set { + _width = value; + + if (_hidden && value != 0) { + _hidden = false; + } + } + } + + /// <summary> + /// If set to true a column automaticlly resize(grow wider) when a user inputs numbers in a cell. + /// </summary> + public bool BestFit { get; set; } + + /// <summary> + /// If the column is collapsed in outline mode + /// </summary> + public bool Collapsed { get; set; } + + /// <summary> + /// Outline level. Zero if no outline + /// </summary> + public int OutlineLevel { get; set; } + + /// <summary> + /// Phonetic + /// </summary> + public bool Phonetic { get; set; } + + /// <summary> + /// The Style applied to the whole column. Only effects cells with no individual style set. + /// Use Range object if you want to set specific styles. + /// </summary> + public ExcelStyle Style { + get { + string letter = ExcelCellBase.GetColumnLetter(ColumnMin); + string endLetter = ExcelCellBase.GetColumnLetter(ColumnMax); + return _worksheet.Workbook.Styles.GetStyleObject( + StyleID, + _worksheet.PositionID, + letter + ":" + endLetter); + } + } + internal string _styleName = ""; + + /// <summary> + /// Sets the style for the entire column using a style name. + /// </summary> + public string StyleName { + get => _styleName; + set { + StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); + _styleName = value; + } + } + + //internal int _styleID = 0; + /// <summary> + /// Sets the style for the entire column using the style ID. + /// </summary> + public int StyleID { + get => _worksheet._styles.GetValue(0, ColumnMin); + set => _worksheet._styles.SetValue(0, ColumnMin, value); + } + + /// <summary> + /// Adds a manual page break after the column. + /// </summary> + public bool PageBreak { get; set; } + public bool Merged { + get => _worksheet.MergedCells[ColumnMin, 0] != null; + set => _worksheet.MergedCells.Add(new(1, ColumnMin, ExcelPackage.MaxRows, ColumnMax), true); + } + + /// <summary> + /// Returns the range of columns covered by the column definition. + /// </summary> + /// <returns>A string describing the range of columns covered by the column definition.</returns> + public override string ToString() { + return string.Format( + "Column Range: {0} to {1}", + _colElement.GetAttribute("min"), + _colElement.GetAttribute("min")); + } + + /// <summary> + /// Get the internal RangeID + /// </summary> + /// <param name="sheetId">Sheet no</param> + /// <param name="column">Column</param> + /// <returns></returns> + internal static ulong GetColumnId(int sheetId, int column) { + return ((ulong)sheetId) + (((ulong)column) << 15); + } + + ulong IRangeId.RangeID { + get => ColumnID; + set { + int prevColMin = _columnMin; + _columnMin = ((int)(value >> 15) & 0x3FF); + _columnMax += prevColMin - ColumnMin; + //Todo:More Validation + if (_columnMax > ExcelPackage.MaxColumns) { + _columnMax = ExcelPackage.MaxColumns; + } + } + } + + /// <summary> + /// Copies the current column to a new worksheet + /// </summary> + /// <param name="added">The worksheet where the copy will be created</param> + internal ExcelColumn Clone(ExcelWorksheet added) { + return Clone(added, ColumnMin); + } + + internal ExcelColumn Clone(ExcelWorksheet added, int col) { + ExcelColumn newCol = added.Column(col); + newCol.ColumnMax = ColumnMax; + newCol.BestFit = BestFit; + newCol.Collapsed = Collapsed; + newCol.OutlineLevel = OutlineLevel; + newCol.PageBreak = PageBreak; + newCol.Phonetic = Phonetic; + newCol._styleName = _styleName; + newCol.StyleID = StyleID; + newCol.Width = Width; + newCol.Hidden = Hidden; + return newCol; + } }
diff --git a/EPPlus/ExcelComment.cs b/EPPlus/ExcelComment.cs index e25e7d8..acd42ad 100644 --- a/EPPlus/ExcelComment.cs +++ b/EPPlus/ExcelComment.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,139 +13,134 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* - * Jan Källman Initial Release + * Jan Källman Initial Release * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.Style; + using System.Xml; -using OfficeOpenXml.Drawing; using OfficeOpenXml.Drawing.Vml; +using OfficeOpenXml.Style; -namespace OfficeOpenXml -{ - /// <summary> - /// An Excel Cell Comment - /// </summary> - public class ExcelComment : ExcelVmlDrawingComment - { - internal XmlHelper _commentHelper; - private string _text; - internal ExcelComment(XmlNamespaceManager ns, XmlNode commentTopNode, ExcelRangeBase cell) - : base(null, cell, cell.Worksheet.VmlDrawingsComments.NameSpaceManager) - { - //_commentHelper = new XmlHelper(ns, commentTopNode); - _commentHelper = XmlHelperFactory.Create(ns, commentTopNode); - var textElem=commentTopNode.SelectSingleNode("d:text", ns); - if (textElem == null) - { - textElem = commentTopNode.OwnerDocument.CreateElement("text", ExcelPackage.schemaMain); - commentTopNode.AppendChild(textElem); - } - if (!cell.Worksheet._vmlDrawings.ContainsKey(ExcelAddress.GetCellID(cell.Worksheet.SheetID, cell.Start.Row, cell.Start.Column))) - { - cell.Worksheet._vmlDrawings.Add(cell); - } +namespace OfficeOpenXml; - TopNode = cell.Worksheet.VmlDrawingsComments[ExcelCellBase.GetCellID(cell.Worksheet.SheetID, cell.Start.Row, cell.Start.Column)].TopNode; - RichText = new ExcelRichTextCollection(ns,textElem); - var tNode = textElem.SelectSingleNode("d:t", ns); - if (tNode != null) - { - _text = tNode.InnerText; - } - } - const string AUTHORS_PATH = "d:comments/d:authors"; - const string AUTHOR_PATH = "d:comments/d:authors/d:author"; - /// <summary> - /// Author - /// </summary> - public string Author - { - get - { - int authorRef = _commentHelper.GetXmlNodeInt("@authorId"); - return _commentHelper.TopNode.OwnerDocument.SelectSingleNode(string.Format("{0}[{1}]", AUTHOR_PATH, authorRef+1), _commentHelper.NameSpaceManager).InnerText; - } - set - { - int authorRef = GetAuthor(value); - _commentHelper.SetXmlNodeString("@authorId", authorRef.ToString()); - } - } - private int GetAuthor(string value) - { - int authorRef = 0; - bool found = false; - foreach (XmlElement node in _commentHelper.TopNode.OwnerDocument.SelectNodes(AUTHOR_PATH, _commentHelper.NameSpaceManager)) - { - if (node.InnerText == value) - { - found = true; - break; - } - authorRef++; - } - if (!found) - { - var elem = _commentHelper.TopNode.OwnerDocument.CreateElement("d", "author", ExcelPackage.schemaMain); - _commentHelper.TopNode.OwnerDocument.SelectSingleNode(AUTHORS_PATH, _commentHelper.NameSpaceManager).AppendChild(elem); - elem.InnerText = value; - } - return authorRef; - } - /// <summary> - /// The comment text - /// </summary> - public string Text - { - get - { - if(!string.IsNullOrEmpty(RichText.Text)) return RichText.Text; - return _text; - } - set - { - RichText.Text = value; - } - } - /// <summary> - /// Sets the font of the first richtext item. - /// </summary> - public ExcelRichText Font - { - get - { - if (RichText.Count > 0) - { - return RichText[0]; - } - return null; - } - } - /// <summary> - /// Richtext collection - /// </summary> - public ExcelRichTextCollection RichText - { - get; - set; - } +/// <summary> +/// An Excel Cell Comment +/// </summary> +public class ExcelComment : ExcelVmlDrawingComment { + internal XmlHelper _commentHelper; + private string _text; + + internal ExcelComment(XmlNamespaceManager ns, XmlNode commentTopNode, ExcelRangeBase cell) + : base(null, cell, cell.Worksheet.VmlDrawingsComments.NameSpaceManager) { + //_commentHelper = new XmlHelper(ns, commentTopNode); + _commentHelper = XmlHelperFactory.Create(ns, commentTopNode); + var textElem = commentTopNode.SelectSingleNode("d:text", ns); + if (textElem == null) { + textElem = commentTopNode.OwnerDocument.CreateElement("text", ExcelPackage._schemaMain); + commentTopNode.AppendChild(textElem); } + if (!cell.Worksheet._vmlDrawings.ContainsKey( + ExcelCellBase.GetCellId(cell.Worksheet.SheetID, cell.Start.Row, cell.Start.Column))) { + cell.Worksheet._vmlDrawings.Add(cell); + } + + TopNode = cell.Worksheet.VmlDrawingsComments[ExcelCellBase.GetCellId( + cell.Worksheet.SheetID, + cell.Start.Row, + cell.Start.Column)].TopNode; + RichText = new(ns, textElem); + var tNode = textElem.SelectSingleNode("d:t", ns); + if (tNode != null) { + _text = tNode.InnerText; + } + } + + private const string _authorsPath = "d:comments/d:authors"; + private const string _authorPath = "d:comments/d:authors/d:author"; + + /// <summary> + /// Author + /// </summary> + public string Author { + get { + int authorRef = _commentHelper.GetXmlNodeInt("@authorId"); + return _commentHelper.TopNode.OwnerDocument + .SelectSingleNode( + string.Format("{0}[{1}]", _authorPath, authorRef + 1), + _commentHelper.NameSpaceManager) + .InnerText; + } + set { + int authorRef = GetAuthor(value); + _commentHelper.SetXmlNodeString("@authorId", authorRef.ToString()); + } + } + + private int GetAuthor(string value) { + int authorRef = 0; + bool found = false; + foreach (XmlElement node in _commentHelper.TopNode.OwnerDocument.SelectNodes( + _authorPath, + _commentHelper.NameSpaceManager)) { + if (node.InnerText == value) { + found = true; + break; + } + authorRef++; + } + if (!found) { + var elem = _commentHelper.TopNode.OwnerDocument.CreateElement( + "d", + "author", + ExcelPackage._schemaMain); + _commentHelper.TopNode.OwnerDocument + .SelectSingleNode(_authorsPath, _commentHelper.NameSpaceManager) + .AppendChild(elem); + elem.InnerText = value; + } + return authorRef; + } + + /// <summary> + /// The comment text + /// </summary> + public string Text { + get { + if (!string.IsNullOrEmpty(RichText.Text)) { + return RichText.Text; + } + return _text; + } + set => RichText.Text = value; + } + + /// <summary> + /// Sets the font of the first richtext item. + /// </summary> + public ExcelRichText Font { + get { + if (RichText.Count > 0) { + return RichText[0]; + } + return null; + } + } + + /// <summary> + /// Richtext collection + /// </summary> + public ExcelRichTextCollection RichText { get; set; } }
diff --git a/EPPlus/ExcelCommentCollection.cs b/EPPlus/ExcelCommentCollection.cs index cf0a540..b4a60af 100644 --- a/EPPlus/ExcelCommentCollection.cs +++ b/EPPlus/ExcelCommentCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,223 +13,204 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; using System.Collections; +using System.Collections.Generic; +using System.Xml; +using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils; -namespace OfficeOpenXml -{ - /// <summary> - /// Collection of Excelcomment objects - /// </summary> - public class ExcelCommentCollection : IEnumerable, IDisposable - { - internal RangeCollection _comments; - internal ExcelCommentCollection(ExcelPackage pck, ExcelWorksheet ws, XmlNamespaceManager ns) - { - CommentXml = new XmlDocument(); - CommentXml.PreserveWhitespace = false; - NameSpaceManager=ns; - Worksheet=ws; - CreateXml(pck); - AddCommentsFromXml(); - } - private void CreateXml(ExcelPackage pck) - { - var commentParts = Worksheet.Part.GetRelationshipsByType(ExcelPackage.schemaComment); - bool isLoaded=false; - CommentXml=new XmlDocument(); - foreach(var commentPart in commentParts) - { - Uri = UriHelper.ResolvePartUri(commentPart.SourceUri, commentPart.TargetUri); - Part = pck.Package.GetPart(Uri); - XmlHelper.LoadXmlSafe(CommentXml, Part.GetStream()); - RelId = commentPart.Id; - isLoaded=true; - } - //Create a new document - if(!isLoaded) - { - CommentXml.LoadXml("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><comments xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><authors /><commentList /></comments>"); - Uri = null; - } - } - private void AddCommentsFromXml() - { - var lst = new List<IRangeID>(); - foreach (XmlElement node in CommentXml.SelectNodes("//d:commentList/d:comment", NameSpaceManager)) - { - var comment = new ExcelComment(NameSpaceManager, node, new ExcelRangeBase(Worksheet, node.GetAttribute("ref"))); - lst.Add(comment); - } - _comments = new RangeCollection(lst); - } - /// <summary> - /// Access to the comment xml document - /// </summary> - public XmlDocument CommentXml { get; set; } - internal Uri Uri { get; set; } - internal string RelId { get; set; } - internal XmlNamespaceManager NameSpaceManager { get; set; } - internal Packaging.ZipPackagePart Part - { - get; - set; - } - /// <summary> - /// A reference to the worksheet object - /// </summary> - public ExcelWorksheet Worksheet - { - get; - set; - } - /// <summary> - /// Number of comments in the collection - /// </summary> - public int Count - { - get - { - return _comments.Count; - } - } - /// <summary> - /// Indexer for the comments collection - /// </summary> - /// <param name="Index">The index</param> - /// <returns>The comment</returns> - public ExcelComment this[int Index] - { - get - { - if (Index < 0 || Index >= _comments.Count) - { - throw(new ArgumentOutOfRangeException("Comment index out of range")); - } - return _comments[Index] as ExcelComment; - } - } - /// <summary> - /// Indexer for the comments collection - /// </summary> - /// <param name="cell">The cell</param> - /// <returns>The comment</returns> - public ExcelComment this[ExcelCellAddress cell] - { - get - { - ulong cellID=ExcelCellBase.GetCellID(Worksheet.SheetID, cell.Row, cell.Column); - if (_comments.IndexOf(cellID) >= 0) - { - return _comments[cellID] as ExcelComment; - } - else - { - return null; - } - } - } - /// <summary> - /// Adds a comment to the top left cell of the range - /// </summary> - /// <param name="cell">The cell</param> - /// <param name="Text">The comment text</param> - /// <param name="author">Author</param> - /// <returns>The comment</returns> - public ExcelComment Add(ExcelRangeBase cell, string Text, string author) - { - var elem = CommentXml.CreateElement("comment", ExcelPackage.schemaMain); - int ix=_comments.IndexOf(ExcelAddress.GetCellID(Worksheet.SheetID, cell._fromRow, cell._fromCol)); - //Make sure the nodes come on order. - if (ix < 0 && (~ix < _comments.Count)) - { - ix = ~ix; - var preComment = _comments[ix] as ExcelComment; - preComment._commentHelper.TopNode.ParentNode.InsertBefore(elem, preComment._commentHelper.TopNode); - } - else - { - CommentXml.SelectSingleNode("d:comments/d:commentList", NameSpaceManager).AppendChild(elem); - } - elem.SetAttribute("ref", cell.Start.Address); - ExcelComment comment = new ExcelComment(NameSpaceManager, elem , cell); - comment.RichText.Add(Text); - if(author!="") - { - comment.Author=author; - } - _comments.Add(comment); - //Check if a value exists otherwise add one so it is saved when the cells collection is iterated - if (!Worksheet._values.Exists(cell._fromRow, cell._fromCol)) - { - Worksheet._values.SetValue(cell._fromRow, cell._fromCol, null); - } - return comment; - } - /// <summary> - /// Removes the comment - /// </summary> - /// <param name="comment">The comment to remove</param> - public void Remove(ExcelComment comment) - { - ulong id = ExcelAddress.GetCellID(Worksheet.SheetID, comment.Range._fromRow, comment.Range._fromCol); - int ix=_comments.IndexOf(id); - if (ix >= 0 && comment == _comments[ix]) - { - comment.TopNode.ParentNode.RemoveChild(comment.TopNode); //Remove VML - comment._commentHelper.TopNode.ParentNode.RemoveChild(comment._commentHelper.TopNode); //Remove Comment - Worksheet.VmlDrawingsComments._drawings.Delete(id); - _comments.Delete(id); - } - else - { - throw (new ArgumentException("Comment does not exist in the worksheet")); - } - } +namespace OfficeOpenXml; - void IDisposable.Dispose() { } - - /// <summary> - /// Removes the comment at the specified position - /// </summary> - /// <param name="Index">The index</param> - public void RemoveAt(int Index) - { - Remove(this[Index]); - } - #region IEnumerable Members +/// <summary> +/// Collection of Excelcomment objects +/// </summary> +public class ExcelCommentCollection : IEnumerable, IDisposable { + internal RangeCollection _comments; - IEnumerator IEnumerable.GetEnumerator() - { - return _comments; - } - #endregion + internal ExcelCommentCollection(ExcelPackage pck, ExcelWorksheet ws, XmlNamespaceManager ns) { + CommentXml = new(); + CommentXml.PreserveWhitespace = false; + NameSpaceManager = ns; + Worksheet = ws; + CreateXml(pck); + AddCommentsFromXml(); + } - internal void Clear() - { - while(Count>0) - { - RemoveAt(0); - } - } + private void CreateXml(ExcelPackage pck) { + var commentParts = Worksheet.Part.GetRelationshipsByType(ExcelPackage._schemaComment); + bool isLoaded = false; + CommentXml = new(); + foreach (var commentPart in commentParts) { + Uri = UriHelper.ResolvePartUri(commentPart.SourceUri, commentPart.TargetUri); + Part = pck.Package.GetPart(Uri); + XmlHelper.LoadXmlSafe(CommentXml, Part.GetStream()); + RelId = commentPart.Id; + isLoaded = true; } + //Create a new document + if (!isLoaded) { + CommentXml.LoadXml( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><comments xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\"><authors /><commentList /></comments>"); + Uri = null; + } + } + + private void AddCommentsFromXml() { + var lst = new List<IRangeId>(); + foreach (XmlElement node in CommentXml.SelectNodes( + "//d:commentList/d:comment", + NameSpaceManager)) { + var comment = new ExcelComment( + NameSpaceManager, + node, + new(Worksheet, node.GetAttribute("ref"))); + lst.Add(comment); + } + _comments = new(lst); + } + + /// <summary> + /// Access to the comment xml document + /// </summary> + public XmlDocument CommentXml { get; set; } + + internal Uri Uri { get; set; } + + internal string RelId { get; set; } + + internal XmlNamespaceManager NameSpaceManager { get; set; } + + internal ZipPackagePart Part { get; set; } + + /// <summary> + /// A reference to the worksheet object + /// </summary> + public ExcelWorksheet Worksheet { get; set; } + + /// <summary> + /// Number of comments in the collection + /// </summary> + public int Count => _comments.Count; + + /// <summary> + /// Indexer for the comments collection + /// </summary> + /// <param name="index">The index</param> + /// <returns>The comment</returns> + public ExcelComment this[int index] { + get { + if (index < 0 || index >= _comments.Count) { + throw (new ArgumentOutOfRangeException("Comment index out of range")); + } + return _comments[index] as ExcelComment; + } + } + + /// <summary> + /// Indexer for the comments collection + /// </summary> + /// <param name="cell">The cell</param> + /// <returns>The comment</returns> + public ExcelComment this[ExcelCellAddress cell] { + get { + ulong cellId = ExcelCellBase.GetCellId(Worksheet.SheetID, cell.Row, cell.Column); + if (_comments.IndexOf(cellId) >= 0) { + return _comments[cellId] as ExcelComment; + } + return null; + } + } + + /// <summary> + /// Adds a comment to the top left cell of the range + /// </summary> + /// <param name="cell">The cell</param> + /// <param name="text">The comment text</param> + /// <param name="author">Author</param> + /// <returns>The comment</returns> + public ExcelComment Add(ExcelRangeBase cell, string text, string author) { + var elem = CommentXml.CreateElement("comment", ExcelPackage._schemaMain); + int ix = _comments.IndexOf( + ExcelCellBase.GetCellId(Worksheet.SheetID, cell._fromRow, cell._fromCol)); + //Make sure the nodes come on order. + if (ix < 0 && (~ix < _comments.Count)) { + ix = ~ix; + var preComment = _comments[ix] as ExcelComment; + preComment._commentHelper.TopNode.ParentNode.InsertBefore( + elem, + preComment._commentHelper.TopNode); + } else { + CommentXml.SelectSingleNode("d:comments/d:commentList", NameSpaceManager).AppendChild(elem); + } + elem.SetAttribute("ref", cell.Start.Address); + ExcelComment comment = new ExcelComment(NameSpaceManager, elem, cell); + comment.RichText.Add(text); + if (author != "") { + comment.Author = author; + } + _comments.Add(comment); + //Check if a value exists otherwise add one so it is saved when the cells collection is iterated + if (!Worksheet._values.Exists(cell._fromRow, cell._fromCol)) { + Worksheet._values.SetValue(cell._fromRow, cell._fromCol, null); + } + return comment; + } + + /// <summary> + /// Removes the comment + /// </summary> + /// <param name="comment">The comment to remove</param> + public void Remove(ExcelComment comment) { + ulong id = ExcelCellBase.GetCellId( + Worksheet.SheetID, + comment.Range._fromRow, + comment.Range._fromCol); + int ix = _comments.IndexOf(id); + if (ix >= 0 && comment == _comments[ix]) { + comment.TopNode.ParentNode.RemoveChild(comment.TopNode); //Remove VML + comment._commentHelper.TopNode.ParentNode.RemoveChild(comment._commentHelper.TopNode); //Remove Comment + + Worksheet.VmlDrawingsComments._drawings.Delete(id); + _comments.Delete(id); + } else { + throw (new ArgumentException("Comment does not exist in the worksheet")); + } + } + + void IDisposable.Dispose() {} + + /// <summary> + /// Removes the comment at the specified position + /// </summary> + /// <param name="index">The index</param> + public void RemoveAt(int index) { + Remove(this[index]); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _comments; + } + + internal void Clear() { + while (Count > 0) { + RemoveAt(0); + } + } }
diff --git a/EPPlus/ExcelHeaderFooter.cs b/EPPlus/ExcelHeaderFooter.cs index ce72dd8..9a53f92 100644 --- a/EPPlus/ExcelHeaderFooter.cs +++ b/EPPlus/ExcelHeaderFooter.cs
@@ -13,365 +13,337 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Initial Release 2009-10-01 * Jan Källman Total rewrite 2010-03-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 * *******************************************************************************/ + using System.Xml; -namespace OfficeOpenXml -{ - #region class ExcelHeaderFooterText - /// <summary> - /// Print header and footer - /// </summary> - public class ExcelHeaderFooterText - { - ExcelWorksheet _ws; - string _hf; - internal ExcelHeaderFooterText(XmlNode TextNode, ExcelWorksheet ws, string hf) - { - _ws = ws; - _hf = hf; - if (TextNode == null || string.IsNullOrEmpty(TextNode.InnerText)) return; - string text = TextNode.InnerText; - string code = text.Substring(0, 2); - int startPos=2; - for (int pos=startPos;pos<text.Length-2;pos++) - { - string newCode = text.Substring(pos, 2); - if (newCode == "&C" || newCode == "&R") - { - SetText(code, text.Substring(startPos, pos-startPos)); - startPos = pos+2; - pos = startPos; - code = newCode; - } - } - SetText(code, text.Substring(startPos, text.Length - startPos)); - } - private void SetText(string code, string text) - { - switch (code) - { - case "&L": - LeftAlignedText=text; - break; - case "&C": - CenteredText=text; - break; - default: - RightAlignedText=text; - break; - } - } - /// <summary> - /// Get/set the text to appear on the left hand side of the header (or footer) on the worksheet. - /// </summary> - public string LeftAlignedText = null; - /// <summary> - /// Get/set the text to appear in the center of the header (or footer) on the worksheet. - /// </summary> - public string CenteredText = null; - /// <summary> - /// Get/set the text to appear on the right hand side of the header (or footer) on the worksheet. - /// </summary> - public string RightAlignedText = null; - } - #endregion - #region ExcelHeaderFooter - /// <summary> - /// Represents the Header and Footer on an Excel Worksheet - /// </summary> - public sealed class ExcelHeaderFooter : XmlHelper - { - #region Static Properties - /// <summary> - /// The code for "current page #" - /// </summary> - public const string PageNumber = @"&P"; - /// <summary> - /// The code for "total pages" - /// </summary> - public const string NumberOfPages = @"&N"; - /// <summary> - /// The code for "text font color" - /// RGB Color is specified as RRGGBB - /// Theme Color is specified as TTSNN where TT is the theme color Id, S is either "+" or "-" of the tint/shade value, NN is the tint/shade value. - /// </summary> - public const string FontColor = @"&K"; - /// <summary> - /// The code for "sheet tab name" - /// </summary> - public const string SheetName = @"&A"; - /// <summary> - /// The code for "this workbook's file path" - /// </summary> - public const string FilePath = @"&Z"; - /// <summary> - /// The code for "this workbook's file name" - /// </summary> - public const string FileName = @"&F"; - /// <summary> - /// The code for "date" - /// </summary> - public const string CurrentDate = @"&D"; - /// <summary> - /// The code for "time" - /// </summary> - public const string CurrentTime = @"&T"; - /// <summary> - /// The code for "picture as background" - /// </summary> - public const string Image = @"&G"; - /// <summary> - /// The code for "outline style" - /// </summary> - public const string OutlineStyle = @"&O"; - /// <summary> - /// The code for "shadow style" - /// </summary> - public const string ShadowStyle = @"&H"; - #endregion +namespace OfficeOpenXml; - #region ExcelHeaderFooter Private Properties - internal ExcelHeaderFooterText _oddHeader; - internal ExcelHeaderFooterText _oddFooter; - internal ExcelHeaderFooterText _evenHeader; - internal ExcelHeaderFooterText _evenFooter; - internal ExcelHeaderFooterText _firstHeader; - internal ExcelHeaderFooterText _firstFooter; - private ExcelWorksheet _ws; - #endregion +/// <summary> +/// Print header and footer +/// </summary> +public class ExcelHeaderFooterText { + private ExcelWorksheet _ws; + private string _hf; - #region ExcelHeaderFooter Constructor - /// <summary> - /// ExcelHeaderFooter Constructor - /// </summary> - /// <param name="nameSpaceManager"></param> - /// <param name="topNode"></param> - /// <param name="ws">The worksheet</param> - internal ExcelHeaderFooter(XmlNamespaceManager nameSpaceManager, XmlNode topNode, ExcelWorksheet ws) : - base(nameSpaceManager, topNode) - { - _ws = ws; - SchemaNodeOrder = new string[] { "headerFooter", "oddHeader", "oddFooter", "evenHeader", "evenFooter", "firstHeader", "firstFooter" }; - } - #endregion + internal ExcelHeaderFooterText(XmlNode textNode, ExcelWorksheet ws, string hf) { + _ws = ws; + _hf = hf; + if (textNode == null || string.IsNullOrEmpty(textNode.InnerText)) { + return; + } + string text = textNode.InnerText; + string code = text.Substring(0, 2); + int startPos = 2; + for (int pos = startPos; pos < text.Length - 2; pos++) { + string newCode = text.Substring(pos, 2); + if (newCode == "&C" || newCode == "&R") { + SetText(code, text.Substring(startPos, pos - startPos)); + startPos = pos + 2; + pos = startPos; + code = newCode; + } + } + SetText(code, text.Substring(startPos, text.Length - startPos)); + } - #region alignWithMargins - const string alignWithMarginsPath="@alignWithMargins"; - /// <summary> - /// Gets/sets the alignWithMargins attribute - /// </summary> - public bool AlignWithMargins - { - get - { - return GetXmlNodeBool(alignWithMarginsPath); - } - set - { - SetXmlNodeString(alignWithMarginsPath, value ? "1" : "0"); - } - } - #endregion + private void SetText(string code, string text) { + switch (code) { + case "&L": + LeftAlignedText = text; + break; + case "&C": + CenteredText = text; + break; + default: + RightAlignedText = text; + break; + } + } - #region differentOddEven - const string differentOddEvenPath = "@differentOddEven"; - /// <summary> - /// Gets/sets the flag that tells Excel to display different headers and footers on odd and even pages. - /// </summary> - public bool differentOddEven - { - get - { - return GetXmlNodeBool(differentOddEvenPath); - } - set - { - SetXmlNodeString(differentOddEvenPath, value ? "1" : "0"); - } - } - #endregion + /// <summary> + /// Get/set the text to appear on the left hand side of the header (or footer) on the worksheet. + /// </summary> + public string LeftAlignedText; - #region differentFirst - const string differentFirstPath = "@differentFirst"; + /// <summary> + /// Get/set the text to appear in the center of the header (or footer) on the worksheet. + /// </summary> + public string CenteredText; - /// <summary> - /// Gets/sets the flag that tells Excel to display different headers and footers on the first page of the worksheet. - /// </summary> - public bool differentFirst - { - get - { - return GetXmlNodeBool(differentFirstPath); - } - set - { - SetXmlNodeString(differentFirstPath, value ? "1" : "0"); - } - } - #endregion + /// <summary> + /// Get/set the text to appear on the right hand side of the header (or footer) on the worksheet. + /// </summary> + public string RightAlignedText; +} - #region ExcelHeaderFooter Public Properties - /// <summary> - /// Provides access to the header on odd numbered pages of the document. - /// If you want the same header on both odd and even pages, then only set values in this ExcelHeaderFooterText class. - /// </summary> - public ExcelHeaderFooterText OddHeader - { - get - { - if (_oddHeader == null) - { - _oddHeader = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:oddHeader", NameSpaceManager), _ws, "H"); - } - return _oddHeader; } - } - /// <summary> - /// Provides access to the footer on odd numbered pages of the document. - /// If you want the same footer on both odd and even pages, then only set values in this ExcelHeaderFooterText class. - /// </summary> - public ExcelHeaderFooterText OddFooter - { - get - { - if (_oddFooter == null) - { - _oddFooter = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:oddFooter", NameSpaceManager), _ws, "F"); ; - } - return _oddFooter; - } - } - // evenHeader and evenFooter set differentOddEven = true - /// <summary> - /// Provides access to the header on even numbered pages of the document. - /// </summary> - public ExcelHeaderFooterText EvenHeader - { - get - { - if (_evenHeader == null) - { - _evenHeader = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:evenHeader", NameSpaceManager), _ws, "HEVEN"); - differentOddEven = true; - } - return _evenHeader; - } - } - /// <summary> - /// Provides access to the footer on even numbered pages of the document. - /// </summary> - public ExcelHeaderFooterText EvenFooter - { - get - { - if (_evenFooter == null) - { - _evenFooter = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:evenFooter", NameSpaceManager), _ws, "FEVEN"); - differentOddEven = true; - } - return _evenFooter ; - } - } - /// <summary> - /// Provides access to the header on the first page of the document. - /// </summary> - public ExcelHeaderFooterText FirstHeader - { - get - { - if (_firstHeader == null) - { - _firstHeader = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:firstHeader", NameSpaceManager), _ws, "HFIRST"); - differentFirst = true; - } - return _firstHeader; - } - } - /// <summary> - /// Provides access to the footer on the first page of the document. - /// </summary> - public ExcelHeaderFooterText FirstFooter - { - get - { - if (_firstFooter == null) - { - _firstFooter = new ExcelHeaderFooterText(TopNode.SelectSingleNode("d:firstFooter", NameSpaceManager), _ws, "FFIRST"); - differentFirst = true; - } - return _firstFooter; - } - } - #endregion - #region Save // ExcelHeaderFooter - /// <summary> - /// Saves the header and footer information to the worksheet XML - /// </summary> - internal void Save() - { - if (_oddHeader != null) - { - SetXmlNodeString("d:oddHeader", GetText(OddHeader)); - } - if (_oddFooter != null) - { - SetXmlNodeString("d:oddFooter", GetText(OddFooter)); - } +/// <summary> +/// Represents the Header and Footer on an Excel Worksheet +/// </summary> +public sealed class ExcelHeaderFooter : XmlHelper { + /// <summary> + /// The code for "current page #" + /// </summary> + public const string PageNumber = "&P"; - // only set evenHeader and evenFooter - if (differentOddEven) - { - if (_evenHeader != null) - { - SetXmlNodeString("d:evenHeader", GetText(EvenHeader)); - } - if (_evenFooter != null) - { - SetXmlNodeString("d:evenFooter", GetText(EvenFooter)); - } - } + /// <summary> + /// The code for "total pages" + /// </summary> + public const string NumberOfPages = "&N"; - // only set firstHeader and firstFooter - if (differentFirst) - { - if (_firstHeader != null) - { - SetXmlNodeString("d:firstHeader", GetText(FirstHeader)); - } - if (_firstFooter != null) - { - SetXmlNodeString("d:firstFooter", GetText(FirstFooter)); - } - } - } - private string GetText(ExcelHeaderFooterText headerFooter) - { - string ret = ""; - if (headerFooter.LeftAlignedText != null) - ret += "&L" + headerFooter.LeftAlignedText; - if (headerFooter.CenteredText != null) - ret += "&C" + headerFooter.CenteredText; - if (headerFooter.RightAlignedText != null) - ret += "&R" + headerFooter.RightAlignedText; - return ret; - } - #endregion - } - #endregion + /// <summary> + /// The code for "text font color" + /// RGB Color is specified as RRGGBB + /// Theme Color is specified as TTSNN where TT is the theme color Id, S is either "+" or "-" of the tint/shade value, NN is the tint/shade value. + /// </summary> + public const string FontColor = "&K"; + + /// <summary> + /// The code for "sheet tab name" + /// </summary> + public const string SheetName = "&A"; + + /// <summary> + /// The code for "this workbook's file path" + /// </summary> + public const string FilePath = "&Z"; + + /// <summary> + /// The code for "this workbook's file name" + /// </summary> + public const string FileName = "&F"; + + /// <summary> + /// The code for "date" + /// </summary> + public const string CurrentDate = "&D"; + + /// <summary> + /// The code for "time" + /// </summary> + public const string CurrentTime = "&T"; + + /// <summary> + /// The code for "picture as background" + /// </summary> + public const string Image = "&G"; + + /// <summary> + /// The code for "outline style" + /// </summary> + public const string OutlineStyle = "&O"; + + /// <summary> + /// The code for "shadow style" + /// </summary> + public const string ShadowStyle = "&H"; + + internal ExcelHeaderFooterText _oddHeader; + internal ExcelHeaderFooterText _oddFooter; + internal ExcelHeaderFooterText _evenHeader; + internal ExcelHeaderFooterText _evenFooter; + internal ExcelHeaderFooterText _firstHeader; + internal ExcelHeaderFooterText _firstFooter; + private ExcelWorksheet _ws; + + /// <summary> + /// ExcelHeaderFooter Constructor + /// </summary> + /// <param name="nameSpaceManager"></param> + /// <param name="topNode"></param> + /// <param name="ws">The worksheet</param> + internal ExcelHeaderFooter( + XmlNamespaceManager nameSpaceManager, + XmlNode topNode, + ExcelWorksheet ws) + : base(nameSpaceManager, topNode) { + _ws = ws; + SchemaNodeOrder = new[] { + "headerFooter", + "oddHeader", + "oddFooter", + "evenHeader", + "evenFooter", + "firstHeader", + "firstFooter", + }; + } + + private const string _alignWithMarginsPath = "@alignWithMargins"; + + /// <summary> + /// Gets/sets the alignWithMargins attribute + /// </summary> + public bool AlignWithMargins { + get => GetXmlNodeBool(_alignWithMarginsPath); + set => SetXmlNodeString(_alignWithMarginsPath, value ? "1" : "0"); + } + + private const string _differentOddEvenPath = "@differentOddEven"; + + /// <summary> + /// Gets/sets the flag that tells Excel to display different headers and footers on odd and even pages. + /// </summary> + public bool differentOddEven { + get => GetXmlNodeBool(_differentOddEvenPath); + set => SetXmlNodeString(_differentOddEvenPath, value ? "1" : "0"); + } + + private const string _differentFirstPath = "@differentFirst"; + + /// <summary> + /// Gets/sets the flag that tells Excel to display different headers and footers on the first page of the worksheet. + /// </summary> + public bool differentFirst { + get => GetXmlNodeBool(_differentFirstPath); + set => SetXmlNodeString(_differentFirstPath, value ? "1" : "0"); + } + + /// <summary> + /// Provides access to the header on odd numbered pages of the document. + /// If you want the same header on both odd and even pages, then only set values in this ExcelHeaderFooterText class. + /// </summary> + public ExcelHeaderFooterText OddHeader { + get { + if (_oddHeader == null) { + _oddHeader = new(TopNode.SelectSingleNode("d:oddHeader", NameSpaceManager), _ws, "H"); + } + return _oddHeader; + } + } + + /// <summary> + /// Provides access to the footer on odd numbered pages of the document. + /// If you want the same footer on both odd and even pages, then only set values in this ExcelHeaderFooterText class. + /// </summary> + public ExcelHeaderFooterText OddFooter { + get { + if (_oddFooter == null) { + _oddFooter = new(TopNode.SelectSingleNode("d:oddFooter", NameSpaceManager), _ws, "F"); + ; + } + return _oddFooter; + } + } + + // evenHeader and evenFooter set differentOddEven = true + /// <summary> + /// Provides access to the header on even numbered pages of the document. + /// </summary> + public ExcelHeaderFooterText EvenHeader { + get { + if (_evenHeader == null) { + _evenHeader = new(TopNode.SelectSingleNode("d:evenHeader", NameSpaceManager), _ws, "HEVEN"); + differentOddEven = true; + } + return _evenHeader; + } + } + + /// <summary> + /// Provides access to the footer on even numbered pages of the document. + /// </summary> + public ExcelHeaderFooterText EvenFooter { + get { + if (_evenFooter == null) { + _evenFooter = new(TopNode.SelectSingleNode("d:evenFooter", NameSpaceManager), _ws, "FEVEN"); + differentOddEven = true; + } + return _evenFooter; + } + } + + /// <summary> + /// Provides access to the header on the first page of the document. + /// </summary> + public ExcelHeaderFooterText FirstHeader { + get { + if (_firstHeader == null) { + _firstHeader = new( + TopNode.SelectSingleNode("d:firstHeader", NameSpaceManager), + _ws, + "HFIRST"); + differentFirst = true; + } + return _firstHeader; + } + } + + /// <summary> + /// Provides access to the footer on the first page of the document. + /// </summary> + public ExcelHeaderFooterText FirstFooter { + get { + if (_firstFooter == null) { + _firstFooter = new( + TopNode.SelectSingleNode("d:firstFooter", NameSpaceManager), + _ws, + "FFIRST"); + differentFirst = true; + } + return _firstFooter; + } + } + + /// <summary> + /// Saves the header and footer information to the worksheet XML + /// </summary> + internal void Save() { + if (_oddHeader != null) { + SetXmlNodeString("d:oddHeader", GetText(OddHeader)); + } + if (_oddFooter != null) { + SetXmlNodeString("d:oddFooter", GetText(OddFooter)); + } + + // only set evenHeader and evenFooter + if (differentOddEven) { + if (_evenHeader != null) { + SetXmlNodeString("d:evenHeader", GetText(EvenHeader)); + } + if (_evenFooter != null) { + SetXmlNodeString("d:evenFooter", GetText(EvenFooter)); + } + } + + // only set firstHeader and firstFooter + if (differentFirst) { + if (_firstHeader != null) { + SetXmlNodeString("d:firstHeader", GetText(FirstHeader)); + } + if (_firstFooter != null) { + SetXmlNodeString("d:firstFooter", GetText(FirstFooter)); + } + } + } + + private string GetText(ExcelHeaderFooterText headerFooter) { + string ret = ""; + if (headerFooter.LeftAlignedText != null) { + ret += "&L" + headerFooter.LeftAlignedText; + } + if (headerFooter.CenteredText != null) { + ret += "&C" + headerFooter.CenteredText; + } + if (headerFooter.RightAlignedText != null) { + ret += "&R" + headerFooter.RightAlignedText; + } + return ret; + } }
diff --git a/EPPlus/ExcelHyperLink.cs b/EPPlus/ExcelHyperLink.cs index 3d1a027..dc4aa3b 100644 --- a/EPPlus/ExcelHyperLink.cs +++ b/EPPlus/ExcelHyperLink.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,155 +13,125 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added this class 2010-01-24 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -namespace OfficeOpenXml -{ - /// <summary> - /// HyperlinkClass - /// </summary> - public class ExcelHyperLink : Uri - { - /// <summary> - /// A new hyperlink with the specified URI - /// </summary> - /// <param name="uriString">The URI</param> - public ExcelHyperLink(string uriString) : - base(uriString) - { - OriginalUri = (Uri)this; - } - /// <summary> - /// A new hyperlink with the specified URI. This syntax is obsolete - /// </summary> - /// <param name="uriString">The URI</param> - /// <param name="dontEscape"></param> - [Obsolete("base constructor 'System.Uri.Uri(string, bool)' is obsolete: 'The constructor has been deprecated. Please use new ExcelHyperLink(string). The dontEscape parameter is deprecated and is always false.")] - public ExcelHyperLink(string uriString, bool dontEscape) : - base(uriString, dontEscape) - { - OriginalUri = (Uri)this; - } - /// <summary> - /// A new hyperlink with the specified URI and kind - /// </summary> - /// <param name="uriString">The URI</param> - /// <param name="uriKind">Kind (absolute/relative or indeterminate)</param> - public ExcelHyperLink(string uriString, UriKind uriKind) : - base(uriString, uriKind) - { - OriginalUri = (Uri)this; - } - /// <summary> - /// Sheet internal reference - /// </summary> - /// <param name="referenceAddress">Address</param> - /// <param name="display">Displayed text</param> - public ExcelHyperLink(string referenceAddress, string display) : - base("xl://internal") //URI is not used on internal links so put a dummy uri here. - { - _referenceAddress = referenceAddress; - _display = display; - } - string _referenceAddress = null; - /// <summary> - /// The Excel address for internal links. - /// </summary> - public string ReferenceAddress - { - get - { - return _referenceAddress; - } - set - { - _referenceAddress = value; - } - } - string _display = ""; - /// <summary> - /// Displayed text - /// </summary> - public string Display - { - get - { - return _display; - } - set - { - _display = value; - } - } - /// <summary> - /// Tooltip - /// </summary> - public string ToolTip - { - get; - set; - } - int _colSpann = 0; - /// <summary> - /// If the hyperlink spans multiple columns - /// </summary> - public int ColSpann - { - get - { - return _colSpann; - } - set - { - _colSpann = value; - } - } - int _rowSpann = 0; - /// <summary> - /// If the hyperlink spans multiple rows - /// </summary> - public int RowSpann - { - get - { - return _rowSpann; - } - set - { - _rowSpann = value; - } - } - /// <summary> - /// Used to handle non absolute URI's. - /// Is used if IsAblsoluteUri is true. The base URI will have a dummy value of xl://nonAbsolute. - /// </summary> - public Uri OriginalUri - { - get; - internal set; - } - internal string RId - { - get; - set; - } - } +using System; + +namespace OfficeOpenXml; + +/// <summary> +/// HyperlinkClass +/// </summary> +public class ExcelHyperLink : Uri { + /// <summary> + /// A new hyperlink with the specified URI + /// </summary> + /// <param name="uriString">The URI</param> + public ExcelHyperLink(string uriString) + : base(uriString) { + OriginalUri = this; + } + + /// <summary> + /// A new hyperlink with the specified URI. This syntax is obsolete + /// </summary> + /// <param name="uriString">The URI</param> + /// <param name="dontEscape"></param> + [Obsolete( + "base constructor 'System.Uri.Uri(string, bool)' is obsolete: 'The constructor has been deprecated. Please use new ExcelHyperLink(string). The dontEscape parameter is deprecated and is always false.")] + public ExcelHyperLink(string uriString, bool dontEscape) + : base(uriString, dontEscape) { + OriginalUri = this; + } + + /// <summary> + /// A new hyperlink with the specified URI and kind + /// </summary> + /// <param name="uriString">The URI</param> + /// <param name="uriKind">Kind (absolute/relative or indeterminate)</param> + public ExcelHyperLink(string uriString, UriKind uriKind) + : base(uriString, uriKind) { + OriginalUri = this; + } + + /// <summary> + /// Sheet internal reference + /// </summary> + /// <param name="referenceAddress">Address</param> + /// <param name="display">Displayed text</param> + public ExcelHyperLink(string referenceAddress, string display) + : base( + "xl://internal") //URI is not used on internal links so put a dummy uri here. + { + _referenceAddress = referenceAddress; + _display = display; + } + + private string _referenceAddress; + + /// <summary> + /// The Excel address for internal links. + /// </summary> + public string ReferenceAddress { + get => _referenceAddress; + set => _referenceAddress = value; + } + + private string _display = ""; + + /// <summary> + /// Displayed text + /// </summary> + public string Display { + get => _display; + set => _display = value; + } + + /// <summary> + /// Tooltip + /// </summary> + public string ToolTip { get; set; } + + private int _colSpann; + + /// <summary> + /// If the hyperlink spans multiple columns + /// </summary> + public int ColSpann { + get => _colSpann; + set => _colSpann = value; + } + + private int _rowSpann; + + /// <summary> + /// If the hyperlink spans multiple rows + /// </summary> + public int RowSpann { + get => _rowSpann; + set => _rowSpann = value; + } + + /// <summary> + /// Used to handle non absolute URI's. + /// Is used if IsAblsoluteUri is true. The base URI will have a dummy value of xl://nonAbsolute. + /// </summary> + public Uri OriginalUri { get; internal set; } + + internal string RId { get; set; } }
diff --git a/EPPlus/ExcelNamedRange.cs b/EPPlus/ExcelNamedRange.cs index e8bef17..da86830 100644 --- a/EPPlus/ExcelNamedRange.cs +++ b/EPPlus/ExcelNamedRange.cs
@@ -13,110 +13,92 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added this class 2010-01-28 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -namespace OfficeOpenXml -{ - /// <summary> - /// A named range. - /// </summary> - public sealed class ExcelNamedRange : ExcelRangeBase - { - ExcelWorksheet _sheet; - /// <summary> - /// A named range - /// </summary> - /// <param name="name">The name</param> - /// <param name="nameSheet">The sheet containing the name. null if its a global name</param> - /// <param name="sheet">Sheet where the address points</param> - /// <param name="address">The address</param> - /// <param name="index">The index in the collection</param> - public ExcelNamedRange(string name, ExcelWorksheet nameSheet , ExcelWorksheet sheet, string address, int index) : - base(sheet, address) - { - Name = name; - _sheet = nameSheet; - Index = index; +namespace OfficeOpenXml; - } - internal ExcelNamedRange(string name,ExcelWorkbook wb, ExcelWorksheet nameSheet, int index) : - base(wb, nameSheet, name, true) - { - Name = name; - _sheet = nameSheet; - Index = index; - } +/// <summary> +/// A named range. +/// </summary> +public sealed class ExcelNamedRange : ExcelRangeBase { + private ExcelWorksheet _sheet; - /// <summary> - /// Name of the range - /// </summary> - public string Name - { - get; - internal set; - } - /// <summary> - /// Is the named range local for the sheet - /// </summary> - public int LocalSheetId - { - get - { - if (_sheet == null) - { - return -1; - } - else - { - return _sheet.PositionID-1; - } - } - } - internal int Index - { - get; - set; - } - /// <summary> - /// Is the name hidden - /// </summary> - public bool IsNameHidden - { - get; - set; - } - /// <summary> - /// A comment for the Name - /// </summary> - public string NameComment - { - get; - set; - } - internal object NameValue { get; set; } - internal string NameFormula { get; set; } - public override string ToString() - { - return Name; - } + /// <summary> + /// A named range + /// </summary> + /// <param name="name">The name</param> + /// <param name="nameSheet">The sheet containing the name. null if its a global name</param> + /// <param name="sheet">Sheet where the address points</param> + /// <param name="address">The address</param> + /// <param name="index">The index in the collection</param> + public ExcelNamedRange( + string name, + ExcelWorksheet nameSheet, + ExcelWorksheet sheet, + string address, + int index) + : base(sheet, address) { + Name = name; + _sheet = nameSheet; + Index = index; + } + internal ExcelNamedRange(string name, ExcelWorkbook wb, ExcelWorksheet nameSheet, int index) + : base(wb, nameSheet, name, true) { + Name = name; + _sheet = nameSheet; + Index = index; + } + + /// <summary> + /// Name of the range + /// </summary> + public string Name { get; internal set; } + + /// <summary> + /// Is the named range local for the sheet + /// </summary> + public int LocalSheetId { + get { + if (_sheet == null) { + return -1; + } + return _sheet.PositionID - 1; } + } + + internal int Index { get; set; } + + /// <summary> + /// Is the name hidden + /// </summary> + public bool IsNameHidden { get; set; } + + /// <summary> + /// A comment for the Name + /// </summary> + public string NameComment { get; set; } + + internal object NameValue { get; set; } + + internal string NameFormula { get; set; } + + public override string ToString() { + return Name; + } }
diff --git a/EPPlus/ExcelNamedRangeCollection.cs b/EPPlus/ExcelNamedRangeCollection.cs index 2cad528..ab281f9 100644 --- a/EPPlus/ExcelNamedRangeCollection.cs +++ b/EPPlus/ExcelNamedRangeCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,228 +13,198 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added this class 2010-01-28 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; using System.Collections; +using System.Collections.Generic; -namespace OfficeOpenXml -{ - /// <summary> - /// Collection for named ranges - /// </summary> - public class ExcelNamedRangeCollection : IEnumerable<ExcelNamedRange> - { - internal ExcelWorksheet _ws; - internal ExcelWorkbook _wb; - internal ExcelNamedRangeCollection(ExcelWorkbook wb) - { - _wb = wb; - _ws = null; - } - internal ExcelNamedRangeCollection(ExcelWorkbook wb, ExcelWorksheet ws) - { - _wb = wb; - _ws = ws; - } - List<ExcelNamedRange> _list = new List<ExcelNamedRange>(); - Dictionary<string, int> _dic = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase); - /// <summary> - /// Add a new named range - /// </summary> - /// <param name="Name">The name</param> - /// <param name="Range">The range</param> - /// <returns></returns> - public ExcelNamedRange Add(string Name, ExcelRangeBase Range) - { - ExcelNamedRange item; - if (Range.IsName) - { +namespace OfficeOpenXml; - item = new ExcelNamedRange(Name, _wb,_ws, _dic.Count); - } - else - { - item = new ExcelNamedRange(Name, _ws, Range.Worksheet, Range.Address, _dic.Count); - } +/// <summary> +/// Collection for named ranges +/// </summary> +public class ExcelNamedRangeCollection : IEnumerable<ExcelNamedRange> { + internal ExcelWorksheet _ws; + internal ExcelWorkbook _wb; - AddName(Name, item); + internal ExcelNamedRangeCollection(ExcelWorkbook wb) { + _wb = wb; + _ws = null; + } - return item; - } + internal ExcelNamedRangeCollection(ExcelWorkbook wb, ExcelWorksheet ws) { + _wb = wb; + _ws = ws; + } - private void AddName(string Name, ExcelNamedRange item) - { - // Is 'Name' already present - if (_dic.ContainsKey(Name)) - { - int index = _dic[Name]; - if ((0 <= index) && (index < _list.Count)) - { - ExcelNamedRange listItem = _list[index]; - if ((listItem != null) && (listItem.FullAddress != null) && (listItem.FullAddress == item.FullAddress)) - return; + private List<ExcelNamedRange> _list = new(); + private Dictionary<string, int> _dic = new(StringComparer.InvariantCultureIgnoreCase); - //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once. First as '{1}' and second as '{2}'.", Name, listItem.FullAddress, item.FullAddress)); - return; - } - - //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once.", Name)); - return; - } - - _dic.Add(Name, _list.Count); - _list.Add(item); - } - /// <summary> - /// Add a defined name referencing value - /// </summary> - /// <param name="Name"></param> - /// <param name="value"></param> - /// <returns></returns> - public ExcelNamedRange AddValue(string Name, object value) - { - var item = new ExcelNamedRange(Name,_wb, _ws, _dic.Count); - item.NameValue = value; - AddName(Name, item); - return item; - } - - /// <summary> - /// Add a defined name referencing a formula -- the method name contains a typo. - /// This method is obsolete and will be removed in the future. - /// Use <see cref="AddFormula"/> - /// </summary> - /// <param name="Name"></param> - /// <param name="Formula"></param> - /// <returns></returns> - [Obsolete("Call AddFormula() instead. See Issue Tracker Id #14687")] - public ExcelNamedRange AddFormla(string Name, string Formula) - { - return this.AddFormula(Name, Formula); - } - - /// <summary> - /// Add a defined name referencing a formula - /// </summary> - /// <param name="Name"></param> - /// <param name="Formula"></param> - /// <returns></returns> - public ExcelNamedRange AddFormula(string Name, string Formula) - { - var item = new ExcelNamedRange(Name, _wb, _ws, _dic.Count); - item.NameFormula = Formula; - AddName(Name, item); - return item; - } - /// <summary> - /// Remove a defined name from the collection - /// </summary> - /// <param name="Name">The name</param> - public void Remove(string Name) - { - if(_dic.ContainsKey(Name)) - { - var ix = _dic[Name]; - - for (int i = ix+1; i < _list.Count; i++) - { - _dic.Remove(_list[i].Name); - _list[i].Index--; - _dic.Add(_list[i].Name, _list[i].Index); - } - _dic.Remove(Name); - _list.RemoveAt(ix); - } - } - /// <summary> - /// Checks collection for the presence of a key - /// </summary> - /// <param name="key">key to search for</param> - /// <returns>true if the key is in the collection</returns> - public bool ContainsKey(string key) - { - return _dic.ContainsKey(key); - } - /// <summary> - /// The current number of items in the collection - /// </summary> - public int Count - { - get - { - return _dic.Count; - } - } - /// <summary> - /// Name indexer - /// </summary> - /// <param name="Name">The name (key) for a Named range</param> - /// <returns>a reference to the range</returns> - /// <remarks> - /// Throws a KeyNotFoundException if the key is not in the collection. - /// </remarks> - public ExcelNamedRange this[string Name] - { - get - { - return _list[_dic[Name]]; - } - } - public ExcelNamedRange this[int Index] - { - get - { - return _list[Index]; - } - } - - #region "IEnumerable" - #region IEnumerable<ExcelNamedRange> Members - /// <summary> - /// Implement interface method IEnumerator<ExcelNamedRange> GetEnumerator() - /// </summary> - /// <returns></returns> - public IEnumerator<ExcelNamedRange> GetEnumerator() - { - return _list.GetEnumerator(); - } - #endregion - #region IEnumerable Members - /// <summary> - /// Implement interface method IEnumeratable GetEnumerator() - /// </summary> - /// <returns></returns> - IEnumerator IEnumerable.GetEnumerator() - { - return _list.GetEnumerator(); - } - - #endregion - #endregion - - internal void Clear() - { - while(Count>0) - { - Remove(_list[0].Name); - } - } + /// <summary> + /// Add a new named range + /// </summary> + /// <param name="name">The name</param> + /// <param name="range">The range</param> + /// <returns></returns> + public ExcelNamedRange Add(string name, ExcelRangeBase range) { + ExcelNamedRange item; + if (range.IsName) { + item = new(name, _wb, _ws, _dic.Count); + } else { + item = new(name, _ws, range.Worksheet, range.Address, _dic.Count); } + + AddName(name, item); + + return item; + } + + private void AddName(string name, ExcelNamedRange item) { + // Is 'Name' already present + if (_dic.ContainsKey(name)) { + int index = _dic[name]; + if ((0 <= index) && (index < _list.Count)) { + ExcelNamedRange listItem = _list[index]; + if ((listItem != null) + && (listItem.FullAddress != null) + && (listItem.FullAddress == item.FullAddress)) { + return; + } + + //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once. First as '{1}' and second as '{2}'.", Name, listItem.FullAddress, item.FullAddress)); + return; + } + + //throw new Exception(string.Format("Name '{0}' is defined in the worksheet more than once.", Name)); + return; + } + + _dic.Add(name, _list.Count); + _list.Add(item); + } + + /// <summary> + /// Add a defined name referencing value + /// </summary> + /// <param name="name"></param> + /// <param name="value"></param> + /// <returns></returns> + public ExcelNamedRange AddValue(string name, object value) { + var item = new ExcelNamedRange(name, _wb, _ws, _dic.Count); + item.NameValue = value; + AddName(name, item); + return item; + } + + /// <summary> + /// Add a defined name referencing a formula -- the method name contains a typo. + /// This method is obsolete and will be removed in the future. + /// Use <see cref="AddFormula"/> + /// </summary> + /// <param name="name"></param> + /// <param name="formula"></param> + /// <returns></returns> + [Obsolete("Call AddFormula() instead. See Issue Tracker Id #14687")] + public ExcelNamedRange AddFormla(string name, string formula) { + return AddFormula(name, formula); + } + + /// <summary> + /// Add a defined name referencing a formula + /// </summary> + /// <param name="name"></param> + /// <param name="formula"></param> + /// <returns></returns> + public ExcelNamedRange AddFormula(string name, string formula) { + var item = new ExcelNamedRange(name, _wb, _ws, _dic.Count); + item.NameFormula = formula; + AddName(name, item); + return item; + } + + /// <summary> + /// Remove a defined name from the collection + /// </summary> + /// <param name="name">The name</param> + public void Remove(string name) { + if (_dic.ContainsKey(name)) { + var ix = _dic[name]; + + for (int i = ix + 1; i < _list.Count; i++) { + _dic.Remove(_list[i].Name); + _list[i].Index--; + _dic.Add(_list[i].Name, _list[i].Index); + } + _dic.Remove(name); + _list.RemoveAt(ix); + } + } + + /// <summary> + /// Checks collection for the presence of a key + /// </summary> + /// <param name="key">key to search for</param> + /// <returns>true if the key is in the collection</returns> + public bool ContainsKey(string key) { + return _dic.ContainsKey(key); + } + + /// <summary> + /// The current number of items in the collection + /// </summary> + public int Count => _dic.Count; + + /// <summary> + /// Name indexer + /// </summary> + /// <param name="name">The name (key) for a Named range</param> + /// <returns>a reference to the range</returns> + /// <remarks> + /// Throws a KeyNotFoundException if the key is not in the collection. + /// </remarks> + public ExcelNamedRange this[string name] { + get { return _list[_dic[name]]; } + } + + public ExcelNamedRange this[int index] { + get { return _list[index]; } + } + + /// <summary> + /// Implement interface method IEnumerator<ExcelNamedRange> GetEnumerator() + /// </summary> + /// <returns></returns> + public IEnumerator<ExcelNamedRange> GetEnumerator() { + return _list.GetEnumerator(); + } + + /// <summary> + /// Implement interface method IEnumeratable GetEnumerator() + /// </summary> + /// <returns></returns> + IEnumerator IEnumerable.GetEnumerator() { + return _list.GetEnumerator(); + } + + internal void Clear() { + while (Count > 0) { + Remove(_list[0].Name); + } + } }
diff --git a/EPPlus/ExcelPackage.cs b/EPPlus/ExcelPackage.cs index 78c4083..5bd9395 100644 --- a/EPPlus/ExcelPackage.cs +++ b/EPPlus/ExcelPackage.cs
@@ -13,352 +13,349 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 - * Starnuto Di Topo & Jan Källman Added stream constructors - * and Load method Save as + * Starnuto Di Topo & Jan Källman Added stream constructors + * and Load method Save as * stream 2010-03-14 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Xml; using System.IO; -using System.Collections.Generic; -using System.Security.Cryptography; +using System.Xml; +using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils; -namespace OfficeOpenXml -{ - /// <summary> - /// Maps to DotNetZips CompressionLevel enum - /// </summary> - public enum CompressionLevel - { - Level0 = 0, - None = 0, - Level1 = 1, - BestSpeed = 1, - Level2 = 2, - Level3 = 3, - Level4 = 4, - Level5 = 5, - Level6 = 6, - Default = 6, - Level7 = 7, - Level8 = 8, - BestCompression = 9, - Level9 = 9, - } - /// <summary> - /// Represents an Excel 2007/2010 XLSX file package. - /// This is the top-level object to access all parts of the document. - /// <code> - /// FileInfo newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx"); - /// if (newFile.Exists) - /// { - /// newFile.Delete(); // ensures we create a new workbook - /// newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx"); - /// } - /// using (ExcelPackage package = new ExcelPackage(newFile)) - /// { - /// // add a new worksheet to the empty workbook - /// ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Inventory"); - /// //Add the headers - /// worksheet.Cells[1, 1].Value = "ID"; - /// worksheet.Cells[1, 2].Value = "Product"; - /// worksheet.Cells[1, 3].Value = "Quantity"; - /// worksheet.Cells[1, 4].Value = "Price"; - /// worksheet.Cells[1, 5].Value = "Value"; - /// - /// //Add some items... - /// worksheet.Cells["A2"].Value = "12001"; - /// worksheet.Cells["B2"].Value = "Nails"; - /// worksheet.Cells["C2"].Value = 37; - /// worksheet.Cells["D2"].Value = 3.99; - /// - /// worksheet.Cells["A3"].Value = "12002"; - /// worksheet.Cells["B3"].Value = "Hammer"; - /// worksheet.Cells["C3"].Value = 5; - /// worksheet.Cells["D3"].Value = 12.10; - /// - /// worksheet.Cells["A4"].Value = "12003"; - /// worksheet.Cells["B4"].Value = "Saw"; - /// worksheet.Cells["C4"].Value = 12; - /// worksheet.Cells["D4"].Value = 15.37; - /// - /// //Add a formula for the value-column - /// worksheet.Cells["E2:E4"].Formula = "C2*D2"; - /// - /// //Ok now format the values; - /// using (var range = worksheet.Cells[1, 1, 1, 5]) - /// { - /// range.Style.Font.Bold = true; - /// range.Style.Fill.PatternType = ExcelFillStyle.Solid; - /// range.Style.Fill.BackgroundColor.SetColor(Color.DarkBlue); - /// range.Style.Font.Color.SetColor(Color.White); - /// } - /// - /// worksheet.Cells["A5:E5"].Style.Border.Top.Style = ExcelBorderStyle.Thin; - /// worksheet.Cells["A5:E5"].Style.Font.Bold = true; - /// - /// worksheet.Cells[5, 3, 5, 5].Formula = string.Format("SUBTOTAL(9,{0})", new ExcelAddress(2,3,4,3).Address); - /// worksheet.Cells["C2:C5"].Style.Numberformat.Format = "#,##0"; - /// worksheet.Cells["D2:E5"].Style.Numberformat.Format = "#,##0.00"; - /// - /// //Create an autofilter for the range - /// worksheet.Cells["A1:E4"].AutoFilter = true; - /// - /// worksheet.Cells["A1:E5"].AutoFitColumns(0); - /// - /// // lets set the header text - /// worksheet.HeaderFooter.oddHeader.CenteredText = "&24&U&\"Arial,Regular Bold\" Inventory"; - /// // add the page number to the footer plus the total number of pages - /// worksheet.HeaderFooter.oddFooter.RightAlignedText = - /// string.Format("Page {0} of {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages); - /// // add the sheet name to the footer - /// worksheet.HeaderFooter.oddFooter.CenteredText = ExcelHeaderFooter.SheetName; - /// // add the file path to the footer - /// worksheet.HeaderFooter.oddFooter.LeftAlignedText = ExcelHeaderFooter.FilePath + ExcelHeaderFooter.FileName; - /// - /// worksheet.PrinterSettings.RepeatRows = worksheet.Cells["1:2"]; - /// worksheet.PrinterSettings.RepeatColumns = worksheet.Cells["A:G"]; - /// - /// // Change the sheet view to show it in page layout mode - /// worksheet.View.PageLayoutView = true; - /// - /// // set some document properties - /// package.Workbook.Properties.Title = "Invertory"; - /// package.Workbook.Properties.Author = "Jan K�llman"; - /// package.Workbook.Properties.Comments = "This sample demonstrates how to create an Excel 2007 workbook using EPPlus"; - /// - /// // set some extended property values - /// package.Workbook.Properties.Company = "AdventureWorks Inc."; - /// - /// // set some custom property values - /// package.Workbook.Properties.SetCustomPropertyValue("Checked by", "Jan K�llman"); - /// package.Workbook.Properties.SetCustomPropertyValue("AssemblyName", "EPPlus"); - /// - /// // save our new workbook and we are done! - /// package.Save(); - /// - /// } - /// - /// return newFile.FullName; - /// </code> - /// More samples can be found at <a href="http://epplus.codeplex.com/">http://epplus.codeplex.com/</a> - /// </summary> - public sealed class ExcelPackage - { - internal const bool preserveWhitespace=false; - - #region Properties - /// <summary> - /// Extention Schema types - /// </summary> - internal const string schemaXmlExtension = "application/xml"; - internal const string schemaRelsExtension = "application/vnd.openxmlformats-package.relationships+xml"; - /// <summary> - /// Main Xml schema name - /// </summary> - internal const string schemaMain = @"http://schemas.openxmlformats.org/spreadsheetml/2006/main"; - /// <summary> - /// Relationship schema name - /// </summary> - internal const string schemaRelationships = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships"; - - internal const string schemaDrawings = @"http://schemas.openxmlformats.org/drawingml/2006/main"; - internal const string schemaMicrosoftVml = @"urn:schemas-microsoft-com:vml"; - internal const string schemaMicrosoftOffice = "urn:schemas-microsoft-com:office:office"; - internal const string schemaMicrosoftExcel = "urn:schemas-microsoft-com:office:excel"; +namespace OfficeOpenXml; - internal const string schemaChart = @"http://schemas.openxmlformats.org/drawingml/2006/chart"; - internal const string schemaHyperlink = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"; - internal const string schemaComment = @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"; - //Office properties - internal const string schemaCore = @"http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; - internal const string schemaExtended = @"http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"; - internal const string schemaCustom = @"http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"; - internal const string schemaDc = @"http://purl.org/dc/elements/1.1/"; - internal const string schemaDcTerms = @"http://purl.org/dc/terms/"; - internal const string schemaDcmiType = @"http://purl.org/dc/dcmitype/"; - internal const string schemaXsi = @"http://www.w3.org/2001/XMLSchema-instance"; - internal const string schemaVt = @"http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"; +/// <summary> +/// Maps to DotNetZips CompressionLevel enum +/// </summary> +public enum CompressionLevel { + Level0 = 0, + None = 0, + Level1 = 1, + BestSpeed = 1, + Level2 = 2, + Level3 = 3, + Level4 = 4, + Level5 = 5, + Level6 = 6, + Default = 6, + Level7 = 7, + Level8 = 8, + BestCompression = 9, + Level9 = 9, +} - //Pivottables - internal const string schemaPivotTable = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"; - internal const string schemaPivotCacheDefinition = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"; - internal const string schemaPivotCacheRecords = @"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"; +/// <summary> +/// Represents an Excel 2007/2010 XLSX file package. +/// This is the top-level object to access all parts of the document. +/// <code> +/// FileInfo newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx"); +/// if (newFile.Exists) +/// { +/// newFile.Delete(); // ensures we create a new workbook +/// newFile = new FileInfo(outputDir.FullName + @"\sample1.xlsx"); +/// } +/// using (ExcelPackage package = new ExcelPackage(newFile)) +/// { +/// // add a new worksheet to the empty workbook +/// ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Inventory"); +/// //Add the headers +/// worksheet.Cells[1, 1].Value = "ID"; +/// worksheet.Cells[1, 2].Value = "Product"; +/// worksheet.Cells[1, 3].Value = "Quantity"; +/// worksheet.Cells[1, 4].Value = "Price"; +/// worksheet.Cells[1, 5].Value = "Value"; +/// +/// //Add some items... +/// worksheet.Cells["A2"].Value = "12001"; +/// worksheet.Cells["B2"].Value = "Nails"; +/// worksheet.Cells["C2"].Value = 37; +/// worksheet.Cells["D2"].Value = 3.99; +/// +/// worksheet.Cells["A3"].Value = "12002"; +/// worksheet.Cells["B3"].Value = "Hammer"; +/// worksheet.Cells["C3"].Value = 5; +/// worksheet.Cells["D3"].Value = 12.10; +/// +/// worksheet.Cells["A4"].Value = "12003"; +/// worksheet.Cells["B4"].Value = "Saw"; +/// worksheet.Cells["C4"].Value = 12; +/// worksheet.Cells["D4"].Value = 15.37; +/// +/// //Add a formula for the value-column +/// worksheet.Cells["E2:E4"].Formula = "C2*D2"; +/// +/// //Ok now format the values; +/// using (var range = worksheet.Cells[1, 1, 1, 5]) +/// { +/// range.Style.Font.Bold = true; +/// range.Style.Fill.PatternType = ExcelFillStyle.Solid; +/// range.Style.Fill.BackgroundColor.SetColor(Color.DarkBlue); +/// range.Style.Font.Color.SetColor(Color.White); +/// } +/// +/// worksheet.Cells["A5:E5"].Style.Border.Top.Style = ExcelBorderStyle.Thin; +/// worksheet.Cells["A5:E5"].Style.Font.Bold = true; +/// +/// worksheet.Cells[5, 3, 5, 5].Formula = string.Format("SUBTOTAL(9,{0})", new ExcelAddress(2,3,4,3).Address); +/// worksheet.Cells["C2:C5"].Style.Numberformat.Format = "#,##0"; +/// worksheet.Cells["D2:E5"].Style.Numberformat.Format = "#,##0.00"; +/// +/// //Create an autofilter for the range +/// worksheet.Cells["A1:E4"].AutoFilter = true; +/// +/// worksheet.Cells["A1:E5"].AutoFitColumns(0); +/// +/// // lets set the header text +/// worksheet.HeaderFooter.oddHeader.CenteredText = "&24&U&\"Arial,Regular Bold\" Inventory"; +/// // add the page number to the footer plus the total number of pages +/// worksheet.HeaderFooter.oddFooter.RightAlignedText = +/// string.Format("Page {0} of {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages); +/// // add the sheet name to the footer +/// worksheet.HeaderFooter.oddFooter.CenteredText = ExcelHeaderFooter.SheetName; +/// // add the file path to the footer +/// worksheet.HeaderFooter.oddFooter.LeftAlignedText = ExcelHeaderFooter.FilePath + ExcelHeaderFooter.FileName; +/// +/// worksheet.PrinterSettings.RepeatRows = worksheet.Cells["1:2"]; +/// worksheet.PrinterSettings.RepeatColumns = worksheet.Cells["A:G"]; +/// +/// // Change the sheet view to show it in page layout mode +/// worksheet.View.PageLayoutView = true; +/// +/// // set some document properties +/// package.Workbook.Properties.Title = "Invertory"; +/// package.Workbook.Properties.Author = "Jan K�llman"; +/// package.Workbook.Properties.Comments = "This sample demonstrates how to create an Excel 2007 workbook using EPPlus"; +/// +/// // set some extended property values +/// package.Workbook.Properties.Company = "AdventureWorks Inc."; +/// +/// // set some custom property values +/// package.Workbook.Properties.SetCustomPropertyValue("Checked by", "Jan K�llman"); +/// package.Workbook.Properties.SetCustomPropertyValue("AssemblyName", "EPPlus"); +/// +/// // save our new workbook and we are done! +/// package.Save(); +/// +/// } +/// +/// return newFile.FullName; +/// </code> +/// More samples can be found at <a href="http://epplus.codeplex.com/">http://epplus.codeplex.com/</a> +/// </summary> +public sealed class ExcelPackage { + internal const bool _preserveWhitespace = false; - internal const string contentTypeWorkbookDefault = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"; - internal const string contentTypeWorkbookMacroEnabled = "application/vnd.ms-excel.sheet.macroEnabled.main+xml"; - internal const string contentTypeSharedString = @"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"; - /// <summary> - /// Maximum number of columns in a worksheet (16384). - /// </summary> - public const int MaxColumns = 16384; - /// <summary> - /// Maximum number of rows in a worksheet (1048576). - /// </summary> - public const int MaxRows = 1048576; - #endregion + /// <summary> + /// Extention Schema types + /// </summary> + internal const string _schemaXmlExtension = "application/xml"; + internal const string _schemaRelsExtension = + "application/vnd.openxmlformats-package.relationships+xml"; - #region ExcelPackage Constructors - /// <summary> - /// Create a new instance of the ExcelPackage. Output is accessed through the Stream property. - /// </summary> - public ExcelPackage() - { - Package = new(); - Workbook = CreateWorkbook(); - _ = Workbook.WorkbookXml; - // create the relationship to the main part - Package.CreateRelationship(UriHelper.GetRelativeUri(new Uri("/xl", UriKind.Relative), Workbook.WorkbookUri), Packaging.TargetMode.Internal, schemaRelationships + "/officeDocument"); - } - - /// <summary> - /// Create a new instance of the ExcelPackage class based on a existing file or creates a new file. - /// </summary> - /// <param name="newFile">If newFile exists, it is opened. Otherwise it is created from scratch.</param> - public ExcelPackage(FileInfo newFile) - { - using var inputStream = newFile.OpenRead(); - Package = new(inputStream); - Workbook = CreateWorkbook(); - } - - /// <summary> - /// Create a new instance of the ExcelPackage class based on a stream - /// </summary> - /// <param name="newStream">The stream object can be empty or contain a package. The stream must be Read/Write</param> - public ExcelPackage(Stream newStream) - { - Package = new(newStream); - Workbook = CreateWorkbook(); - } + /// <summary> + /// Main Xml schema name + /// </summary> + internal const string _schemaMain = "http://schemas.openxmlformats.org/spreadsheetml/2006/main"; - private ExcelWorkbook CreateWorkbook() - { - ExcelWorkbook workbook = new(this, CreateDefaultNSM()); - workbook.GetExternalReferences(); - workbook.GetDefinedNames(); - return workbook; - } - - #endregion - - /// <summary> - /// Returns a reference to the package - /// </summary> - internal Packaging.ZipPackage Package { get; } - - /// <summary> - /// Returns a reference to the workbook component within the package. - /// All worksheets and cells can be accessed through the workbook. - /// </summary> - public ExcelWorkbook Workbook { get; } + /// <summary> + /// Relationship schema name + /// </summary> + internal const string _schemaRelationships = + "http://schemas.openxmlformats.org/officeDocument/2006/relationships"; - private XmlNamespaceManager CreateDefaultNSM() - { - // Create a NamespaceManager to handle the default namespace, - // and create a prefix for the default namespace: - NameTable nt = new NameTable(); - var ns = new XmlNamespaceManager(nt); - ns.AddNamespace(string.Empty, ExcelPackage.schemaMain); - ns.AddNamespace("d", ExcelPackage.schemaMain); - ns.AddNamespace("r", ExcelPackage.schemaRelationships); - ns.AddNamespace("c", ExcelPackage.schemaChart); - ns.AddNamespace("vt", schemaVt); - // extended properties (app.xml) - ns.AddNamespace("xp", schemaExtended); - // custom properties - ns.AddNamespace("ctp", schemaCustom); - // core properties - ns.AddNamespace("cp", schemaCore); - // core property namespaces - ns.AddNamespace("dc", schemaDc); - ns.AddNamespace("dcterms", schemaDcTerms); - ns.AddNamespace("dcmitype", schemaDcmiType); - ns.AddNamespace("xsi", schemaXsi); - return ns; - } - - #region SavePart - /// <summary> - /// Saves the XmlDocument into the package at the specified Uri. - /// </summary> - /// <param name="uri">The Uri of the component</param> - /// <param name="xmlDoc">The XmlDocument to save</param> - internal void SavePart(Uri uri, XmlDocument xmlDoc) - { - Packaging.ZipPackagePart part = Package.GetPart(uri); - xmlDoc.Save(part.GetStream(FileMode.Create, FileAccess.Write)); - } + internal const string _schemaDrawings = "http://schemas.openxmlformats.org/drawingml/2006/main"; - #endregion + internal const string _schemaMicrosoftVml = "urn:schemas-microsoft-com:vml"; + internal const string _schemaMicrosoftOffice = "urn:schemas-microsoft-com:office:office"; + internal const string _schemaMicrosoftExcel = "urn:schemas-microsoft-com:office:excel"; - /// <summary> - /// Compression option for the package - /// </summary> - public CompressionLevel Compression - { - get - { - return Package.Compression; - } - set - { - Package.Compression = value; - } - } - #region GetXmlFromUri - /// <summary> - /// Get the XmlDocument from an URI - /// </summary> - /// <param name="uri">The Uri to the part</param> - /// <returns>The XmlDocument</returns> - internal XmlDocument GetXmlFromUri(Uri uri) - { - XmlDocument xml = new XmlDocument(); - Packaging.ZipPackagePart part = Package.GetPart(uri); - XmlHelper.LoadXmlSafe(xml, part.GetStream()); - return (xml); - } - #endregion + internal const string _schemaChart = "http://schemas.openxmlformats.org/drawingml/2006/chart"; + internal const string _schemaHyperlink = + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"; + internal const string _schemaComment = + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"; - /// <summary> - /// Saves and returns the Excel files as a bytearray. - /// Note that the package is closed upon save - /// </summary> - /// <example> - /// Example how to return a document from a Webserver... - /// <code> - /// ExcelPackage package=new ExcelPackage(); - /// /**** ... Create the document ****/ - /// Byte[] bin = package.GetAsByteArray(); - /// Response.ContentType = "Application/vnd.ms-Excel"; - /// Response.AddHeader("content-disposition", "attachment; filename=TheFile.xlsx"); - /// Response.BinaryWrite(bin); - /// </code> - /// </example> - /// <returns></returns> - public byte[] GetAsByteArray() - { - var result = new MemoryStream(); - Workbook.Save(); - Package.Save(result); - return result.ToArray(); - } - } -} \ No newline at end of file + //Office properties + internal const string _schemaCore = + "http://schemas.openxmlformats.org/package/2006/metadata/core-properties"; + internal const string _schemaExtended = + "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties"; + internal const string _schemaCustom = + "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties"; + internal const string _schemaDc = "http://purl.org/dc/elements/1.1/"; + internal const string _schemaDcTerms = "http://purl.org/dc/terms/"; + internal const string _schemaDcmiType = "http://purl.org/dc/dcmitype/"; + internal const string _schemaXsi = "http://www.w3.org/2001/XMLSchema-instance"; + internal const string _schemaVt = + "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"; + + //Pivottables + internal const string _schemaPivotTable = + "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml"; + internal const string _schemaPivotCacheDefinition = + "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml"; + internal const string _schemaPivotCacheRecords = + "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml"; + + internal const string _contentTypeWorkbookDefault = + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"; + internal const string _contentTypeWorkbookMacroEnabled = + "application/vnd.ms-excel.sheet.macroEnabled.main+xml"; + internal const string _contentTypeSharedString = + "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"; + + /// <summary> + /// Maximum number of columns in a worksheet (16384). + /// </summary> + public const int MaxColumns = 16384; + + /// <summary> + /// Maximum number of rows in a worksheet (1048576). + /// </summary> + public const int MaxRows = 1048576; + + /// <summary> + /// Create a new instance of the ExcelPackage. Output is accessed through the Stream property. + /// </summary> + public ExcelPackage() { + Package = new(); + Workbook = CreateWorkbook(); + _ = Workbook.WorkbookXml; + // create the relationship to the main part + Package.CreateRelationship( + UriHelper.GetRelativeUri(new("/xl", UriKind.Relative), Workbook.WorkbookUri), + TargetMode.Internal, + _schemaRelationships + "/officeDocument"); + } + + /// <summary> + /// Create a new instance of the ExcelPackage class based on a existing file or creates a new file. + /// </summary> + /// <param name="newFile">If newFile exists, it is opened. Otherwise it is created from scratch.</param> + public ExcelPackage(FileInfo newFile) { + using var inputStream = newFile.OpenRead(); + Package = new(inputStream); + Workbook = CreateWorkbook(); + } + + /// <summary> + /// Create a new instance of the ExcelPackage class based on a stream + /// </summary> + /// <param name="newStream">The stream object can be empty or contain a package. The stream must be Read/Write</param> + public ExcelPackage(Stream newStream) { + Package = new(newStream); + Workbook = CreateWorkbook(); + } + + private ExcelWorkbook CreateWorkbook() { + ExcelWorkbook workbook = new(this, CreateDefaultNsm()); + workbook.GetExternalReferences(); + workbook.GetDefinedNames(); + return workbook; + } + + /// <summary> + /// Returns a reference to the package + /// </summary> + internal ZipPackage Package { get; } + + /// <summary> + /// Returns a reference to the workbook component within the package. + /// All worksheets and cells can be accessed through the workbook. + /// </summary> + public ExcelWorkbook Workbook { get; } + + private XmlNamespaceManager CreateDefaultNsm() { + // Create a NamespaceManager to handle the default namespace, + // and create a prefix for the default namespace: + NameTable nt = new NameTable(); + var ns = new XmlNamespaceManager(nt); + ns.AddNamespace(string.Empty, _schemaMain); + ns.AddNamespace("d", _schemaMain); + ns.AddNamespace("r", _schemaRelationships); + ns.AddNamespace("c", _schemaChart); + ns.AddNamespace("vt", _schemaVt); + // extended properties (app.xml) + ns.AddNamespace("xp", _schemaExtended); + // custom properties + ns.AddNamespace("ctp", _schemaCustom); + // core properties + ns.AddNamespace("cp", _schemaCore); + // core property namespaces + ns.AddNamespace("dc", _schemaDc); + ns.AddNamespace("dcterms", _schemaDcTerms); + ns.AddNamespace("dcmitype", _schemaDcmiType); + ns.AddNamespace("xsi", _schemaXsi); + return ns; + } + + /// <summary> + /// Saves the XmlDocument into the package at the specified Uri. + /// </summary> + /// <param name="uri">The Uri of the component</param> + /// <param name="xmlDoc">The XmlDocument to save</param> + internal void SavePart(Uri uri, XmlDocument xmlDoc) { + ZipPackagePart part = Package.GetPart(uri); + xmlDoc.Save(part.GetStream(FileMode.Create, FileAccess.Write)); + } + + /// <summary> + /// Compression option for the package + /// </summary> + public CompressionLevel Compression { + get => Package.Compression; + set => Package.Compression = value; + } + + /// <summary> + /// Get the XmlDocument from an URI + /// </summary> + /// <param name="uri">The Uri to the part</param> + /// <returns>The XmlDocument</returns> + internal XmlDocument GetXmlFromUri(Uri uri) { + XmlDocument xml = new XmlDocument(); + ZipPackagePart part = Package.GetPart(uri); + XmlHelper.LoadXmlSafe(xml, part.GetStream()); + return (xml); + } + + /// <summary> + /// Saves and returns the Excel files as a bytearray. + /// Note that the package is closed upon save + /// </summary> + /// <example> + /// Example how to return a document from a Webserver... + /// <code> + /// ExcelPackage package=new ExcelPackage(); + /// /**** ... Create the document ****/ + /// Byte[] bin = package.GetAsByteArray(); + /// Response.ContentType = "Application/vnd.ms-Excel"; + /// Response.AddHeader("content-disposition", "attachment; filename=TheFile.xlsx"); + /// Response.BinaryWrite(bin); + /// </code> + /// </example> + /// <returns></returns> + public byte[] GetAsByteArray() { + var result = new MemoryStream(); + Workbook.Save(); + Package.Save(result); + return result.ToArray(); + } +}
diff --git a/EPPlus/ExcelPrinterSettings.cs b/EPPlus/ExcelPrinterSettings.cs index f362650..17ed052 100644 --- a/EPPlus/ExcelPrinterSettings.cs +++ b/EPPlus/ExcelPrinterSettings.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,831 +13,761 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; using System.Globalization; +using System.Xml; -namespace OfficeOpenXml -{ - #region "Enums" - /// <summary> - /// Printer orientation - /// </summary> - public enum eOrientation - { - /// <summary> - /// Portrait orientation - /// </summary> - Portrait, - /// <summary> - /// Landscape orientation - /// </summary> - Landscape +namespace OfficeOpenXml; + +/// <summary> +/// Printer orientation +/// </summary> +public enum eOrientation { + /// <summary> + /// Portrait orientation + /// </summary> + Portrait, + + /// <summary> + /// Landscape orientation + /// </summary> + Landscape, +} + +/// <summary> +/// Papersize +/// </summary> +public enum ePaperSize { + /// <summary> + /// Letter paper (8.5 in. by 11 in.) + /// </summary> + Letter = 1, + + /// <summary> + /// Letter small paper (8.5 in. by 11 in.) + /// </summary> + LetterSmall = 2, + + /// <summary> + /// // Tabloid paper (11 in. by 17 in.) + /// </summary> + Tabloid = 3, + + /// <summary> + /// Ledger paper (17 in. by 11 in.) + /// </summary> + Ledger = 4, + + /// <summary> + /// Legal paper (8.5 in. by 14 in.) + /// </summary> + Legal = 5, + + /// <summary> + /// Statement paper (5.5 in. by 8.5 in.) + /// </summary> + Statement = 6, + + /// <summary> + /// Executive paper (7.25 in. by 10.5 in.) + /// </summary> + Executive = 7, + + /// <summary> + /// A3 paper (297 mm by 420 mm) + /// </summary> + A3 = 8, + + /// <summary> + /// A4 paper (210 mm by 297 mm) + /// </summary> + A4 = 9, + + /// <summary> + /// A4 small paper (210 mm by 297 mm) + /// </summary> + A4Small = 10, + + /// <summary> + /// A5 paper (148 mm by 210 mm) + /// </summary> + A5 = 11, + + /// <summary> + /// B4 paper (250 mm by 353 mm) + /// </summary> + B4 = 12, + + /// <summary> + /// B5 paper (176 mm by 250 mm) + /// </summary> + B5 = 13, + + /// <summary> + /// Folio paper (8.5 in. by 13 in.) + /// </summary> + Folio = 14, + + /// <summary> + /// Quarto paper (215 mm by 275 mm) + /// </summary> + Quarto = 15, + + /// <summary> + /// Standard paper (10 in. by 14 in.) + /// </summary> + Standard1014 = 16, + + /// <summary> + /// Standard paper (11 in. by 17 in.) + /// </summary> + Standard1117 = 17, + + /// <summary> + /// Note paper (8.5 in. by 11 in.) + /// </summary> + Note = 18, + + /// <summary> + /// #9 envelope (3.875 in. by 8.875 in.) + /// </summary> + Envelope9 = 19, + + /// <summary> + /// #10 envelope (4.125 in. by 9.5 in.) + /// </summary> + Envelope10 = 20, + + /// <summary> + /// #11 envelope (4.5 in. by 10.375 in.) + /// </summary> + Envelope11 = 21, + + /// <summary> + /// #12 envelope (4.75 in. by 11 in.) + /// </summary> + Envelope12 = 22, + + /// <summary> + /// #14 envelope (5 in. by 11.5 in.) + /// </summary> + Envelope14 = 23, + + /// <summary> + /// C paper (17 in. by 22 in.) + /// </summary> + C = 24, + + /// <summary> + /// D paper (22 in. by 34 in.) + /// </summary> + D = 25, + + /// <summary> + /// E paper (34 in. by 44 in.) + /// </summary> + E = 26, + + /// <summary> + /// DL envelope (110 mm by 220 mm) + /// </summary> + DlEnvelope = 27, + + /// <summary> + /// C5 envelope (162 mm by 229 mm) + /// </summary> + C5Envelope = 28, + + /// <summary> + /// C3 envelope (324 mm by 458 mm) + /// </summary> + C3Envelope = 29, + + /// <summary> + /// C4 envelope (229 mm by 324 mm) + /// </summary> + C4Envelope = 30, + + /// <summary> + /// C6 envelope (114 mm by 162 mm) + /// </summary> + C6Envelope = 31, + + /// <summary> + /// C65 envelope (114 mm by 229 mm) + /// </summary> + C65Envelope = 32, + + /// <summary> + /// B4 envelope (250 mm by 353 mm) + /// </summary> + B4Envelope = 33, + + /// <summary> + /// B5 envelope (176 mm by 250 mm) + /// </summary> + B5Envelope = 34, + + /// <summary> + /// B6 envelope (176 mm by 125 mm) + /// </summary> + B6Envelope = 35, + + /// <summary> + /// Italy envelope (110 mm by 230 mm) + /// </summary> + ItalyEnvelope = 36, + + /// <summary> + /// Monarch envelope (3.875 in. by 7.5 in.). + /// </summary> + MonarchEnvelope = 37, + + /// <summary> + /// 6 3/4 envelope (3.625 in. by 6.5 in.) + /// </summary> + Six34Envelope = 38, + + /// <summary> + /// US standard fanfold (14.875 in. by 11 in.) + /// </summary> + UsStandard = 39, + + /// <summary> + /// German standard fanfold (8.5 in. by 12 in.) + /// </summary> + GermanStandard = 40, + + /// <summary> + /// German legal fanfold (8.5 in. by 13 in.) + /// </summary> + GermanLegal = 41, + + /// <summary> + /// ISO B4 (250 mm by 353 mm) + /// </summary> + Isob4 = 42, + + /// <summary> + /// Japanese double postcard (200 mm by 148 mm) + /// </summary> + JapaneseDoublePostcard = 43, + + /// <summary> + /// Standard paper (9 in. by 11 in.) + /// </summary> + Standard9 = 44, + + /// <summary> + /// Standard paper (10 in. by 11 in.) + /// </summary> + Standard10 = 45, + + /// <summary> + /// Standard paper (15 in. by 11 in.) + /// </summary> + Standard15 = 46, + + /// <summary> + /// Invite envelope (220 mm by 220 mm) + /// </summary> + InviteEnvelope = 47, + + /// <summary> + /// Letter extra paper (9.275 in. by 12 in.) + /// </summary> + LetterExtra = 50, + + /// <summary> + /// Legal extra paper (9.275 in. by 15 in.) + /// </summary> + LegalExtra = 51, + + /// <summary> + /// Tabloid extra paper (11.69 in. by 18 in.) + /// </summary> + TabloidExtra = 52, + + /// <summary> + /// A4 extra paper (236 mm by 322 mm) + /// </summary> + A4Extra = 53, + + /// <summary> + /// Letter transverse paper (8.275 in. by 11 in.) + /// </summary> + LetterTransverse = 54, + + /// <summary> + /// A4 transverse paper (210 mm by 297 mm) + /// </summary> + A4Transverse = 55, + + /// <summary> + /// Letter extra transverse paper (9.275 in. by 12 in.) + /// </summary> + LetterExtraTransverse = 56, + + /// <summary> + /// SuperA/SuperA/A4 paper (227 mm by 356 mm) + /// </summary> + SuperA = 57, + + /// <summary> + /// SuperB/SuperB/A3 paper (305 mm by 487 mm) + /// </summary> + SuperB = 58, + + /// <summary> + /// Letter plus paper (8.5 in. by 12.69 in.) + /// </summary> + LetterPlus = 59, + + /// <summary> + /// A4 plus paper (210 mm by 330 mm) + /// </summary> + A4Plus = 60, + + /// <summary> + /// A5 transverse paper (148 mm by 210 mm) + /// </summary> + A5Transverse = 61, + + /// <summary> + /// JIS B5 transverse paper (182 mm by 257 mm) + /// </summary> + Jisb5Transverse = 62, + + /// <summary> + /// A3 extra paper (322 mm by 445 mm) + /// </summary> + A3Extra = 63, + + /// <summary> + /// A5 extra paper (174 mm by 235 mm) + /// </summary> + A5Extra = 64, + + /// <summary> + /// ISO B5 extra paper (201 mm by 276 mm) + /// </summary> + Isob5 = 65, + + /// <summary> + /// A2 paper (420 mm by 594 mm) + /// </summary> + A2 = 66, + + /// <summary> + /// A3 transverse paper (297 mm by 420 mm) + /// </summary> + A3Transverse = 67, + + /// <summary> + /// A3 extra transverse paper (322 mm by 445 mm*/ + /// </summary> + A3ExtraTransverse = 68, +} + +/// <summary> +/// Specifies printed page order +/// </summary> +public enum ePageOrder { + /// <summary> + /// Order pages vertically first, then move horizontally. + /// </summary> + DownThenOver, + + /// <summary> + /// Order pages horizontally first, then move vertically + /// </summary> + OverThenDown, +} + +/// <summary> +/// Printer settings +/// </summary> +public sealed class ExcelPrinterSettings : XmlHelper { + private ExcelWorksheet _ws; + private bool _marginsCreated; + + internal ExcelPrinterSettings(XmlNamespaceManager ns, XmlNode topNode, ExcelWorksheet ws) + : base(ns, topNode) { + _ws = ws; + SchemaNodeOrder = ws.SchemaNodeOrder; + } + + private const string _leftMarginPath = "d:pageMargins/@left"; + + /// <summary> + /// Left margin in inches + /// </summary> + public decimal LeftMargin { + get => GetXmlNodeDecimal(_leftMarginPath); + set { + CreateMargins(); + SetXmlNodeString(_leftMarginPath, value.ToString(CultureInfo.InvariantCulture)); } - /// <summary> - /// Papersize - /// </summary> - public enum ePaperSize - { - /// <summary> - /// Letter paper (8.5 in. by 11 in.) - /// </summary> - Letter= 1, - /// <summary> - /// Letter small paper (8.5 in. by 11 in.) - /// </summary> - LetterSmall=2, - /// <summary> - /// // Tabloid paper (11 in. by 17 in.) - /// </summary> - Tabloid=3, - /// <summary> - /// Ledger paper (17 in. by 11 in.) - /// </summary> - Ledger=4, - /// <summary> - /// Legal paper (8.5 in. by 14 in.) - /// </summary> - Legal=5, - /// <summary> - /// Statement paper (5.5 in. by 8.5 in.) - /// </summary> - Statement=6, - /// <summary> - /// Executive paper (7.25 in. by 10.5 in.) - /// </summary> - Executive=7, - /// <summary> - /// A3 paper (297 mm by 420 mm) - /// </summary> - A3=8, - /// <summary> - /// A4 paper (210 mm by 297 mm) - /// </summary> - A4=9, - /// <summary> - /// A4 small paper (210 mm by 297 mm) - /// </summary> - A4Small=10, - /// <summary> - /// A5 paper (148 mm by 210 mm) - /// </summary> - A5=11, - /// <summary> - /// B4 paper (250 mm by 353 mm) - /// </summary> - B4=12, - /// <summary> - /// B5 paper (176 mm by 250 mm) - /// </summary> - B5=13, - /// <summary> - /// Folio paper (8.5 in. by 13 in.) - /// </summary> - Folio=14, - /// <summary> - /// Quarto paper (215 mm by 275 mm) - /// </summary> - Quarto=15, - /// <summary> - /// Standard paper (10 in. by 14 in.) - /// </summary> - Standard10_14=16, - /// <summary> - /// Standard paper (11 in. by 17 in.) - /// </summary> - Standard11_17=17, - /// <summary> - /// Note paper (8.5 in. by 11 in.) - /// </summary> - Note=18, - /// <summary> - /// #9 envelope (3.875 in. by 8.875 in.) - /// </summary> - Envelope9=19, - /// <summary> - /// #10 envelope (4.125 in. by 9.5 in.) - /// </summary> - Envelope10=20, - /// <summary> - /// #11 envelope (4.5 in. by 10.375 in.) - /// </summary> - Envelope11=21, - /// <summary> - /// #12 envelope (4.75 in. by 11 in.) - /// </summary> - Envelope12=22, - /// <summary> - /// #14 envelope (5 in. by 11.5 in.) - /// </summary> - Envelope14=23, - /// <summary> - /// C paper (17 in. by 22 in.) - /// </summary> - C=24, - /// <summary> - /// D paper (22 in. by 34 in.) - /// </summary> - D=25, - /// <summary> - /// E paper (34 in. by 44 in.) - /// </summary> - E=26, - /// <summary> - /// DL envelope (110 mm by 220 mm) - /// </summary> - DLEnvelope = 27, - /// <summary> - /// C5 envelope (162 mm by 229 mm) - /// </summary> - C5Envelope = 28, - /// <summary> - /// C3 envelope (324 mm by 458 mm) - /// </summary> - C3Envelope = 29, - /// <summary> - /// C4 envelope (229 mm by 324 mm) - /// </summary> - C4Envelope = 30, - /// <summary> - /// C6 envelope (114 mm by 162 mm) - /// </summary> - C6Envelope = 31, - /// <summary> - /// C65 envelope (114 mm by 229 mm) - /// </summary> - C65Envelope = 32, - /// <summary> - /// B4 envelope (250 mm by 353 mm) - /// </summary> - B4Envelope= 33, - /// <summary> - /// B5 envelope (176 mm by 250 mm) - /// </summary> - B5Envelope= 34, - /// <summary> - /// B6 envelope (176 mm by 125 mm) - /// </summary> - B6Envelope = 35, - /// <summary> - /// Italy envelope (110 mm by 230 mm) - /// </summary> - ItalyEnvelope = 36, - /// <summary> - /// Monarch envelope (3.875 in. by 7.5 in.). - /// </summary> - MonarchEnvelope = 37, - /// <summary> - /// 6 3/4 envelope (3.625 in. by 6.5 in.) - /// </summary> - Six3_4Envelope = 38, - /// <summary> - /// US standard fanfold (14.875 in. by 11 in.) - /// </summary> - USStandard=39, - /// <summary> - /// German standard fanfold (8.5 in. by 12 in.) - /// </summary> - GermanStandard=40, - /// <summary> - /// German legal fanfold (8.5 in. by 13 in.) - /// </summary> - GermanLegal=41, - /// <summary> - /// ISO B4 (250 mm by 353 mm) - /// </summary> - ISOB4=42, - /// <summary> - /// Japanese double postcard (200 mm by 148 mm) - /// </summary> - JapaneseDoublePostcard=43, - /// <summary> - /// Standard paper (9 in. by 11 in.) - /// </summary> - Standard9=44, - /// <summary> - /// Standard paper (10 in. by 11 in.) - /// </summary> - Standard10=45, - /// <summary> - /// Standard paper (15 in. by 11 in.) - /// </summary> - Standard15=46, - /// <summary> - /// Invite envelope (220 mm by 220 mm) - /// </summary> - InviteEnvelope = 47, - /// <summary> - /// Letter extra paper (9.275 in. by 12 in.) - /// </summary> - LetterExtra=50, - /// <summary> - /// Legal extra paper (9.275 in. by 15 in.) - /// </summary> - LegalExtra=51, - /// <summary> - /// Tabloid extra paper (11.69 in. by 18 in.) - /// </summary> - TabloidExtra=52, - /// <summary> - /// A4 extra paper (236 mm by 322 mm) - /// </summary> - A4Extra=53, - /// <summary> - /// Letter transverse paper (8.275 in. by 11 in.) - /// </summary> - LetterTransverse=54, - /// <summary> - /// A4 transverse paper (210 mm by 297 mm) - /// </summary> - A4Transverse=55, - /// <summary> - /// Letter extra transverse paper (9.275 in. by 12 in.) - /// </summary> - LetterExtraTransverse=56, - /// <summary> - /// SuperA/SuperA/A4 paper (227 mm by 356 mm) - /// </summary> - SuperA=57, - /// <summary> - /// SuperB/SuperB/A3 paper (305 mm by 487 mm) - /// </summary> - SuperB=58, - /// <summary> - /// Letter plus paper (8.5 in. by 12.69 in.) - /// </summary> - LetterPlus=59, - /// <summary> - /// A4 plus paper (210 mm by 330 mm) - /// </summary> - A4Plus=60, - /// <summary> - /// A5 transverse paper (148 mm by 210 mm) - /// </summary> - A5Transverse=61, - /// <summary> - /// JIS B5 transverse paper (182 mm by 257 mm) - /// </summary> - JISB5Transverse=62, - /// <summary> - /// A3 extra paper (322 mm by 445 mm) - /// </summary> - A3Extra=63, - /// <summary> - /// A5 extra paper (174 mm by 235 mm) - /// </summary> - A5Extra=64, - /// <summary> - /// ISO B5 extra paper (201 mm by 276 mm) - /// </summary> - ISOB5=65, - /// <summary> - /// A2 paper (420 mm by 594 mm) - /// </summary> - A2=66, - /// <summary> - /// A3 transverse paper (297 mm by 420 mm) - /// </summary> - A3Transverse=67, - /// <summary> - /// A3 extra transverse paper (322 mm by 445 mm*/ - /// </summary> - A3ExtraTransverse = 68 + } + + private const string _rightMarginPath = "d:pageMargins/@right"; + + /// <summary> + /// Right margin in inches + /// </summary> + public decimal RightMargin { + get => GetXmlNodeDecimal(_rightMarginPath); + set { + CreateMargins(); + SetXmlNodeString(_rightMarginPath, value.ToString(CultureInfo.InvariantCulture)); } - /// <summary> - /// Specifies printed page order - /// </summary> - public enum ePageOrder - { + } - /// <summary> - /// Order pages vertically first, then move horizontally. - /// </summary> - DownThenOver, - /// <summary> - /// Order pages horizontally first, then move vertically - /// </summary> - OverThenDown + private const string _topMarginPath = "d:pageMargins/@top"; + + /// <summary> + /// Top margin in inches + /// </summary> + public decimal TopMargin { + get => GetXmlNodeDecimal(_topMarginPath); + set { + CreateMargins(); + SetXmlNodeString(_topMarginPath, value.ToString(CultureInfo.InvariantCulture)); } - #endregion - /// <summary> - /// Printer settings - /// </summary> - public sealed class ExcelPrinterSettings : XmlHelper - { - ExcelWorksheet _ws; - bool _marginsCreated = false; + } - internal ExcelPrinterSettings(XmlNamespaceManager ns, XmlNode topNode,ExcelWorksheet ws) : - base(ns, topNode) - { - _ws = ws; - SchemaNodeOrder = ws.SchemaNodeOrder; - } - const string _leftMarginPath = "d:pageMargins/@left"; - /// <summary> - /// Left margin in inches - /// </summary> - public decimal LeftMargin - { - get - { - return GetXmlNodeDecimal(_leftMarginPath); - } - set - { - CreateMargins(); - SetXmlNodeString(_leftMarginPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - const string _rightMarginPath = "d:pageMargins/@right"; - /// <summary> - /// Right margin in inches - /// </summary> - public decimal RightMargin - { - get - { - return GetXmlNodeDecimal(_rightMarginPath); - } - set - { - CreateMargins(); - SetXmlNodeString(_rightMarginPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - const string _topMarginPath = "d:pageMargins/@top"; - /// <summary> - /// Top margin in inches - /// </summary> - public decimal TopMargin - { - get - { - return GetXmlNodeDecimal(_topMarginPath); - } - set - { - CreateMargins(); - SetXmlNodeString(_topMarginPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - const string _bottomMarginPath = "d:pageMargins/@bottom"; - /// <summary> - /// Bottom margin in inches - /// </summary> - public decimal BottomMargin - { - get - { - return GetXmlNodeDecimal(_bottomMarginPath); - } - set - { - CreateMargins(); - SetXmlNodeString(_bottomMarginPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - const string _headerMarginPath = "d:pageMargins/@header"; - /// <summary> - /// Header margin in inches - /// </summary> - public decimal HeaderMargin - { - get - { - return GetXmlNodeDecimal(_headerMarginPath); - } - set - { - CreateMargins(); - SetXmlNodeString(_headerMarginPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - const string _footerMarginPath = "d:pageMargins/@footer"; - /// <summary> - /// Footer margin in inches - /// </summary> - public decimal FooterMargin - { - get - { - return GetXmlNodeDecimal(_footerMarginPath); - } - set - { - CreateMargins(); - SetXmlNodeString(_footerMarginPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - const string _orientationPath = "d:pageSetup/@orientation"; - /// <summary> - /// Orientation - /// Portrait or Landscape - /// </summary> - public eOrientation Orientation - { - get - { - return (eOrientation)Enum.Parse(typeof(eOrientation), GetXmlNodeString(_orientationPath), true); - } - set - { - SetXmlNodeString(_orientationPath, value.ToString().ToLower(CultureInfo.InvariantCulture)); - } - } - const string _fitToWidthPath = "d:pageSetup/@fitToWidth"; - /// <summary> - /// Fit to Width in pages. - /// Set FitToPage to true when using this one. - /// 0 is automatic - /// </summary> - public int FitToWidth - { - get - { - return GetXmlNodeInt(_fitToWidthPath); - } - set - { - SetXmlNodeString(_fitToWidthPath, value.ToString()); - } - } - const string _fitToHeightPath = "d:pageSetup/@fitToHeight"; - /// <summary> - /// Fit to height in pages. - /// Set FitToPage to true when using this one. - /// 0 is automatic - /// </summary> - public int FitToHeight - { - get - { - return GetXmlNodeInt(_fitToHeightPath); - } - set - { - SetXmlNodeString(_fitToHeightPath, value.ToString()); - } - } - const string _scalePath = "d:pageSetup/@scale"; - /// <summary> - /// Print scale - /// </summary> - public int Scale - { - get - { - return GetXmlNodeInt(_scalePath); - } - set - { - SetXmlNodeString(_scalePath, value.ToString()); - } - } - const string _fitToPagePath = "d:sheetPr/d:pageSetUpPr/@fitToPage"; - /// <summary> - /// Fit To Page. - /// </summary> - public bool FitToPage - { - get - { - return GetXmlNodeBool(_fitToPagePath); - } - set - { - SetXmlNodeString(_fitToPagePath, value ? "1" : "0"); - } - } - const string _headersPath = "d:printOptions/@headings"; - /// <summary> - /// Print headings (column letter and row numbers) - /// </summary> - public bool ShowHeaders - { - get - { - return GetXmlNodeBool(_headersPath, false); - } - set - { - SetXmlNodeBool(_headersPath, value, false); - } - } - /// <summary> - /// Print titles - /// Rows to be repeated after each pagebreak. - /// The address must be a full row address (ex. 1:1) - /// </summary> - public ExcelAddress RepeatRows - { - get - { - if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) - { - ExcelRangeBase r = _ws.Names["_xlnm.Print_Titles"] as ExcelRangeBase; - if (r.Start.Column == 1 && r.End.Column == ExcelPackage.MaxColumns) - { - return new ExcelAddress(r.FirstAddress); - } - else if (r._addresses != null && r.Addresses[0].Start.Column == 1 && r.Addresses[0].End.Column == ExcelPackage.MaxColumns) - { - return r._addresses[0]; - } - else - { - return null; - } - } - else - { - return null; - } - } - set - { + private const string _bottomMarginPath = "d:pageMargins/@bottom"; - //Must span entire columns - if (!(value.Start.Column == 1 && value.End.Column == ExcelPackage.MaxColumns)) - { - throw new InvalidOperationException("Address must span full columns only (for ex. Address=\"A:A\" for the first column)."); - } - - var vertAddr = RepeatColumns; - string addr; - if (vertAddr == null) - { - addr = value.Address; - } - else - { - addr = vertAddr.Address + "," + value.Address; - } - - if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) - { - _ws.Names["_xlnm.Print_Titles"].Address = addr; - } - else - { - _ws.Names.Add("_xlnm.Print_Titles", new ExcelRangeBase(_ws, addr)); - } - } - } - /// <summary> - /// Print titles - /// Columns to be repeated after each pagebreak. - /// The address must be a full column address (ex. A:A) - /// </summary> - public ExcelAddress RepeatColumns - { - get - { - if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) - { - ExcelRangeBase r = _ws.Names["_xlnm.Print_Titles"] as ExcelRangeBase; - if (r.Start.Row == 1 && r.End.Row == ExcelPackage.MaxRows) - { - return new ExcelAddress(r.FirstAddress); - } - else if (r._addresses != null && (r._addresses[0].Start.Row == 1 && r._addresses[0].End.Row == ExcelPackage.MaxRows)) - { - return r._addresses[0]; - } - else - { - return null; - } - } - else - { - return null; - } - } - set - { - //Must span entire rows - if (!(value.Start.Row == 1 && value.End.Row== ExcelPackage.MaxRows)) - { - throw new InvalidOperationException("Address must span rows only (for ex. Address=\"1:1\" for the first row)."); - } - - var horAddr = RepeatRows; - string addr; - if (horAddr == null) - { - addr = value.Address; - } - else - { - addr = value.Address + "," + horAddr.Address; - } - - if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) - { - _ws.Names["_xlnm.Print_Titles"].Address = addr; - } - else - { - _ws.Names.Add("_xlnm.Print_Titles", new ExcelRangeBase(_ws, addr)); - } - } - } - /// <summary> - /// The printarea. - /// Null if no print area is set. - /// </summary> - public ExcelRangeBase PrintArea - { - get - { - if (_ws.Names.ContainsKey("_xlnm.Print_Area")) - { - return _ws.Names["_xlnm.Print_Area"]; - } - else - { - return null; - } - } - set - { - if (value == null) - { - _ws.Names.Remove("_xlnm.Print_Area"); - } - else if (_ws.Names.ContainsKey("_xlnm.Print_Area")) - { - _ws.Names["_xlnm.Print_Area"].Address = value.Address; - } - else - { - _ws.Names.Add("_xlnm.Print_Area", value); - } - } - } - const string _gridLinesPath = "d:printOptions/@gridLines"; - /// <summary> - /// Print gridlines - /// </summary> - public bool ShowGridLines - { - get - { - return GetXmlNodeBool(_gridLinesPath, false); - } - set - { - SetXmlNodeBool(_gridLinesPath, value, false); - } - } - const string _horizontalCenteredPath = "d:printOptions/@horizontalCentered"; - /// <summary> - /// Horizontal centered when printing - /// </summary>w - public bool HorizontalCentered - { - get - { - return GetXmlNodeBool(_horizontalCenteredPath, false); - } - set - { - SetXmlNodeBool(_horizontalCenteredPath, value, false); - } - } - const string _verticalCenteredPath = "d:printOptions/@verticalCentered"; - /// <summary> - /// Vertical centered when printing - /// </summary> - public bool VerticalCentered - { - get - { - return GetXmlNodeBool(_verticalCenteredPath, false); - } - set - { - SetXmlNodeBool(_verticalCenteredPath, value, false); - } - } - const string _pageOrderPath = "d:pageSetup/@pageOrder"; - /// <summary> - /// Specifies printed page order - /// </summary> - public ePageOrder PageOrder - { - get - { - if (GetXmlNodeString(_pageOrderPath) == "overThenDown") - { - return ePageOrder.OverThenDown; - } - else - { - return ePageOrder.DownThenOver; - } - } - set - { - if (value == ePageOrder.OverThenDown) - { - SetXmlNodeString(_pageOrderPath, "overThenDown"); - } - else - { - DeleteNode(_pageOrderPath); - } - } - } - const string _blackAndWhitePath = "d:pageSetup/@blackAndWhite"; - /// <summary> - /// Print black and white - /// </summary> - public bool BlackAndWhite - { - get - { - return GetXmlNodeBool(_blackAndWhitePath, false); - } - set - { - SetXmlNodeBool(_blackAndWhitePath, value, false); - } - } - const string _draftPath = "d:pageSetup/@draft"; - /// <summary> - /// Print a draft - /// </summary> - public bool Draft - { - get - { - return GetXmlNodeBool(_draftPath, false); - } - set - { - SetXmlNodeBool(_draftPath, value, false); - } - } - const string _paperSizePath = "d:pageSetup/@paperSize"; - /// <summary> - /// Paper size - /// </summary> - public ePaperSize PaperSize - { - get - { - string s = GetXmlNodeString(_paperSizePath); - if (s != "") - { - return (ePaperSize)int.Parse(s); - } - else - { - return ePaperSize.Letter; - - } - } - set - { - SetXmlNodeString(_paperSizePath, ((int)value).ToString()); - } - } - /// <summary> - /// All or none of the margin attributes must exist. Create all att ones. - /// </summary> - private void CreateMargins() - { - if (_marginsCreated==false && TopNode.SelectSingleNode(_leftMarginPath, NameSpaceManager) == null) - { - _marginsCreated=true; - LeftMargin = 0.7087M; - RightMargin = 0.7087M; - TopMargin = 0.7480M; - BottomMargin = 0.7480M; - HeaderMargin = 0.315M; - FooterMargin = 0.315M; - } - } + /// <summary> + /// Bottom margin in inches + /// </summary> + public decimal BottomMargin { + get => GetXmlNodeDecimal(_bottomMarginPath); + set { + CreateMargins(); + SetXmlNodeString(_bottomMarginPath, value.ToString(CultureInfo.InvariantCulture)); } + } + + private const string _headerMarginPath = "d:pageMargins/@header"; + + /// <summary> + /// Header margin in inches + /// </summary> + public decimal HeaderMargin { + get => GetXmlNodeDecimal(_headerMarginPath); + set { + CreateMargins(); + SetXmlNodeString(_headerMarginPath, value.ToString(CultureInfo.InvariantCulture)); + } + } + + private const string _footerMarginPath = "d:pageMargins/@footer"; + + /// <summary> + /// Footer margin in inches + /// </summary> + public decimal FooterMargin { + get => GetXmlNodeDecimal(_footerMarginPath); + set { + CreateMargins(); + SetXmlNodeString(_footerMarginPath, value.ToString(CultureInfo.InvariantCulture)); + } + } + + private const string _orientationPath = "d:pageSetup/@orientation"; + + /// <summary> + /// Orientation + /// Portrait or Landscape + /// </summary> + public eOrientation Orientation { + get => (eOrientation)Enum.Parse(typeof(eOrientation), GetXmlNodeString(_orientationPath), true); + set => + SetXmlNodeString(_orientationPath, value.ToString().ToLower(CultureInfo.InvariantCulture)); + } + + private const string _fitToWidthPath = "d:pageSetup/@fitToWidth"; + + /// <summary> + /// Fit to Width in pages. + /// Set FitToPage to true when using this one. + /// 0 is automatic + /// </summary> + public int FitToWidth { + get => GetXmlNodeInt(_fitToWidthPath); + set => SetXmlNodeString(_fitToWidthPath, value.ToString()); + } + + private const string _fitToHeightPath = "d:pageSetup/@fitToHeight"; + + /// <summary> + /// Fit to height in pages. + /// Set FitToPage to true when using this one. + /// 0 is automatic + /// </summary> + public int FitToHeight { + get => GetXmlNodeInt(_fitToHeightPath); + set => SetXmlNodeString(_fitToHeightPath, value.ToString()); + } + + private const string _scalePath = "d:pageSetup/@scale"; + + /// <summary> + /// Print scale + /// </summary> + public int Scale { + get => GetXmlNodeInt(_scalePath); + set => SetXmlNodeString(_scalePath, value.ToString()); + } + + private const string _fitToPagePath = "d:sheetPr/d:pageSetUpPr/@fitToPage"; + + /// <summary> + /// Fit To Page. + /// </summary> + public bool FitToPage { + get => GetXmlNodeBool(_fitToPagePath); + set => SetXmlNodeString(_fitToPagePath, value ? "1" : "0"); + } + + private const string _headersPath = "d:printOptions/@headings"; + + /// <summary> + /// Print headings (column letter and row numbers) + /// </summary> + public bool ShowHeaders { + get => GetXmlNodeBool(_headersPath, false); + set => SetXmlNodeBool(_headersPath, value, false); + } + + /// <summary> + /// Print titles + /// Rows to be repeated after each pagebreak. + /// The address must be a full row address (ex. 1:1) + /// </summary> + public ExcelAddress RepeatRows { + get { + if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) { + ExcelRangeBase r = _ws.Names["_xlnm.Print_Titles"]; + if (r.Start.Column == 1 && r.End.Column == ExcelPackage.MaxColumns) { + return new(r.FirstAddress); + } + if (r._addresses != null + && r.Addresses[0].Start.Column == 1 + && r.Addresses[0].End.Column == ExcelPackage.MaxColumns) { + return r._addresses[0]; + } + return null; + } + return null; + } + set { + //Must span entire columns + if (!(value.Start.Column == 1 && value.End.Column == ExcelPackage.MaxColumns)) { + throw new InvalidOperationException( + "Address must span full columns only (for ex. Address=\"A:A\" for the first column)."); + } + + var vertAddr = RepeatColumns; + string addr; + if (vertAddr == null) { + addr = value.Address; + } else { + addr = vertAddr.Address + "," + value.Address; + } + + if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) { + _ws.Names["_xlnm.Print_Titles"].Address = addr; + } else { + _ws.Names.Add("_xlnm.Print_Titles", new(_ws, addr)); + } + } + } + + /// <summary> + /// Print titles + /// Columns to be repeated after each pagebreak. + /// The address must be a full column address (ex. A:A) + /// </summary> + public ExcelAddress RepeatColumns { + get { + if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) { + ExcelRangeBase r = _ws.Names["_xlnm.Print_Titles"]; + if (r.Start.Row == 1 && r.End.Row == ExcelPackage.MaxRows) { + return new(r.FirstAddress); + } + if (r._addresses != null + && (r._addresses[0].Start.Row == 1 + && r._addresses[0].End.Row == ExcelPackage.MaxRows)) { + return r._addresses[0]; + } + return null; + } + return null; + } + set { + //Must span entire rows + if (!(value.Start.Row == 1 && value.End.Row == ExcelPackage.MaxRows)) { + throw new InvalidOperationException( + "Address must span rows only (for ex. Address=\"1:1\" for the first row)."); + } + + var horAddr = RepeatRows; + string addr; + if (horAddr == null) { + addr = value.Address; + } else { + addr = value.Address + "," + horAddr.Address; + } + + if (_ws.Names.ContainsKey("_xlnm.Print_Titles")) { + _ws.Names["_xlnm.Print_Titles"].Address = addr; + } else { + _ws.Names.Add("_xlnm.Print_Titles", new(_ws, addr)); + } + } + } + + /// <summary> + /// The printarea. + /// Null if no print area is set. + /// </summary> + public ExcelRangeBase PrintArea { + get { + if (_ws.Names.ContainsKey("_xlnm.Print_Area")) { + return _ws.Names["_xlnm.Print_Area"]; + } + return null; + } + set { + if (value == null) { + _ws.Names.Remove("_xlnm.Print_Area"); + } else if (_ws.Names.ContainsKey("_xlnm.Print_Area")) { + _ws.Names["_xlnm.Print_Area"].Address = value.Address; + } else { + _ws.Names.Add("_xlnm.Print_Area", value); + } + } + } + + private const string _gridLinesPath = "d:printOptions/@gridLines"; + + /// <summary> + /// Print gridlines + /// </summary> + public bool ShowGridLines { + get => GetXmlNodeBool(_gridLinesPath, false); + set => SetXmlNodeBool(_gridLinesPath, value, false); + } + + private const string _horizontalCenteredPath = "d:printOptions/@horizontalCentered"; + + /// <summary> + /// Horizontal centered when printing + /// </summary>w + public bool HorizontalCentered { + get => GetXmlNodeBool(_horizontalCenteredPath, false); + set => SetXmlNodeBool(_horizontalCenteredPath, value, false); + } + + private const string _verticalCenteredPath = "d:printOptions/@verticalCentered"; + + /// <summary> + /// Vertical centered when printing + /// </summary> + public bool VerticalCentered { + get => GetXmlNodeBool(_verticalCenteredPath, false); + set => SetXmlNodeBool(_verticalCenteredPath, value, false); + } + + private const string _pageOrderPath = "d:pageSetup/@pageOrder"; + + /// <summary> + /// Specifies printed page order + /// </summary> + public ePageOrder PageOrder { + get { + if (GetXmlNodeString(_pageOrderPath) == "overThenDown") { + return ePageOrder.OverThenDown; + } + return ePageOrder.DownThenOver; + } + set { + if (value == ePageOrder.OverThenDown) { + SetXmlNodeString(_pageOrderPath, "overThenDown"); + } else { + DeleteNode(_pageOrderPath); + } + } + } + + private const string _blackAndWhitePath = "d:pageSetup/@blackAndWhite"; + + /// <summary> + /// Print black and white + /// </summary> + public bool BlackAndWhite { + get => GetXmlNodeBool(_blackAndWhitePath, false); + set => SetXmlNodeBool(_blackAndWhitePath, value, false); + } + + private const string _draftPath = "d:pageSetup/@draft"; + + /// <summary> + /// Print a draft + /// </summary> + public bool Draft { + get => GetXmlNodeBool(_draftPath, false); + set => SetXmlNodeBool(_draftPath, value, false); + } + + private const string _paperSizePath = "d:pageSetup/@paperSize"; + + /// <summary> + /// Paper size + /// </summary> + public ePaperSize PaperSize { + get { + string s = GetXmlNodeString(_paperSizePath); + if (s != "") { + return (ePaperSize)int.Parse(s); + } + return ePaperSize.Letter; + } + set => SetXmlNodeString(_paperSizePath, ((int)value).ToString()); + } + + /// <summary> + /// All or none of the margin attributes must exist. Create all att ones. + /// </summary> + private void CreateMargins() { + if (_marginsCreated == false + && TopNode.SelectSingleNode(_leftMarginPath, NameSpaceManager) == null) { + _marginsCreated = true; + LeftMargin = 0.7087M; + RightMargin = 0.7087M; + TopMargin = 0.7480M; + BottomMargin = 0.7480M; + HeaderMargin = 0.315M; + FooterMargin = 0.315M; + } + } }
diff --git a/EPPlus/ExcelProtectedRange.cs b/EPPlus/ExcelProtectedRange.cs index bb66945..ef0da39 100644 --- a/EPPlus/ExcelProtectedRange.cs +++ b/EPPlus/ExcelProtectedRange.cs
@@ -1,44 +1,35 @@ -using OfficeOpenXml.Utils; using System.Xml; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml -{ - public class ExcelProtectedRange : XmlHelper - { - public string Name - { - get - { - return GetXmlNodeString("@name"); - } - set - { - SetXmlNodeString("@name",value); - } - } - ExcelAddress _address=null; - public ExcelAddress Address - { - get - { - if(_address==null) - { - _address=new ExcelAddress(GetXmlNodeString("@sqref")); - } - return _address; - } - set - { - SetXmlNodeString("@sqref", SqRefUtility.ToSqRefAddress(value.Address)); - _address=value; - } - } +namespace OfficeOpenXml; - internal ExcelProtectedRange(string name, ExcelAddress address, XmlNamespaceManager ns, XmlNode topNode) : - base(ns,topNode) - { - Name = name; - Address = address; - } +public class ExcelProtectedRange : XmlHelper { + public string Name { + get => GetXmlNodeString("@name"); + set => SetXmlNodeString("@name", value); + } + + private ExcelAddress _address; + public ExcelAddress Address { + get { + if (_address == null) { + _address = new(GetXmlNodeString("@sqref")); + } + return _address; } + set { + SetXmlNodeString("@sqref", SqRefUtility.ToSqRefAddress(value.Address)); + _address = value; + } + } + + internal ExcelProtectedRange( + string name, + ExcelAddress address, + XmlNamespaceManager ns, + XmlNode topNode) + : base(ns, topNode) { + Name = name; + Address = address; + } }
diff --git a/EPPlus/ExcelProtectedRangeCollection.cs b/EPPlus/ExcelProtectedRangeCollection.cs index 9285975..72afcc3 100644 --- a/EPPlus/ExcelProtectedRangeCollection.cs +++ b/EPPlus/ExcelProtectedRangeCollection.cs
@@ -1,94 +1,89 @@ -using OfficeOpenXml.Utils; -using System; +using System.Collections; using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Text; using System.Xml; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml -{ - public class ExcelProtectedRangeCollection : XmlHelper, IEnumerable<ExcelProtectedRange> - { - internal ExcelProtectedRangeCollection(XmlNamespaceManager nsm, XmlNode topNode, ExcelWorksheet ws) - : base(nsm, topNode) - { - foreach (XmlNode protectedRangeNode in topNode.SelectNodes("d:protectedRanges/d:protectedRange", nsm)) - { - if (!(protectedRangeNode is XmlElement)) - continue; - _baseList.Add(new ExcelProtectedRange(protectedRangeNode.Attributes["name"].Value, new ExcelAddress(SqRefUtility.FromSqRefAddress(protectedRangeNode.Attributes["sqref"].Value)), nsm, topNode)); - } - } +namespace OfficeOpenXml; - private List<ExcelProtectedRange> _baseList = new List<ExcelProtectedRange>(); - - public ExcelProtectedRange Add(string name, ExcelAddress address) - { - if (!ExistNode("d:protectedRanges")) - CreateNode("d:protectedRanges"); - - var newNode = CreateNode("d:protectedRanges/d:protectedRange"); - var item = new ExcelProtectedRange(name, address, base.NameSpaceManager, newNode); - _baseList.Add(item); - return item; - } - - public void Clear() - { - DeleteNode("d:protectedRanges"); - _baseList.Clear(); - } - - public bool Contains(ExcelProtectedRange item) - { - return _baseList.Contains(item); - } - - public void CopyTo(ExcelProtectedRange[] array, int arrayIndex) - { - _baseList.CopyTo(array, arrayIndex); - } - - public int Count - { - get { return _baseList.Count; } - } - - public bool Remove(ExcelProtectedRange item) - { - DeleteAllNode("d:protectedRanges/d:protectedRange[@name='" + item.Name + "' and @sqref='" + item.Address.Address + "']"); - if (_baseList.Count == 0) - DeleteNode("d:protectedRanges"); - return _baseList.Remove(item); - } - - public int IndexOf(ExcelProtectedRange item) - { - return _baseList.IndexOf(item); - } - - public void RemoveAt(int index) - { - _baseList.RemoveAt(index); - } - - public ExcelProtectedRange this[int index] - { - get - { - return _baseList[index]; - } - } - - IEnumerator<ExcelProtectedRange> IEnumerable<ExcelProtectedRange>.GetEnumerator() - { - return _baseList.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _baseList.GetEnumerator(); - } +public class ExcelProtectedRangeCollection : XmlHelper, IEnumerable<ExcelProtectedRange> { + internal ExcelProtectedRangeCollection( + XmlNamespaceManager nsm, + XmlNode topNode, + ExcelWorksheet ws) + : base(nsm, topNode) { + foreach (XmlNode protectedRangeNode in topNode.SelectNodes( + "d:protectedRanges/d:protectedRange", + nsm)) { + if (!(protectedRangeNode is XmlElement)) { + continue; + } + _baseList.Add( + new( + protectedRangeNode.Attributes["name"].Value, + new(SqRefUtility.FromSqRefAddress(protectedRangeNode.Attributes["sqref"].Value)), + nsm, + topNode)); } + } + + private List<ExcelProtectedRange> _baseList = new(); + + public ExcelProtectedRange Add(string name, ExcelAddress address) { + if (!ExistNode("d:protectedRanges")) { + CreateNode("d:protectedRanges"); + } + + var newNode = CreateNode("d:protectedRanges/d:protectedRange"); + var item = new ExcelProtectedRange(name, address, NameSpaceManager, newNode); + _baseList.Add(item); + return item; + } + + public void Clear() { + DeleteNode("d:protectedRanges"); + _baseList.Clear(); + } + + public bool Contains(ExcelProtectedRange item) { + return _baseList.Contains(item); + } + + public void CopyTo(ExcelProtectedRange[] array, int arrayIndex) { + _baseList.CopyTo(array, arrayIndex); + } + + public int Count => _baseList.Count; + + public bool Remove(ExcelProtectedRange item) { + DeleteAllNode( + "d:protectedRanges/d:protectedRange[@name='" + + item.Name + + "' and @sqref='" + + item.Address.Address + + "']"); + if (_baseList.Count == 0) { + DeleteNode("d:protectedRanges"); + } + return _baseList.Remove(item); + } + + public int IndexOf(ExcelProtectedRange item) { + return _baseList.IndexOf(item); + } + + public void RemoveAt(int index) { + _baseList.RemoveAt(index); + } + + public ExcelProtectedRange this[int index] { + get { return _baseList[index]; } + } + + IEnumerator<ExcelProtectedRange> IEnumerable<ExcelProtectedRange>.GetEnumerator() { + return _baseList.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _baseList.GetEnumerator(); + } }
diff --git a/EPPlus/ExcelProtection.cs b/EPPlus/ExcelProtection.cs index 6e307a3..bf10612 100644 --- a/EPPlus/ExcelProtection.cs +++ b/EPPlus/ExcelProtection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,82 +13,65 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 10-AUG-2010 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System.Xml; -namespace OfficeOpenXml -{ - /// <summary> - /// Sets protection on the workbook level - ///<seealso cref="ExcelEncryption"/> - ///<seealso cref="ExcelSheetProtection"/> - /// </summary> - public class ExcelProtection : XmlHelper - { - internal ExcelProtection(XmlNamespaceManager ns, XmlNode topNode, ExcelWorkbook wb) : - base(ns, topNode) - { - SchemaNodeOrder = wb.SchemaNodeOrder; - } - const string lockStructurePath = "d:workbookProtection/@lockStructure"; - /// <summary> - /// Locks the structure,which prevents users from adding or deleting worksheets or from displaying hidden worksheets. - /// </summary> - public bool LockStructure - { - get - { - return GetXmlNodeBool(lockStructurePath, false); - } - set - { - SetXmlNodeBool(lockStructurePath, value, false); - } - } - const string lockWindowsPath = "d:workbookProtection/@lockWindows"; - /// <summary> - /// Locks the position of the workbook window. - /// </summary> - public bool LockWindows - { - get - { - return GetXmlNodeBool(lockWindowsPath, false); - } - set - { - SetXmlNodeBool(lockWindowsPath, value, false); - } - } - const string lockRevisionPath = "d:workbookProtection/@lockRevision"; - /// <summary> - /// Lock the workbook for revision - /// </summary> - public bool LockRevision - { - get - { - return GetXmlNodeBool(lockRevisionPath, false); - } - set - { - SetXmlNodeBool(lockRevisionPath, value, false); - } - } - } +using System.Xml; + +namespace OfficeOpenXml; + +/// <summary> +/// Sets protection on the workbook level +///<seealso cref="ExcelEncryption"/> +///<seealso cref="ExcelSheetProtection"/> +/// </summary> +public class ExcelProtection : XmlHelper { + internal ExcelProtection(XmlNamespaceManager ns, XmlNode topNode, ExcelWorkbook wb) + : base(ns, topNode) { + SchemaNodeOrder = wb.SchemaNodeOrder; + } + + private const string _lockStructurePath = "d:workbookProtection/@lockStructure"; + + /// <summary> + /// Locks the structure,which prevents users from adding or deleting worksheets or from displaying hidden worksheets. + /// </summary> + public bool LockStructure { + get => GetXmlNodeBool(_lockStructurePath, false); + set => SetXmlNodeBool(_lockStructurePath, value, false); + } + + private const string _lockWindowsPath = "d:workbookProtection/@lockWindows"; + + /// <summary> + /// Locks the position of the workbook window. + /// </summary> + public bool LockWindows { + get => GetXmlNodeBool(_lockWindowsPath, false); + set => SetXmlNodeBool(_lockWindowsPath, value, false); + } + + private const string _lockRevisionPath = "d:workbookProtection/@lockRevision"; + + /// <summary> + /// Lock the workbook for revision + /// </summary> + public bool LockRevision { + get => GetXmlNodeBool(_lockRevisionPath, false); + set => SetXmlNodeBool(_lockRevisionPath, value, false); + } }
diff --git a/EPPlus/ExcelRange.cs b/EPPlus/ExcelRange.cs index 8396c9d..92352fc 100644 --- a/EPPlus/ExcelRange.cs +++ b/EPPlus/ExcelRange.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,155 +13,111 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -using OfficeOpenXml.Style; -using System.Data; -namespace OfficeOpenXml -{ - /// <summary> - /// A range of cells. - /// </summary> - public class ExcelRange : ExcelRangeBase - { - #region "Constructors" - internal ExcelRange(ExcelWorksheet sheet) : - base(sheet) - { - } - internal ExcelRange(ExcelWorksheet sheet, string address) - : base(sheet, address) - { +namespace OfficeOpenXml; - } - internal ExcelRange(ExcelWorksheet sheet, int fromRow, int fromCol, int toRow, int toCol) - : base(sheet) - { - _fromRow = fromRow; - _fromCol = fromCol; - _toRow = toRow; - _toCol = toCol; - } - #endregion - #region "Indexers" - /// <summary> - /// Access the range using an address - /// </summary> - /// <param name="Address">The address</param> - /// <returns>A range object</returns> - public ExcelRange this[string Address] - { - get - { - if (_worksheet.Names.ContainsKey(Address)) - { - if (_worksheet.Names[Address].IsName) - { - return null; - } - else - { - base.Address = _worksheet.Names[Address].Address; - } - } - else - { - base.Address = Address; - } - return this; - } - } +/// <summary> +/// A range of cells. +/// </summary> +public class ExcelRange : ExcelRangeBase { + internal ExcelRange(ExcelWorksheet sheet) + : base(sheet) {} - private ExcelRange GetTableAddess(ExcelWorksheet _worksheet, string address) - { - int ixStart = address.IndexOf('['); - if (ixStart == 0) //External Address - { - int ixEnd = address.IndexOf(']',ixStart+1); - if (ixStart >= 0 & ixEnd >= 0) - { - var external = address.Substring(ixStart + 1, ixEnd - 1); - //if (Worksheet.Workbook._externalReferences.Count < external) - //{ - //foreach(var - //} - } - } - return null; - } - /// <summary> - /// Access a single cell - /// </summary> - /// <param name="Row">The row</param> - /// <param name="Col">The column</param> - /// <returns>A range object</returns> - public ExcelRange this[int Row, int Col] - { - get - { - ValidateRowCol(Row, Col); + internal ExcelRange(ExcelWorksheet sheet, string address) + : base(sheet, address) {} - _fromCol = Col; - _fromRow = Row; - _toCol = Col; - _toRow = Row; - base.Address = GetAddress(_fromRow, _fromCol); - return this; - } - } - /// <summary> - /// Access a range of cells - /// </summary> - /// <param name="FromRow">Start row</param> - /// <param name="FromCol">Start column</param> - /// <param name="ToRow">End Row</param> - /// <param name="ToCol">End Column</param> - /// <returns></returns> - public ExcelRange this[int FromRow, int FromCol, int ToRow, int ToCol] - { - get - { - ValidateRowCol(FromRow, FromCol); - ValidateRowCol(ToRow, ToCol); + internal ExcelRange(ExcelWorksheet sheet, int fromRow, int fromCol, int toRow, int toCol) + : base(sheet) { + _fromRow = fromRow; + _fromCol = fromCol; + _toRow = toRow; + _toCol = toCol; + } - _fromCol = FromCol; - _fromRow = FromRow; - _toCol = ToCol; - _toRow = ToRow; - base.Address = GetAddress(_fromRow, _fromCol, _toRow, _toCol); - return this; - } + /// <summary> + /// Access the range using an address + /// </summary> + /// <param name="address">The address</param> + /// <returns>A range object</returns> + public ExcelRange this[string address] { + get { + if (_worksheet.Names.ContainsKey(address)) { + if (_worksheet.Names[address].IsName) { + return null; } - #endregion - private static void ValidateRowCol(int Row, int Col) - { - if (Row < 1 || Row > ExcelPackage.MaxRows) - { - throw (new ArgumentException("Row out of range")); - } - if (Col < 1 || Col > ExcelPackage.MaxColumns) - { - throw (new ArgumentException("Column out of range")); - } - } - + Address = _worksheet.Names[address].Address; + } else { + Address = address; + } + return this; } + } + + /// <summary> + /// Access a single cell + /// </summary> + /// <param name="row">The row</param> + /// <param name="col">The column</param> + /// <returns>A range object</returns> + public ExcelRange this[int row, int col] { + get { + ValidateRowCol(row, col); + + _fromCol = col; + _fromRow = row; + _toCol = col; + _toRow = row; + Address = GetAddress(_fromRow, _fromCol); + return this; + } + } + + /// <summary> + /// Access a range of cells + /// </summary> + /// <param name="fromRow">Start row</param> + /// <param name="fromCol">Start column</param> + /// <param name="toRow">End Row</param> + /// <param name="toCol">End Column</param> + /// <returns></returns> + public ExcelRange this[int fromRow, int fromCol, int toRow, int toCol] { + get { + ValidateRowCol(fromRow, fromCol); + ValidateRowCol(toRow, toCol); + + _fromCol = fromCol; + _fromRow = fromRow; + _toCol = toCol; + _toRow = toRow; + Address = GetAddress(_fromRow, _fromCol, _toRow, _toCol); + return this; + } + } + + private static void ValidateRowCol(int row, int col) { + if (row < 1 || row > ExcelPackage.MaxRows) { + throw (new ArgumentException("Row out of range")); + } + if (col < 1 || col > ExcelPackage.MaxColumns) { + throw (new ArgumentException("Column out of range")); + } + } }
diff --git a/EPPlus/ExcelRangeBase.cs b/EPPlus/ExcelRangeBase.cs index a4cf198..fd753d6 100644 --- a/EPPlus/ExcelRangeBase.cs +++ b/EPPlus/ExcelRangeBase.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,2750 +13,2409 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2010-01-28 * Jan Källman License changed GPL-->LGPL 2011-12-27 * Eyal Seagull Conditional Formatting 2012-04-03 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; -using System.Text; using System.Data; -using System.Threading; -using OfficeOpenXml.FormulaParsing; -using OfficeOpenXml.Style; -using System.Xml; -using System.Drawing; using System.Globalization; -using System.Collections; -using OfficeOpenXml.Table; -using System.Text.RegularExpressions; using System.IO; using System.Linq; -using OfficeOpenXml.DataValidation; -using OfficeOpenXml.DataValidation.Contracts; using System.Reflection; -using OfficeOpenXml.Style.XmlAccess; using System.Security; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading; +using System.Xml; using OfficeOpenXml.ConditionalFormatting; -using OfficeOpenXml.ConditionalFormatting.Contracts; +using OfficeOpenXml.DataValidation; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml -{ - /// <summary> - /// A range of cells - /// </summary> - public class ExcelRangeBase : ExcelAddress, IExcelCell, IDisposable, IEnumerable<ExcelRangeBase>, IEnumerator<ExcelRangeBase> - { - /// <summary> - /// Reference to the worksheet - /// </summary> - protected ExcelWorksheet _worksheet; - internal ExcelWorkbook _workbook = null; - private delegate void _changeProp(_setValue method, object value); - private delegate void _setValue(object value, int row, int col); - private _changeProp _changePropMethod; - private int _styleID; - private class CopiedCell - { - internal int Row { get; set; } - internal int Column { get; set; } - internal object Value { get; set; } - internal string Type { get; set; } - internal object Formula { get; set; } - internal int? StyleID { get; set; } - internal Uri HyperLink { get; set; } - internal ExcelComment Comment { get; set; } - internal Byte Flag { get; set; } - } - //private class CopiedFlag - //{ - // internal int Row { get; set; } - // internal int Column { get; set; } - // internal Byte Flag { get; set; } - //} - #region Constructors - internal ExcelRangeBase(ExcelWorksheet xlWorksheet) - { - _worksheet = xlWorksheet; - _ws = _worksheet.Name; - _workbook = _worksheet.Workbook; - this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange); - SetDelegate(); - } +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.Table; - void ExcelRangeBase_AddressChange(object sender, EventArgs e) - { - if (Table != null) - { - SetRCFromTable(_workbook._package, null); - } - SetDelegate(); - } - internal ExcelRangeBase(ExcelWorksheet xlWorksheet, string address) : - base(xlWorksheet == null ? "" : xlWorksheet.Name, address) - { - _worksheet = xlWorksheet; - _workbook = _worksheet.Workbook; - base.SetRCFromTable(_worksheet._package, null); - if (string.IsNullOrEmpty(_ws)) _ws = _worksheet == null ? "" : _worksheet.Name; - this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange); - SetDelegate(); - } - internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName) : - base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName) - { - SetRCFromTable(wb._package, null); - _worksheet = xlWorksheet; - _workbook = wb; - if (string.IsNullOrEmpty(_ws)) _ws = (xlWorksheet == null ? null : xlWorksheet.Name); - this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange); - SetDelegate(); - } - ~ExcelRangeBase() - { - //this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange); - } - #endregion - #region Set Value Delegates - private void SetDelegate() - { - if (_fromRow == -1) - { - _changePropMethod = SetUnknown; - } - //Single cell - else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null) - { - _changePropMethod = SetSingle; - } - //Range (ex A1:A2) - else if (Addresses == null) - { - _changePropMethod = SetRange; - } - //Multi Range (ex A1:A2,C1:C2) - else - { - _changePropMethod = SetMultiRange; - } - } - /// <summary> - /// We dont know the address yet. Set the delegate first time a property is set. - /// </summary> - /// <param name="valueMethod"></param> - /// <param name="value"></param> - private void SetUnknown(_setValue valueMethod, object value) - { - //Address is not set use, selected range - if (_fromRow == -1) - { - SetToSelectedRange(); - } - SetDelegate(); - _changePropMethod(valueMethod, value); - } - /// <summary> - /// Set a single cell - /// </summary> - /// <param name="valueMethod"></param> - /// <param name="value"></param> - private void SetSingle(_setValue valueMethod, object value) - { - valueMethod(value, _fromRow, _fromCol); - } - /// <summary> - /// Set a range - /// </summary> - /// <param name="valueMethod"></param> - /// <param name="value"></param> - private void SetRange(_setValue valueMethod, object value) - { - SetValueAddress(this, valueMethod, value); - } - /// <summary> - /// Set a multirange (A1:A2,C1:C2) - /// </summary> - /// <param name="valueMethod"></param> - /// <param name="value"></param> - private void SetMultiRange(_setValue valueMethod, object value) - { - SetValueAddress(this, valueMethod, value); - foreach (var address in Addresses) - { - SetValueAddress(address, valueMethod, value); - } - } - /// <summary> - /// Set the property for an address - /// </summary> - /// <param name="address"></param> - /// <param name="valueMethod"></param> - /// <param name="value"></param> - private void SetValueAddress(ExcelAddress address, _setValue valueMethod, object value) - { - IsRangeValid(""); - if (_fromRow == 1 && _fromCol == 1 && _toRow == ExcelPackage.MaxRows && _toCol == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging - { - throw (new ArgumentException("Can't reference all cells. Please use the indexer to set the range")); - } - else - { - for (int col = address.Start.Column; col <= address.End.Column; col++) - { - for (int row = address.Start.Row; row <= address.End.Row; row++) - { - valueMethod(value, row, col); - } - } - } - } - #endregion - #region Set property methods - private void Set_StyleID(object value, int row, int col) - { - _worksheet._styles.SetValue(row, col, (int)value); - } - private void Set_StyleName(object value, int row, int col) - { - //_worksheet.Cell(row, col).SetNewStyleName(value.ToString(), _styleID); - _worksheet._styles.SetValue(row, col, _styleID); - } - private void Set_Value(object value, int row, int col) - { - //ExcelCell c = _worksheet.Cell(row, col); - var sfi = _worksheet._formulas.GetValue(row, col); - if (sfi is int) - { - SplitFormulas(_worksheet.Cells[row, col]); - } - if (sfi != null) _worksheet._formulas.SetValue(row, col, string.Empty); - _worksheet._values.SetValue(row, col, value); - } - private void Set_Formula(object value, int row, int col) - { - //ExcelCell c = _worksheet.Cell(row, col); - var f = _worksheet._formulas.GetValue(row, col); - if (f is int && (int)f >= 0) SplitFormulas(_worksheet.Cells[row, col]); +namespace OfficeOpenXml; - string formula = (value == null ? string.Empty : value.ToString()); - if (formula == string.Empty) - { - _worksheet._formulas.SetValue(row, col, string.Empty); - } - else - { - if (formula[0] == '=') value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign. - _worksheet._formulas.SetValue(row, col, formula); - _worksheet._values.SetValue(row, col, null); - } - } - /// <summary> - /// Handles shared formulas - /// </summary> - /// <param name="value">The formula</param> - /// <param name="address">The address of the formula</param> - /// <param name="IsArray">If the forumla is an array formula.</param> - private void Set_SharedFormula(string value, ExcelAddress address, bool IsArray) - { - if (_fromRow == 1 && _fromCol == 1 && _toRow == ExcelPackage.MaxRows && _toCol == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging - { - throw (new InvalidOperationException("Can't set a formula for the entire worksheet")); - } - else if (address.Start.Row == address.End.Row && address.Start.Column == address.End.Column && !IsArray) //is it really a shared formula? Arrayformulas can be one cell only - { - //Nope, single cell. Set the formula - Set_Formula(value, address.Start.Row, address.Start.Column); - return; - } - //RemoveFormuls(address); - CheckAndSplitSharedFormula(address); - ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default); - f.Formula = value; - f.Index = _worksheet.GetMaxShareFunctionIndex(IsArray); - f.Address = address.FirstAddress; - f.StartCol = address.Start.Column; - f.StartRow = address.Start.Row; - f.IsArray = IsArray; +/// <summary> +/// A range of cells +/// </summary> +public class ExcelRangeBase + : ExcelAddress, + IExcelCell, + IDisposable, + IEnumerable<ExcelRangeBase>, + IEnumerator<ExcelRangeBase> { + /// <summary> + /// Reference to the worksheet + /// </summary> + protected ExcelWorksheet _worksheet; + internal ExcelWorkbook _workbook; - _worksheet._sharedFormulas.Add(f.Index, f); - //_worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index; - //_worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value; + private delegate void ChangePropHandler(SetValueHandler method, object value); - for (int col = address.Start.Column; col <= address.End.Column; col++) - { - for (int row = address.Start.Row; row <= address.End.Row; row++) - { - //_worksheet.Cell(row, col).SharedFormulaID = f.Index; - _worksheet._formulas.SetValue(row, col, f.Index); - _worksheet._values.SetValue(row, col, null); - } - } - } - private void Set_HyperLink(object value, int row, int col) - { - //_worksheet.Cell(row, col).Hyperlink = value as Uri; - if (value is Uri) - { - _worksheet._hyperLinks.SetValue(row, col, (Uri)value); + private delegate void SetValueHandler(object value, int row, int col); - if (value is ExcelHyperLink) - { - _worksheet._values.SetValue(row, col, ((ExcelHyperLink)value).Display); - } - else - { - _worksheet._values.SetValue(row, col, ((Uri)value).OriginalString); - } - } - else - { - _worksheet._hyperLinks.SetValue(row, col, (Uri)null); - _worksheet._values.SetValue(row, col, (Uri)null); - } - } - private void Set_IsArrayFormula(object value, int row, int col) - { - _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.ArrayFormula); - } - private void Set_IsRichText(object value, int row, int col) - { - //_worksheet.Cell(row, col).IsRichText = (bool)value; - _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.RichText); - } - private void Exists_Comment(object value, int row, int col) - { - ulong cellID = GetCellID(_worksheet.SheetID, row, col); - if (_worksheet.Comments._comments.ContainsKey(cellID)) - { - throw (new InvalidOperationException(string.Format("Cell {0} already contain a comment.", new ExcelCellAddress(row, col).Address))); - } + private ChangePropHandler _changePropMethod; + private int _styleID; - } - private void Set_Comment(object value, int row, int col) - { - string[] v = (string[])value; - Worksheet.Comments.Add(new ExcelRangeBase(_worksheet, GetAddress(_fromRow, _fromCol)), v[0], v[1]); - // _worksheet.Cell(row, col).Comment = comment; - } - #endregion - private void SetToSelectedRange() - { - if (_worksheet.View.SelectedRange == "") - { - Address = "A1"; - } - else - { - Address = _worksheet.View.SelectedRange; - } - } - private void IsRangeValid(string type) - { - if (_fromRow <= 0) - { - if (_address == "") - { - SetToSelectedRange(); - } - else - { - if (type == "") - { - throw (new InvalidOperationException(string.Format("Range is not valid for this operation: {0}", _address))); - } - else - { - throw (new InvalidOperationException(string.Format("Range is not valid for {0} : {1}", type, _address))); - } - } - } - } - #region Public Properties - /// <summary> - /// The styleobject for the range. - /// </summary> - public ExcelStyle Style - { - get - { - IsRangeValid("styling"); - int s=0; - if(!_worksheet._styles.Exists(_fromRow,_fromCol, ref s)) //Cell exists - { - if(!_worksheet._styles.Exists(_fromRow,0, ref s)) //No, check Row style - { - var c = Worksheet.GetColumn(_fromCol); - if (c == null) - { - s = 0; - } - else - { - s = c.StyleID; - } - } - } - return _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, Address); - } - } - /// <summary> - /// The named style - /// </summary> - public string StyleName - { - get - { - IsRangeValid("styling"); - int xfId; - if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows) - { - xfId=GetColumnStyle(_fromCol); - } - else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) - { - xfId = 0; - if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) - { - xfId = GetColumnStyle(_fromCol); - } - } - else - { - xfId = 0; - if(!_worksheet._styles.Exists(_fromRow, _fromCol, ref xfId)) - { - if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) - { - xfId = GetColumnStyle(_fromCol); - } - } - } - int nsID; - if (xfId <= 0) - { - nsID=Style.Styles.CellXfs[0].XfId; - } - else - { - nsID=Style.Styles.CellXfs[xfId].XfId; - } - foreach (var ns in Style.Styles.NamedStyles) - { - if (ns.StyleXfId == nsID) - { - return ns.Name; - } - } - - return ""; - } - set - { - _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); - int col = _fromCol; - if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows) //Full column - { - ExcelColumn column; - //Get the startcolumn - //ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, column); - var c = _worksheet.GetValue(0, _fromCol); - if (c==null) - { - column = _worksheet.Column(_fromCol); - //if (_worksheet._values.PrevCell(ref row, ref col)) - //{ - // var prevCol = (ExcelColumn)_worksheet._values.GetValue(row, col); - // column = prevCol.Clone(_worksheet, column); - // prevCol.ColumnMax = column - 1; - //} - } - else - { - column = (ExcelColumn)c; - } + private class CopiedCell { + internal int Row { get; set; } - column.StyleName = value; - column.StyleID = _styleID; + internal int Column { get; set; } - //var index = _worksheet._columns.IndexOf(colID); - var cols = new CellsStoreEnumerator<object>(_worksheet._values, 0, _fromCol + 1, 0, _toCol); - if (cols.Next()) - { - col = _fromCol; - while (column.ColumnMin <= _toCol) - { - if (column.ColumnMax > _toCol) - { - var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax); - column.ColumnMax = _toCol; - } + internal object Value { get; set; } - column._styleName = value; - column.StyleID = _styleID; + internal string Type { get; set; } - if (cols.Value == null) - { - break; - } - else - { - var nextCol = (ExcelColumn)cols.Value; - if(column.ColumnMax < nextCol.ColumnMax-1) - { - column.ColumnMax = nextCol.ColumnMax - 1; - } - column = nextCol; - cols.Next(); - } - } - } - if (column.ColumnMax < _toCol) - { - column.ColumnMax = _toCol; - } - //if (column.ColumnMin == column) - //{ - // column.ColumnMax = _toCol; - //} - //else if (column._columnMax < _toCol) - //{ - // var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn; - // newCol._columnMax = _toCol; + internal object Formula { get; set; } - // newCol._styleID = _styleID; - // newCol._styleName = value; - //} - if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) //FullRow - { - var rows = new CellsStoreEnumerator<object>(_worksheet._values, 1, 0, ExcelPackage.MaxRows, 0); - rows.Next(); - while(rows.Value!=null) - { - _worksheet._styles.SetValue(rows.Row, 0, _styleID); - if (!rows.Next()) - { - break; - } - } - } - } - else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) //FullRow - { - for (int r = _fromRow; r <= _toRow; r++) - { - _worksheet.Row(r)._styleName = value; - _worksheet.Row(r).StyleID = _styleID; - } - } + internal int? StyleID { get; set; } - if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows) || (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns))) //Cell specific - { - for (int c = _fromCol; c <= _toCol; c++) - { - for (int r = _fromRow; r <= _toRow; r++) - { - _worksheet._styles.SetValue(r, c, _styleID); - } - } - } - else //Only set name on created cells. (uncreated cells is set on full row or full column). - { - var cells = new CellsStoreEnumerator<object>(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol); - while (cells.Next()) - { - _worksheet._styles.SetValue(cells.Row, cells.Column, _styleID); - } - } - //_changePropMethod(Set_StyleName, value); - } - } + internal Uri HyperLink { get; set; } - private int GetColumnStyle(int col) - { - object c=null; - if (_worksheet._values.Exists(0, col, ref c)) - { - return (c as ExcelColumn).StyleID; - } - else - { - int row = 0; - if (_worksheet._values.PrevCell(ref row, ref col)) - { - var column=_worksheet._values.GetValue(row,col) as ExcelColumn; - if(column.ColumnMax>=col) - { - return _worksheet._styles.GetValue(row, col); - } - } - } - return 0; - } - /// <summary> - /// The style ID. - /// It is not recomended to use this one. Use Named styles as an alternative. - /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook. - /// </summary> - public int StyleID - { - get - { - int s=0; - if(!_worksheet._styles.Exists(_fromRow, _fromCol, ref s)) - { - if (!_worksheet._styles.Exists(_fromRow, 0, ref s)) - { - s = _worksheet._styles.GetValue(0, _fromCol); - } - } - return s; - } - set - { - _changePropMethod(Set_StyleID, value); - } - } - /// <summary> - /// Set the range to a specific value - /// </summary> - public object Value - { - get - { - if (IsName) - { - if (_worksheet == null) - { - return _workbook._names[_address].NameValue; - } - else - { - return _worksheet.Names[_address].NameValue; - } - } - else - { - if (_fromRow == _toRow && _fromCol == _toCol) - { - return _worksheet.GetValue(_fromRow, _fromCol); - } - else - { - return GetValueArray(); - } - } - } - set - { - if (IsName) - { - if (_worksheet == null) - { - _workbook._names[_address].NameValue = value; - } - else - { - _worksheet.Names[_address].NameValue = value; - } - } - else - { - _changePropMethod(Set_Value, value); - } - } - } + internal ExcelComment Comment { get; set; } - private bool IsInfinityValue(object value) - { - double? valueAsDouble = value as double?; + internal Byte Flag { get; set; } + } - if(valueAsDouble.HasValue && - (double.IsNegativeInfinity(valueAsDouble.Value) || double.IsPositiveInfinity(valueAsDouble.Value))) - { - return true; - } + //private class CopiedFlag + //{ + // internal int Row { get; set; } + // internal int Column { get; set; } + // internal Byte Flag { get; set; } + //} - return false; - } - private object GetValueArray() - { - ExcelAddressBase addr; - if (_fromRow == 1 && _fromCol == 1 && _toRow == ExcelPackage.MaxRows && _toCol == ExcelPackage.MaxColumns) - { - addr = _worksheet.Dimension; - if (addr == null) return null; - } - else - { - addr = this; - } - object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1]; + internal ExcelRangeBase(ExcelWorksheet xlWorksheet) { + _worksheet = xlWorksheet; + _ws = _worksheet.Name; + _workbook = _worksheet.Workbook; + AddressChange += ExcelRangeBase_AddressChange; + SetDelegate(); + } - for (int col = addr._fromCol; col <= addr._toCol; col++) - { - for (int row = addr._fromRow; row <= addr._toRow; row++) - { - if (_worksheet._values.Exists(row,col)) - { - if (_worksheet._flags.GetFlagValue(row, col, CellFlags.RichText)) - { - v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text; - } - else - { - v[row - addr._fromRow, col - addr._fromCol] = _worksheet._values.GetValue(row, col); - } - } - } - } - return v; - } - private ExcelAddressBase GetAddressDim(ExcelRangeBase addr) - { - int fromRow, fromCol, toRow, toCol; - var d = _worksheet.Dimension; - fromRow = addr._fromRow < d._fromRow ? d._fromRow : addr._fromRow; - fromCol = addr._fromCol < d._fromCol ? d._fromCol : addr._fromCol; - - toRow = addr._toRow > d._toRow ? d._toRow : addr._toRow; - toCol = addr._toCol > d._toCol ? d._toCol : addr._toCol; - - if (addr._fromCol == fromRow && addr._toRow == toRow && addr._toCol == _toCol) - { - return addr; - } - else - { - if (_fromRow > _toRow || _fromCol > _toCol) - { - return null; - } - else - { - return new ExcelAddressBase(fromRow, fromCol, toRow, toCol); - } - } - } - - private object GetSingleValue() - { - if (IsRichText) - { - return RichText.Text; - } - else - { - return _worksheet._values.GetValue(_fromRow, _fromCol); - } - } - /// <summary> - /// Returns the formatted value. - /// </summary> - public string Text - { - get - { - return GetFormattedText(false); - } - } - - private void SetMinWidth(double minimumWidth, int fromCol, int toCol) - { - var iterator = new CellsStoreEnumerator<object>(_worksheet._values, 0, fromCol, 0, toCol); - var prevCol = fromCol; - foreach (ExcelColumn col in iterator) - { - col.Width = minimumWidth; - if (_worksheet.DefaultColWidth > minimumWidth && col.ColumnMin > prevCol) - { - var newCol = _worksheet.Column(prevCol); - newCol.ColumnMax = col.ColumnMin - 1; - newCol.Width = minimumWidth; - } - prevCol = col.ColumnMax + 1; - } - if (_worksheet.DefaultColWidth > minimumWidth && prevCol<toCol) - { - var newCol = _worksheet.Column(prevCol); - newCol.ColumnMax = toCol; - newCol.Width = minimumWidth; - } - } - - internal string TextForWidth - { - get - { - return GetFormattedText(true); - } - } - private string GetFormattedText(bool forWidthCalc) - { - object v = Value; - if (v == null) return ""; - var styles = Worksheet.Workbook.Styles; - var nfID = styles.CellXfs[StyleID].NumberFormatId; - ExcelNumberFormatXml.ExcelFormatTranslator nf = null; - for (int i = 0; i < styles.NumberFormats.Count; i++) - { - if (nfID == styles.NumberFormats[i].NumFmtId) - { - nf = styles.NumberFormats[i].FormatTranslator; - break; - } - } - - string format, textFormat; - if (forWidthCalc) - { - format = nf.NetFormatForWidth; - textFormat = nf.NetTextFormatForWidth; - } - else - { - format = nf.NetFormat; - textFormat = nf.NetTextFormat; - } - - return FormatValue(v, nf, format, textFormat); - } - - internal static string FormatValue(object v, ExcelNumberFormatXml.ExcelFormatTranslator nf, string format, string textFormat) - { - if (v is decimal || v.GetType().IsPrimitive) - { - double d; - try - { - d = Convert.ToDouble(v); - } - catch - { - return ""; - } - - if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number) - { - if (string.IsNullOrEmpty(nf.FractionFormat)) - { - return d.ToString(format, nf.Culture); - } - else - { - return nf.FormatFraction(d); - } - } - else if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) - { - var date = DateTime.FromOADate(d); - return date.ToString(format, nf.Culture); - } - } - else if (v is DateTime) - { - if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) - { - return ((DateTime)v).ToString(format, nf.Culture); - } - else - { - double d = ((DateTime)v).ToOADate(); - if (string.IsNullOrEmpty(nf.FractionFormat)) - { - return d.ToString(format, nf.Culture); - } - else - { - return nf.FormatFraction(d); - } - } - } - else if (v is TimeSpan) - { - if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) - { - return new DateTime(((TimeSpan)v).Ticks).ToString(format, nf.Culture); - } - else - { - double d = (new DateTime(((TimeSpan)v).Ticks)).ToOADate(); - if (string.IsNullOrEmpty(nf.FractionFormat)) - { - return d.ToString(format, nf.Culture); - } - else - { - return nf.FormatFraction(d); - } - } - } - else - { - if (textFormat == "") - { - return v.ToString(); - } - else - { - return string.Format(textFormat, v); - } - } - return v.ToString(); -} - /// <summary> - /// Gets or sets a formula for a range. - /// </summary> - public string Formula - { - get - { - if (IsName) - { - if (_worksheet == null) - { - return _workbook._names[_address].NameFormula; - } - else - { - return _worksheet.Names[_address].NameFormula; - } - } - else - { - return _worksheet.GetFormula(_fromRow, _fromCol); - } - } - set - { - if (IsName) - { - if (_worksheet == null) - { - _workbook._names[_address].NameFormula = value; - } - else - { - _worksheet.Names[_address].NameFormula = value; - } - } - else - { - if(value==null || value.Trim()=="") - { - //Set the cells to null - Value = null; - } - else if (_fromRow == _toRow && _fromCol == _toCol) - { - Set_Formula(value, _fromRow, _fromCol); - } - else - { - Set_SharedFormula(value, this, false); - if (Addresses != null) - { - foreach (var address in Addresses) - { - Set_SharedFormula(value, address, false); - } - } - } - } - } - } - /// <summary> - /// Gets or Set a formula in R1C1 format. - /// </summary> - public string FormulaR1C1 - { - get - { - IsRangeValid("FormulaR1C1"); - return _worksheet.GetFormulaR1C1(_fromRow, _fromCol); - } - set - { - IsRangeValid("FormulaR1C1"); - if (value.Length > 0 && value[0] == '=') value = value.Substring(1, value.Length - 1); // remove any starting equalsign. - - if (value == null || value.Trim() == "") - { - //Set the cells to null - _worksheet.Cells[ExcelCellBase.TranslateFromR1C1(value, _fromRow, _fromCol)].Value = null; - } - else if (Addresses == null) - { - Set_SharedFormula(ExcelCellBase.TranslateFromR1C1(value, _fromRow, _fromCol), this, false); - } - else - { - Set_SharedFormula(ExcelCellBase.TranslateFromR1C1(value, _fromRow, _fromCol), new ExcelAddress(WorkSheet, FirstAddress), false); - foreach (var address in Addresses) - { - Set_SharedFormula(ExcelCellBase.TranslateFromR1C1(value, address.Start.Row, address.Start.Column), address, false); - } - } - } - } - - /// <summary> - /// Gets or Set a formula in R1C1 format. - /// - public string FormulaR1C1_V1 - { - get - { - IsRangeValid("FormulaR1C1"); - return _worksheet.GetFormulaR1C1_V1(_fromRow, _fromCol); - } - } - - public string ArrayFormulaAddress - { - get - { - IsRangeValid("FormulaR1C1"); - return _worksheet.GetArrayFormulaAddress(_fromRow, _fromCol); - } - } - /// <summary> - /// Set the hyperlink property for a range of cells - /// </summary> - public Uri Hyperlink - { - get - { - IsRangeValid("formulaR1C1"); - return _worksheet._hyperLinks.GetValue(_fromRow, _fromCol); - } - set - { - _changePropMethod(Set_HyperLink, value); - } - } - /// <summary> - /// If the cells in the range are merged. - /// </summary> - public bool Merge - { - get - { - IsRangeValid("merging"); - for (int col = _fromCol; col <= _toCol; col++) - { - for (int row = _fromRow; row <= _toRow; row++) - { - if(_worksheet.MergedCells[row, col]==null) - { - return false; - } - //if (!_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged)) - //{ - // return false; - //} - } - } - return true; - } - set - { - IsRangeValid("merging"); - //SetMerge(value, FirstAddress); - if (value) - { - _worksheet.MergedCells.Add(new ExcelAddressBase(FirstAddress), true); - if (Addresses != null) - { - foreach (var address in Addresses) - { - _worksheet.MergedCells.Add(address, true); - //SetMerge(value, address._address); - } - } - } - else - { - _worksheet.MergedCells.Clear(this); - if (Addresses != null) - { - foreach (var address in Addresses) - { - _worksheet.MergedCells.Clear(address); ; - } - } - - } - } - } - - //private void SetMerge(bool value, string address) - //{ - // if (!value) - // { - // if (_worksheet.MergedCells.List.Contains(address)) - // { - // SetCellMerge(false, address); - // _worksheet.MergedCells.List.Remove(address); - // } - // else if (!CheckMergeDiff(false, address)) - // { - // throw (new Exception("Range is not fully merged.Specify the exact range")); - // } - // } - // else - // { - // if (CheckMergeDiff(false, address)) - // { - // SetCellMerge(true, address); - // _worksheet.MergedCells.List.Add(address); - // } - // else - // { - // if (!_worksheet.MergedCells.List.Contains(address)) - // { - // throw (new Exception("Cells are already merged")); - // } - // } - // } - //} - /// <summary> - /// Set an autofilter for the range - /// </summary> - public bool AutoFilter - { - get - { - IsRangeValid("autofilter"); - ExcelAddressBase address = _worksheet.AutoFilterAddress; - if (address == null) return false; - if (_fromRow >= address.Start.Row - && - _toRow <= address.End.Row - && - _fromCol >= address.Start.Column - && - _toCol <= address.End.Column) - { - return true; - } - return false; - } - set - { - IsRangeValid("autofilter"); - _worksheet.AutoFilterAddress = this; - if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase")) - { - _worksheet.Names.Remove("_xlnm._FilterDatabase"); - } - var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this); - result.IsNameHidden = true; - } - } - /// <summary> - /// If the value is in richtext format. - /// </summary> - public bool IsRichText - { - get - { - IsRangeValid("richtext"); - return _worksheet._flags.GetFlagValue(_fromRow, _fromCol,CellFlags.RichText); - } - set - { - _changePropMethod(Set_IsRichText, value); - } - } - /// <summary> - /// Is the range a part of an Arrayformula - /// </summary> - public bool IsArrayFormula - { - get - { - IsRangeValid("arrayformulas"); - return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.ArrayFormula); - } - set - { - _changePropMethod(Set_IsArrayFormula, value); - } - } - ExcelRichTextCollection _rtc = null; - /// <summary> - /// Cell value is richtext formatted. - /// Richtext-property only apply to the left-top cell of the range. - /// </summary> - public ExcelRichTextCollection RichText - { - get - { - IsRangeValid("richtext"); - if (_rtc == null) - { - _rtc = GetRichText(_fromRow, _fromCol); - } - return _rtc; - } - } - - private ExcelRichTextCollection GetRichText(int row, int col) - { - XmlDocument xml = new XmlDocument(); - var v = _worksheet._values.GetValue(row, col); - var isRt = _worksheet._flags.GetFlagValue(row, col, CellFlags.RichText); - if (v != null) - { - if (isRt) - { - XmlHelper.LoadXmlSafe(xml, "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >" + v.ToString() + "</d:si>", Encoding.UTF8); - } - else - { - xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ><d:r><d:t>" + SecurityElement.Escape(v.ToString()) + "</d:t></d:r></d:si>"); - } - } - else - { - xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />"); - } - var rtc = new ExcelRichTextCollection(_worksheet.NameSpaceManager, xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager), this); - return rtc; - } - /// <summary> - /// returns the comment object of the first cell in the range - /// </summary> - public ExcelComment Comment - { - get - { - IsRangeValid("comments"); - ulong cellID = GetCellID(_worksheet.SheetID, _fromRow, _fromCol); - if (_worksheet.Comments._comments.ContainsKey(cellID)) - { - return _worksheet._comments._comments[cellID] as ExcelComment; - } - return null; - } - } - /// <summary> - /// WorkSheet object - /// </summary> - public ExcelWorksheet Worksheet - { - get - { - return _worksheet; - } - } - /// <summary> - /// Address including sheetname - /// </summary> - public string FullAddress - { - get - { - string fullAddress = GetFullAddress(_worksheet.Name, _address); - if (Addresses != null) - { - foreach (var a in Addresses) - { - fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address); ; - } - } - return fullAddress; - } - } - /// <summary> - /// Address including sheetname - /// </summary> - public string FullAddressAbsolute - { - get - { - string wbwsRef = string.IsNullOrEmpty(base._wb) ? base._ws : "[" + base._wb.Replace("'", "''") + "]" + _ws; - string fullAddress = GetFullAddress(wbwsRef, GetAddress(_fromRow, _fromCol, _toRow, _toCol, true)); - if (Addresses != null) - { - foreach (var a in Addresses) - { - fullAddress += "," + GetFullAddress(wbwsRef, GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true)); ; - } - } - return fullAddress; - } - } - /// <summary> - /// Address including sheetname - /// </summary> - internal string FullAddressAbsoluteNoFullRowCol - { - get - { - string wbwsRef = string.IsNullOrEmpty(base._wb) ? base._ws : "[" + base._wb.Replace("'", "''") + "]" + _ws; - string fullAddress = GetFullAddress(wbwsRef, GetAddress(_fromRow, _fromCol, _toRow, _toCol, true), false); - if (Addresses != null) - { - foreach (var a in Addresses) - { - fullAddress += "," + GetFullAddress(wbwsRef, GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true),false); ; - } - } - return fullAddress; - } - } - #endregion - #region Private Methods - ///// <summary> - ///// Check if the range is partly merged - ///// </summary> - ///// <param name="startValue">the starting value</param> - ///// <param name="address">the address</param> - ///// <returns></returns> - //private bool CheckMergeDiff(bool startValue, string address) - //{ - // ExcelAddress a = new ExcelAddress(address); - // for (int col = a.column; col <= a._toCol; col++) - // { - // for (int row = a._fromRow; row <= a._toRow; row++) - // { - // if (_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged) != startValue) - // { - // return false; - // } - // } - // } - // return true; - //} - ///// <summary> - ///// Set the merge flag for the range - ///// </summary> - ///// <param name="value"></param> - ///// <param name="address"></param> - //internal void SetCellMerge(bool value, string address) - //{ - // ExcelAddress a = new ExcelAddress(address); - // for (int col = a.column; col <= a._toCol; col++) - // { - // for (int row = a._fromRow; row <= a._toRow; row++) - // { - // _worksheet._flags.SetFlagValue(row, col,value,CellFlags.Merged); - // } - // } - //} - /// <summary> - /// Set the value without altering the richtext property - /// </summary> - /// <param name="value">the value</param> - internal void SetValueRichText(object value) - { - if (_fromRow == 1 && _fromCol == 1 && _toRow == ExcelPackage.MaxRows && _toCol == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging - { - //_worksheet.Cell(1, 1).SetValueRichText(value); - SetValue(value, 1, 1); - } - else - { - //for (int col = _fromCol; col <= _toCol; col++) - //{ - // for (int row = _fromRow; row <= _toRow; row++) - // { - //_worksheet.Cell(row, col).SetValueRichText(value); - SetValue(value, _fromRow,_fromCol); - //} - //} - } - } - - private void SetValue(object value, int row, int col) - { - _worksheet.SetValue(row, col, value); - // if (value is string) _worksheet._types.SetValue(row, col, "S"); else _worksheet._types.SetValue(row, col, ""); - _worksheet._formulas.SetValue(row, col, ""); - } - /// <summary> - /// Removes a shared formula - /// </summary> - //private void RemoveFormuls(ExcelAddress address) - //{ - // List<int> removed = new List<int>(); - // int fFromRow, fFromCol, fToRow, fToCol; - // foreach (int index in _worksheet._sharedFormulas.Keys) - // { - // ExcelWorksheet.Formulas f = _worksheet._sharedFormulas[index]; - // ExcelCellBase.GetRowColFromAddress(f.Address, out fFromRow, out fFromCol, out fToRow, out fToCol); - // if (((fFromCol >= address.Start.Column && fFromCol <= address.End.Column) || - // (fToCol >= address.Start.Column && fToCol <= address.End.Column)) && - // ((fFromRow >= address.Start.Row && fFromRow <= address.End.Row) || - // (fToRow >= address.Start.Row && fToRow <= address.End.Row))) - // { - // for (int col = fFromCol; col <= fToCol; col++) - // { - // for (int row = fFromRow; row <= fToRow; row++) - // { - // _worksheet._formulas.SetValue(row, col, int.MinValue); - // } - // } - // removed.Add(index); - // } - // } - // foreach (int index in removed) - // { - // _worksheet._sharedFormulas.Remove(index); - // } - //} - internal void SetSharedFormulaID(int id) - { - for (int col = _fromCol; col <= _toCol; col++) - { - for (int row = _fromRow; row <= _toRow; row++) - { - _worksheet._formulas.SetValue(row, col, id); - } - } - } - private void CheckAndSplitSharedFormula(ExcelAddressBase address) - { - for (int col = address._fromCol; col <= address._toCol; col++) - { - for (int row = address._fromRow; row <= address._toRow; row++) - { - var f = _worksheet._formulas.GetValue(row, col); - if (f is int && (int)f >= 0) - { - SplitFormulas(address); - return; - } - } - } - } - - private void SplitFormulas(ExcelAddressBase address) - { - List<int> formulas = new List<int>(); - for (int col = address._fromCol; col <= address._toCol; col++) - { - for (int row = address._fromRow; row <= address._toRow; row++) - { - var f = _worksheet._formulas.GetValue(row, col); - if (f is int) - { - int id = (int)f; - if (id >= 0 && !formulas.Contains(id)) - { - if (_worksheet._sharedFormulas[id].IsArray && - Collide(_worksheet.Cells[_worksheet._sharedFormulas[id].Address]) == eAddressCollition.Partly) // If the formula is an array formula and its on the inside the overwriting range throw an exception - { - throw (new InvalidOperationException("Can not overwrite a part of an array-formula")); - } - formulas.Add(id); - } - } - } - } - - foreach (int ix in formulas) - { - SplitFormula(address, ix); - } - - ////Clear any formula references inside the refered range - //_worksheet._formulas.Clear(address._fromRow, address._toRow, address._toRow - address._fromRow + 1, address._toCol - address.column + 1); - } - - private void SplitFormula(ExcelAddressBase address, int ix) - { - var f = _worksheet._sharedFormulas[ix]; - var fRange = _worksheet.Cells[f.Address]; - var collide = address.Collide(fRange); - - //The formula is inside the currenct range, remove it - if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside) - { - _worksheet._sharedFormulas.Remove(ix); - return; - //fRange.SetSharedFormulaID(int.MinValue); - } - var firstCellCollide = address.Collide(new ExcelAddressBase(fRange._fromRow, fRange._fromCol, fRange._fromRow, fRange._fromCol)); - if (collide == eAddressCollition.Partly && (firstCellCollide == eAddressCollition.Inside || firstCellCollide == eAddressCollition.Equal)) //Do we need to split? Only if the functions first row is inside the new range. - { - //The formula partly collides with the current range - bool fIsSet = false; - string formulaR1C1 = fRange.FormulaR1C1; - //Top Range - if (fRange._fromRow < _fromRow) - { - f.Address = ExcelCellBase.GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol); - fIsSet = true; - } - //Left Range - if (fRange._fromCol < address._fromCol) - { - if (fIsSet) - { - f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default); - f.Index = _worksheet.GetMaxShareFunctionIndex(false); - f.StartCol = fRange._fromCol; - f.IsArray = false; - _worksheet._sharedFormulas.Add(f.Index, f); - } - else - { - fIsSet = true; - } - if (fRange._fromRow < address._fromRow) - f.StartRow = address._fromRow; - else - { - f.StartRow = fRange._fromRow; - } - if (fRange._toRow < address._toRow) - { - f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol, - fRange._toRow, address._fromCol - 1); - } - else - { - f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol, - address._toRow, address._fromCol - 1); - } - f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); - _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index); - } - //Right Range - if (fRange._toCol > address._toCol) - { - if (fIsSet) - { - f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default); - f.Index = _worksheet.GetMaxShareFunctionIndex(false); - f.IsArray = false; - _worksheet._sharedFormulas.Add(f.Index, f); - } - else - { - fIsSet = true; - } - f.StartCol = address._toCol + 1; - if (address._fromRow < fRange._fromRow) - f.StartRow = fRange._fromRow; - else - { - f.StartRow = address._fromRow; - } - - if (fRange._toRow < address._toRow) - { - f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol, - fRange._toRow, fRange._toCol); - } - else - { - f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol, - address._toRow, fRange._toCol); - } - f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); - _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index); - } - //Bottom Range - if (fRange._toRow > address._toRow) - { - if (fIsSet) - { - f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default); - f.Index = _worksheet.GetMaxShareFunctionIndex(false); - f.IsArray = false; - _worksheet._sharedFormulas.Add(f.Index, f); - } - - f.StartCol = fRange._fromCol; - f.StartRow = _toRow + 1; - - f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); - - f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol, - fRange._toRow, fRange._toCol); - _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index); - - } - } - } - private object ConvertData(ExcelTextFormat Format, string v, int col, bool isText) - { - if (isText && (Format.DataTypes == null || Format.DataTypes.Length < col)) return v; - - double d; - DateTime dt; - if (Format.DataTypes == null || Format.DataTypes.Length <= col || Format.DataTypes[col] == eDataTypes.Unknown) - { - string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; - if (double.TryParse(v2, NumberStyles.Any, Format.Culture, out d)) - { - if (v2 == v) - { - return d; - } - else - { - return d / 100; - } - } - if (DateTime.TryParse(v, Format.Culture, DateTimeStyles.None, out dt)) - { - return dt; - } - else - { - return v; - } - } - else - { - switch (Format.DataTypes[col]) - { - case eDataTypes.Number: - if (double.TryParse(v, NumberStyles.Any, Format.Culture, out d)) - { - return d; - } - else - { - return v; - } - case eDataTypes.DateTime: - if (DateTime.TryParse(v, Format.Culture, DateTimeStyles.None, out dt)) - { - return dt; - } - else - { - return v; - } - case eDataTypes.Percent: - string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; - if (double.TryParse(v2, NumberStyles.Any, Format.Culture, out d)) - { - return d / 100; - } - else - { - return v; - } - - default: - return v; - - } - } - } - #endregion - #region Public Methods - #region ConditionalFormatting - /// <summary> - /// Conditional Formatting for this range. - /// </summary> - public IRangeConditionalFormatting ConditionalFormatting - { - get - { - return new RangeConditionalFormatting(_worksheet, new ExcelAddress(Address)); - } - } - #endregion - #region DataValidation - /// <summary> - /// Data validation for this range. - /// </summary> - public IRangeDataValidation DataValidation - { - get - { - return new RangeDataValidation(_worksheet, Address); - } - } - #endregion - #region LoadFromDataReader - /// <summary> - /// Load the data from the datareader starting from the top left cell of the range - /// </summary> - /// <param name="Reader">The datareader to loadfrom</param> - /// <param name="PrintHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param> - /// <param name="TableName">The name of the table</param> - /// <param name="TableStyle">The table style to apply to the data</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromDataReader(IDataReader Reader, bool PrintHeaders, string TableName, TableStyles TableStyle = TableStyles.None) - { - var r = LoadFromDataReader(Reader, PrintHeaders); - - int rows = r.Rows - 1; - if (rows >= 0 && r.Columns > 0) - { - var tbl = _worksheet.Tables.Add(new ExcelAddressBase(_fromRow, _fromCol, _fromRow + (rows <= 0 ? 1 : rows), _fromCol + r.Columns - 1), TableName); - tbl.ShowHeader = PrintHeaders; - tbl.TableStyle = TableStyle; - } - return r; - } - - /// <summary> - /// Load the data from the datareader starting from the top left cell of the range - /// </summary> - /// <param name="Reader">The datareader to load from</param> - /// <param name="PrintHeaders">Print the caption property (if set) or the columnname property if not, on first row</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromDataReader(IDataReader Reader, bool PrintHeaders) - { - if (Reader == null) - { - throw (new ArgumentNullException("Reader", "Reader can't be null")); - } - int fieldCount = Reader.FieldCount; - - int col = _fromCol, row = _fromRow; - if (PrintHeaders) - { - for (int i = 0; i < fieldCount; i++) - { - // If no caption is set, the ColumnName property is called implicitly. - _worksheet._values.SetValue(row, col++, Reader.GetName(i)); - } - row++; - col = _fromCol; - } - while(Reader.Read()) - { - for (int i = 0; i < fieldCount; i++) - { - _worksheet._values.SetValue(row, col++, Reader.GetValue(i)); - } - row++; - col = _fromCol; - } - return _worksheet.Cells[_fromRow, _fromCol, row - 1, _fromCol + fieldCount - 1]; - } - #endregion - #region LoadFromDataTable - /// <summary> - /// Load the data from the datatable starting from the top left cell of the range - /// </summary> - /// <param name="Table">The datatable to load</param> - /// <param name="PrintHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param> - /// <param name="TableStyle">The table style to apply to the data</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromDataTable(DataTable Table, bool PrintHeaders, TableStyles TableStyle) - { - var r = LoadFromDataTable(Table, PrintHeaders); - - int rows = (Table.Rows.Count == 0 ? 1 : Table.Rows.Count) + (PrintHeaders ? 1 : 0); - if (rows >= 0 && Table.Columns.Count>0) - { - var tbl = _worksheet.Tables.Add(new ExcelAddressBase(_fromRow, _fromCol, _fromRow + rows - 1, _fromCol + Table.Columns.Count-1), Table.TableName); - tbl.ShowHeader = PrintHeaders; - tbl.TableStyle = TableStyle; - } - return r; - } - /// <summary> - /// Load the data from the datatable starting from the top left cell of the range - /// </summary> - /// <param name="Table">The datatable to load</param> - /// <param name="PrintHeaders">Print the caption property (if set) or the columnname property if not, on first row</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromDataTable(DataTable Table, bool PrintHeaders) - { - if (Table == null) - { - throw (new ArgumentNullException("Table can't be null")); - } - - int col = _fromCol, row = _fromRow; - if (PrintHeaders) - { - foreach (DataColumn dc in Table.Columns) - { - // If no caption is set, the ColumnName property is called implicitly. - _worksheet._values.SetValue(row, col++, dc.Caption); - } - row++; - col = _fromCol; - } - else if (Table.Rows.Count == 0) - { - return null; - } - foreach (DataRow dr in Table.Rows) - { - foreach (object value in dr.ItemArray) - { - if (value != null && value != DBNull.Value && !string.IsNullOrEmpty(value.ToString())) - { - _worksheet._values.SetValue(row, col++, value); - } - else - { - col++; - } - } - row++; - col = _fromCol; - } - return _worksheet.Cells[_fromRow, _fromCol, (row == _fromRow ? _fromRow : row - 1), _fromCol + Table.Columns.Count - 1]; - } - #endregion - #region LoadFromArrays - /// <summary> - /// Loads data from the collection of arrays of objects into the range, starting from - /// the top-left cell. - /// </summary> - /// <param name="Data">The data.</param> - public ExcelRangeBase LoadFromArrays(IEnumerable<object[]> Data) - { - //thanx to Abdullin for the code contribution - if (Data == null) throw new ArgumentNullException("data"); - - int column = _fromCol, row = _fromRow; - - foreach (var rowData in Data) - { - column = _fromCol; - foreach (var cellData in rowData) - { - _worksheet._values.SetValue(row, column, cellData); - column += 1; - } - row += 1; - } - return _worksheet.Cells[_fromRow, _fromCol, row - 1, column - 1]; - } - #endregion - #region LoadFromCollection - /// <summary> - /// Load a collection into a the worksheet starting from the top left row of the range. - /// </summary> - /// <typeparam name="T">The datatype in the collection</typeparam> - /// <param name="Collection">The collection to load</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection) - { - return LoadFromCollection<T>(Collection, false, TableStyles.None, BindingFlags.Public | BindingFlags.Instance, null); - } - /// <summary> - /// Load a collection of T into the worksheet starting from the top left row of the range. - /// Default option will load all public instance properties of T - /// </summary> - /// <typeparam name="T">The datatype in the collection</typeparam> - /// <param name="Collection">The collection to load</param> - /// <param name="PrintHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders) - { - return LoadFromCollection<T>(Collection, PrintHeaders, TableStyles.None, BindingFlags.Public | BindingFlags.Instance, null); - } - /// <summary> - /// Load a collection of T into the worksheet starting from the top left row of the range. - /// Default option will load all public instance properties of T - /// </summary> - /// <typeparam name="T">The datatype in the collection</typeparam> - /// <param name="Collection">The collection to load</param> - /// <param name="PrintHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> - /// <param name="TableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders, TableStyles TableStyle) - { - return LoadFromCollection<T>(Collection, PrintHeaders, TableStyle, BindingFlags.Public | BindingFlags.Instance, null); - } - /// <summary> - /// Load a collection into the worksheet starting from the top left row of the range. - /// </summary> - /// <typeparam name="T">The datatype in the collection</typeparam> - /// <param name="Collection">The collection to load</param> - /// <param name="PrintHeaders">Print the property names on the first row. Any underscore in the property name will be converted to a space. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> - /// <param name="TableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param> - /// <param name="memberFlags">Property flags to use</param> - /// <param name="Members">The properties to output. Must be of type T</param> - /// <returns>The filled range</returns> - public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders, TableStyles TableStyle, BindingFlags memberFlags, MemberInfo[] Members) - { - var type = typeof(T); - if (Members == null) - { - Members = type.GetProperties(memberFlags); - } - else - { - foreach (var t in Members) - { - if (t.DeclaringType!=null && t.DeclaringType != type && !t.DeclaringType.IsSubclassOf(type)) - { - throw new InvalidCastException("Supplied properties in parameter Properties must be of the same type as T (or an assignable type from T"); - } - } - } - - int col = _fromCol, row = _fromRow; - if (Members.Length > 0 && PrintHeaders) - { - foreach (var t in Members) - { - var descriptionAttribute = t.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute; - var header = string.Empty; - if (descriptionAttribute != null) - { - header = descriptionAttribute.Description; - } - else - { - var displayNameAttribute = - t.GetCustomAttributes(typeof (DisplayNameAttribute), false).FirstOrDefault() as - DisplayNameAttribute; - if (displayNameAttribute != null) - { - header = displayNameAttribute.DisplayName; - } - else - { - header = t.Name.Replace('_', ' '); - } - } - _worksheet._values.SetValue(row, col++, header); - } - row++; - } - - if (!Collection.Any() && (Members.Length == 0 || PrintHeaders == false)) - { - return null; - } - - if (Members.Length == 0) - { - foreach (var item in Collection) - { - _worksheet.Cells[row++, col].Value = item; - } - } - else - { - foreach (var item in Collection) - { - col = _fromCol; - if (item is string || item is decimal || item is DateTime || item.GetType().IsPrimitive) - { - _worksheet.Cells[row, col++].Value = item; - } - else - { - foreach (var t in Members) - { - if (t is PropertyInfo) - { - _worksheet.Cells[row, col++].Value = ((PropertyInfo)t).GetValue(item, null); - } - else if (t is FieldInfo) - { - _worksheet.Cells[row, col++].Value = ((FieldInfo)t).GetValue(item); - } - else if (t is MethodInfo) - { - _worksheet.Cells[row, col++].Value = ((MethodInfo)t).Invoke(item, null); - } - } - } - row++; - } - } - - if (_fromRow == row-1 && PrintHeaders) - { - row++; - } - - var r = _worksheet.Cells[_fromRow, _fromCol, row - 1, Members.Length==0 ? col : col - 1]; - - if (TableStyle != TableStyles.None) - { - var tbl = _worksheet.Tables.Add(r, ""); - tbl.ShowHeader = PrintHeaders; - tbl.TableStyle = TableStyle; - } - return r; - } - #endregion - #region LoadFromText - /// <summary> - /// Loads a CSV text into a range starting from the top left cell. - /// Default settings is Comma separation - /// </summary> - /// <param name="Text">The Text</param> - /// <returns>The range containing the data</returns> - public ExcelRangeBase LoadFromText(string Text) - { - return LoadFromText(Text, new ExcelTextFormat()); - } - /// <summary> - /// Loads a CSV text into a range starting from the top left cell. - /// </summary> - /// <param name="Text">The Text</param> - /// <param name="Format">Information how to load the text</param> - /// <returns>The range containing the data</returns> - public ExcelRangeBase LoadFromText(string Text, ExcelTextFormat Format) - { - if (string.IsNullOrEmpty(Text)) - { - var r = _worksheet.Cells[_fromRow, _fromCol]; - r.Value = ""; - return r; - } - - if (Format == null) Format = new ExcelTextFormat(); - - string splitRegex = String.Format("{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*[^{1}]*$)", Format.EOL, Format.TextQualifier); - string[] lines = Regex.Split(Text, splitRegex); - int row = _fromRow; - int col = _fromCol; - int maxCol = col; - int lineNo = 1; - foreach (string line in lines) - { - if (lineNo > Format.SkipLinesBeginning && lineNo <= lines.Length - Format.SkipLinesEnd) - { - col = _fromCol; - string v = ""; - bool isText = false, isQualifier = false; - int QCount = 0; - int lineQCount = 0; - foreach (char c in line) - { - if (Format.TextQualifier != 0 && c == Format.TextQualifier) - { - if (!isText && v != "") - { - throw (new Exception(string.Format("Invalid Text Qualifier in line : {0}", line))); - } - isQualifier = !isQualifier; - QCount += 1; - lineQCount++; - isText = true; - } - else - { - if (QCount > 1 && !string.IsNullOrEmpty(v)) - { - v += new string(Format.TextQualifier, QCount / 2); - } - else if (QCount > 2 && string.IsNullOrEmpty(v)) - { - v += new string(Format.TextQualifier, (QCount - 1) / 2); - } - - if (isQualifier) - { - v += c; - } - else - { - if (c == Format.Delimiter) - { - _worksheet.SetValue(row, col, ConvertData(Format, v, col - _fromCol, isText)); - v = ""; - isText = false; - col++; - } - else - { - if (QCount % 2 == 1) - { - throw (new Exception(string.Format("Text delimiter is not closed in line : {0}", line))); - } - v += c; - } - } - QCount = 0; - } - } - if (QCount > 1) - { - v += new string(Format.TextQualifier, QCount / 2); - } - if (lineQCount % 2 == 1) - throw (new Exception(string.Format("Text delimiter is not closed in line : {0}", line))); - - _worksheet._values.SetValue(row, col, ConvertData(Format, v, col - _fromCol, isText)); - if (col > maxCol) maxCol = col; - row++; - } - lineNo++; - } - return _worksheet.Cells[_fromRow, _fromCol, row - 1, maxCol]; - } - /// <summary> - /// Loads a CSV text into a range starting from the top left cell. - /// </summary> - /// <param name="Text">The Text</param> - /// <param name="Format">Information how to load the text</param> - /// <param name="TableStyle">Create a table with this style</param> - /// <param name="FirstRowIsHeader">Use the first row as header</param> - /// <returns></returns> - public ExcelRangeBase LoadFromText(string Text, ExcelTextFormat Format, TableStyles TableStyle, bool FirstRowIsHeader) - { - var r = LoadFromText(Text, Format); - - var tbl = _worksheet.Tables.Add(r, ""); - tbl.ShowHeader = FirstRowIsHeader; - tbl.TableStyle = TableStyle; - - return r; - } - /// <summary> - /// Loads a CSV file into a range starting from the top left cell. - /// </summary> - /// <param name="TextFile">The Textfile</param> - /// <returns></returns> - public ExcelRangeBase LoadFromText(FileInfo TextFile) - { - return LoadFromText(File.ReadAllText(TextFile.FullName, Encoding.ASCII)); - } - /// <summary> - /// Loads a CSV file into a range starting from the top left cell. - /// </summary> - /// <param name="TextFile">The Textfile</param> - /// <param name="Format">Information how to load the text</param> - /// <returns></returns> - public ExcelRangeBase LoadFromText(FileInfo TextFile, ExcelTextFormat Format) - { - return LoadFromText(File.ReadAllText(TextFile.FullName, Format.Encoding), Format); - } - /// <summary> - /// Loads a CSV file into a range starting from the top left cell. - /// </summary> - /// <param name="TextFile">The Textfile</param> - /// <param name="Format">Information how to load the text</param> - /// <param name="TableStyle">Create a table with this style</param> - /// <param name="FirstRowIsHeader">Use the first row as header</param> - /// <returns></returns> - public ExcelRangeBase LoadFromText(FileInfo TextFile, ExcelTextFormat Format, TableStyles TableStyle, bool FirstRowIsHeader) - { - return LoadFromText(File.ReadAllText(TextFile.FullName, Format.Encoding), Format, TableStyle, FirstRowIsHeader); - } - #endregion - #region GetValue - /// <summary> - /// Get the strongly typed value of the cell. - /// </summary> - /// <typeparam name="T">The type</typeparam> - /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns> - public T GetValue<T>() - { - return _worksheet.GetTypedValue<T>(Value); - } - #endregion - /// <summary> - /// Get a range with an offset from the top left cell. - /// The new range has the same dimensions as the current range - /// </summary> - /// <param name="RowOffset">Row Offset</param> - /// <param name="ColumnOffset">Column Offset</param> - /// <returns></returns> - public ExcelRangeBase Offset(int RowOffset, int ColumnOffset) - { - if (_fromRow + RowOffset < 1 || _fromCol + ColumnOffset < 1 || _fromRow + RowOffset > ExcelPackage.MaxRows || _fromCol + ColumnOffset > ExcelPackage.MaxColumns) - { - throw (new ArgumentOutOfRangeException("Offset value out of range")); - } - string address = GetAddress(_fromRow + RowOffset, _fromCol + ColumnOffset, _toRow + RowOffset, _toCol + ColumnOffset); - return new ExcelRangeBase(_worksheet, address); - } - /// <summary> - /// Get a range with an offset from the top left cell. - /// </summary> - /// <param name="RowOffset">Row Offset</param> - /// <param name="ColumnOffset">Column Offset</param> - /// <param name="NumberOfRows">Number of rows. Minimum 1</param> - /// <param name="NumberOfColumns">Number of colums. Minimum 1</param> - /// <returns></returns> - public ExcelRangeBase Offset(int RowOffset, int ColumnOffset, int NumberOfRows, int NumberOfColumns) - { - if (NumberOfRows < 1 || NumberOfColumns < 1) - { - throw (new Exception("Number of rows/columns must be greater than 0")); - } - NumberOfRows--; - NumberOfColumns--; - if (_fromRow + RowOffset < 1 || _fromCol + ColumnOffset < 1 || _fromRow + RowOffset > ExcelPackage.MaxRows || _fromCol + ColumnOffset > ExcelPackage.MaxColumns || - _fromRow + RowOffset + NumberOfRows < 1 || _fromCol + ColumnOffset + NumberOfColumns < 1 || _fromRow + RowOffset + NumberOfRows > ExcelPackage.MaxRows || _fromCol + ColumnOffset + NumberOfColumns > ExcelPackage.MaxColumns) - { - throw (new ArgumentOutOfRangeException("Offset value out of range")); - } - string address = GetAddress(_fromRow + RowOffset, _fromCol + ColumnOffset, _fromRow + RowOffset + NumberOfRows, _fromCol + ColumnOffset + NumberOfColumns); - return new ExcelRangeBase(_worksheet, address); - } - /// <summary> - /// Adds a new comment for the range. - /// If this range contains more than one cell, the top left comment is returned by the method. - /// </summary> - /// <param name="Text"></param> - /// <param name="Author"></param> - /// <returns>A reference comment of the top left cell</returns> - public ExcelComment AddComment(string Text, string Author) - { - if (string.IsNullOrEmpty(Author)) - { - Author = Thread.CurrentPrincipal.Identity.Name; - } - //Check if any comments exists in the range and throw an exception - _changePropMethod(Exists_Comment, null); - //Create the comments - _changePropMethod(Set_Comment, new string[] { Text, Author }); - - return _worksheet.Comments[new ExcelCellAddress(_fromRow, _fromCol)]; - } - - ///// <summary> - ///// Copies the range of cells to an other range - ///// </summary> - ///// <param name="Destination">The start cell where the range will be copied.</param> - public void Copy(ExcelRangeBase Destination) - { - bool sameWorkbook = Destination._worksheet.Workbook == _worksheet.Workbook; - ExcelStyles sourceStyles = _worksheet.Workbook.Styles, - styles = Destination._worksheet.Workbook.Styles; - Dictionary<int, int> styleCashe = new Dictionary<int, int>(); - - //Clear all existing cells; - int toRow = _toRow - _fromRow + 1, - toCol = _toCol - _fromCol + 1; - - string s = ""; - int i=0; - object o = null; - byte flag=0; - Uri hl = null; - ExcelComment comment=null; - - var cse = new CellsStoreEnumerator<object>(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol); - var copiedValue = new List<CopiedCell>(); - while (cse.Next()) - { - var row=cse.Row; - var col = cse.Column; //Issue 15070 - var cell = new CopiedCell - { - Row = Destination._fromRow + (row - _fromRow), - Column = Destination._fromCol + (col - _fromCol), - Value=cse.Value - }; - - //Destination._worksheet._values.SetValue(row, col, cse.Value); - - if (_worksheet._types.Exists(row, col, ref s)) - { - //Destination._worksheet._types.SetValue(row, col,s); - cell.Type=s; - } - - if (_worksheet._formulas.Exists(row, col, ref o)) - { - if (o is int) - { - // Destination._worksheet._formulas.SetValue(row, col, _worksheet.GetFormula(cse.Row, cse.Column)); //Shared formulas, set the formula per cell to simplify - cell.Formula=_worksheet.GetFormula(cse.Row, cse.Column); - } - else - { - //Destination._worksheet._formulas.SetValue(row, col, o); - cell.Formula=o; - } - } - if(_worksheet._styles.Exists(row, col, ref i)) - { - if (sameWorkbook) - { - //Destination._worksheet._styles.SetValue(row, col, i); - cell.StyleID=i; - } - else - { - if (styleCashe.ContainsKey(i)) - { - i = styleCashe[i]; - } - else - { - var oldStyleID = i; - i = styles.CloneStyle(sourceStyles, i); - styleCashe.Add(oldStyleID, i); - } - //Destination._worksheet._styles.SetValue(row, col, i); - cell.StyleID=i; - } - } - - if (_worksheet._hyperLinks.Exists(row, col, ref hl)) - { - //Destination._worksheet._hyperLinks.SetValue(row, col, hl); - cell.HyperLink=hl; - } - - if(_worksheet._commentsStore.Exists(row, col, ref comment)) - { - cell.Comment=comment; - } - - if (_worksheet._flags.Exists(row, col, ref flag)) - { - cell.Flag = flag; - } - copiedValue.Add(cell); - } - - //Copy styles with no cell value - var cses = new CellsStoreEnumerator<int>(_worksheet._styles, _fromRow, _fromCol, _toRow, _toCol); - while (cses.Next()) - { - if (!_worksheet._values.Exists(cses.Row, cses.Column)) - { - var row = Destination._fromRow + (cses.Row - _fromRow); - var col = Destination._fromCol + (cses.Column - _fromCol); - var cell = new CopiedCell - { - Row = row, - Column = col, - Value = null - }; - - i = cses.Value; - if (sameWorkbook) - { - cell.StyleID = i; - } - else - { - if (styleCashe.ContainsKey(i)) - { - i = styleCashe[i]; - } - else - { - var oldStyleID = i; - i = styles.CloneStyle(sourceStyles, i); - styleCashe.Add(oldStyleID, i); - } - //Destination._worksheet._styles.SetValue(row, col, i); - cell.StyleID = i; - } - copiedValue.Add(cell); - } - } - var copiedMergedCells = new Dictionary<int, ExcelAddress>(); - //Merged cells - var csem = new CellsStoreEnumerator<int>(_worksheet.MergedCells._cells, _fromRow, _fromCol, _toRow, _toCol); - while (csem.Next()) - { - if(!copiedMergedCells.ContainsKey(csem.Value)) - { - var adr = new ExcelAddress(_worksheet.Name, _worksheet.MergedCells.List[csem.Value]); - if(this.Collide(adr)==eAddressCollition.Inside) - { - copiedMergedCells.Add(csem.Value, new ExcelAddress( - Destination._fromRow + (adr.Start.Row - _fromRow), - Destination._fromCol + (adr.Start.Column - _fromCol), - Destination._fromRow + (adr.End.Row - _fromRow), - Destination._fromCol + (adr.End.Column - _fromCol))); - } - else - { - //Partial merge of the address ignore. - copiedMergedCells.Add(csem.Value, null); - } - } - } - - Destination._worksheet.MergedCells.Clear(new ExcelAddressBase(Destination._fromRow, Destination._fromCol, Destination._fromRow+toRow-1, Destination._fromCol+toCol-1)); - - Destination._worksheet._values.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol); - Destination._worksheet._formulas.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol); - Destination._worksheet._styles.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol); - Destination._worksheet._types.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol); - Destination._worksheet._hyperLinks.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol); - Destination._worksheet._flags.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol); - Destination._worksheet._commentsStore.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol); - - foreach(var cell in copiedValue) - { - Destination._worksheet._values.SetValue(cell.Row, cell.Column, cell.Value); - - if(cell.Type!=null) - { - Destination._worksheet._types.SetValue(cell.Row, cell.Column, cell.Type); - } - - if(cell.StyleID!=null) - { - Destination._worksheet._styles.SetValue(cell.Row, cell.Column, cell.StyleID.Value); - } - - if(cell.Formula!=null) - { - cell.Formula = UpdateFormulaReferences(cell.Formula.ToString(), Destination._fromRow - _fromRow, Destination._fromCol - _fromCol, 0, 0, true); - Destination._worksheet._formulas.SetValue(cell.Row, cell.Column, cell.Formula); - } - if(cell.HyperLink!=null) - { - Destination._worksheet._hyperLinks.SetValue(cell.Row, cell.Column, cell.HyperLink); - } - - if (cell.Comment != null) - { - //Destination._worksheet._commentsStore.SetValue(cell.Row, cell.Column, cell.Comment); - } - if (cell.Flag != 0) - { - Destination._worksheet._flags.SetValue(cell.Row, cell.Column, cell.Flag); - } - } - - //Add merged cells - foreach(var m in copiedMergedCells.Values) - { - if(m!=null) - { - Destination._worksheet.MergedCells.Add(m, true); - } - } - - - //Clone the cell - //var copiedCell = (_worksheet._cells[GetCellID(_worksheet.SheetID, cell._fromRow, cell.column)] as ExcelCell); - - //var newCell = copiedCell.Clone(Destination._worksheet, - // Destination._fromRow + (copiedCell.Row - _fromRow), - // Destination.column + (copiedCell.Column - column)); - - // newCell.MergeId = _worksheet.GetMergeCellId(copiedCell.Row, copiedCell.Column); - - - // if (!string.IsNullOrEmpty(newCell.Formula)) - // { - // newCell.Formula = ExcelCell.UpdateFormulaReferences(newCell.Formula, newCell.Row - copiedCell.Row, (newCell.Column - copiedCell.Column), 1, 1); - // } - - // //If its not the same workbook we must copy the styles to the new workbook. - // if (!sameWorkbook) - // { - // if (styleCashe.ContainsKey(cell.StyleID)) - // { - // newCell.StyleID = styleCashe[cell.StyleID]; - // } - // else - // { - // newCell.StyleID = styles.CloneStyle(sourceStyles, cell.StyleID); - // styleCashe.Add(cell.StyleID, newCell.StyleID); - // } - // } - // newCells.Add(newCell); - // if (newCell.Merge) mergedCells.Add(newCell.CellID, newCell); - // } - - // //Now clear the destination. - // Destination.Offset(0, 0, (_toRow - _fromRow) + 1, (_toCol - column) + 1).Clear(); - - // //And last add the new cells to the worksheet - // foreach (var cell in newCells) - // { - // Destination.Worksheet._cells.Add(cell); - // } - // //Add merged cells - // if (mergedCells.Count > 0) - // { - // List<ExcelAddressBase> mergedAddresses = new List<ExcelAddressBase>(); - // foreach (var cell in mergedCells.Values) - // { - // if (!IsAdded(cell, mergedAddresses)) - // { - // int startRow = cell.Row, startCol = cell.Column, endRow = cell.Row, endCol = cell.Column + 1; - // while (mergedCells.ContainsKey(ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol))) - // { - // ExcelCell next = mergedCells[ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)]; - // if (cell.MergeId != next.MergeId) - // { - // break; - // } - // endCol++; - // } - - // while (IsMerged(mergedCells, Destination.Worksheet, endRow, startCol, endCol - 1, cell)) - // { - // endRow++; - // } - - // mergedAddresses.Add(new ExcelAddressBase(startRow, startCol, endRow - 1, endCol - 1)); - // } - // } - // Destination.Worksheet.MergedCells.List.AddRange((from r in mergedAddresses select r.Address)); - // } - //} - - //private bool IsAdded(ExcelCell cell, List<ExcelAddressBase> mergedAddresses) - //{ - // foreach (var address in mergedAddresses) - // { - // if (address.Collide(new ExcelAddressBase(cell.CellAddress)) == eAddressCollition.Inside) - // { - // return true; - // } - // } - // return false; - //} - - //private bool IsMerged(Dictionary<ulong, ExcelCell> mergedCells, ExcelWorksheet worksheet, int row, int startCol, int endCol, ExcelCell cell) - //{ - // for (int col = startCol; col <= endCol; col++) - // { - // if (!mergedCells.ContainsKey(ExcelCell.GetCellID(worksheet.SheetID, row, col))) - // { - // return false; - // } - // else - // { - // ExcelCell next = mergedCells[ExcelCell.GetCellID(worksheet.SheetID, row, col)]; - // if (cell.MergeId != next.MergeId) - // { - // return false; - // } - // } - // } - // return true; - } - - /// <summary> - /// Clear all cells - /// </summary> - public void Clear() - { - Delete(this, false); - } - /// <summary> - /// Creates an array-formula. - /// </summary> - /// <param name="ArrayFormula">The formula</param> - public void CreateArrayFormula(string ArrayFormula) - { - if (Addresses != null) - { - throw (new Exception("An Arrayformula can not have more than one address")); - } - Set_SharedFormula(ArrayFormula, this, true); - } - //private void Clear(ExcelAddressBase Range) - //{ - // Clear(Range, true); - //} - internal void Delete(ExcelAddressBase Range, bool shift) - { - //DeleteCheckMergedCells(Range); - _worksheet.MergedCells.Clear(Range); - //First find the start cell - int fromRow, fromCol; - var d = Worksheet.Dimension; - if (d != null && Range._fromRow <= d._fromRow && Range._toRow >= d._toRow) //EntireRow? - { - fromRow = 0; - } - else - { - fromRow = Range._fromRow; - } - if (d != null && Range._fromCol <= d._fromCol && Range._toCol >= d._toCol) //EntireRow? - { - fromCol = 0; - } - else - { - fromCol = Range._fromCol; - } - - var rows = Range._toRow - fromRow + 1; - var cols = Range._toCol - fromCol + 1; - - _worksheet._values.Delete(fromRow, fromCol, rows, cols, shift); - _worksheet._types.Delete(fromRow, fromCol, rows, cols, shift); - _worksheet._styles.Delete(fromRow, fromCol, rows, cols, shift); - _worksheet._formulas.Delete(fromRow, fromCol, rows, cols, shift); - _worksheet._hyperLinks.Delete(fromRow, fromCol, rows, cols, shift); - _worksheet._flags.Delete(fromRow, fromCol, rows, cols, shift); - _worksheet._commentsStore.Delete(fromRow, fromCol, rows, cols, shift); - - //if(shift) - //{ - // _worksheet.AdjustFormulasRow(fromRow, rows); - //} - - //Clear multi addresses as well - if (Addresses != null) - { - foreach (var sub in Addresses) - { - Delete(sub, shift); - } - } - } - - private void DeleteCheckMergedCells(ExcelAddressBase Range) - { - var removeItems = new List<string>(); - foreach (var addr in Worksheet.MergedCells) - { - var addrCol = Range.Collide(new ExcelAddress(Range.WorkSheet, addr)); - if (addrCol != eAddressCollition.No) - { - if (addrCol == eAddressCollition.Inside) - { - removeItems.Add(addr); - } - else - { - throw (new InvalidOperationException("Can't remove/overwrite a part of cells that are merged")); - } - } - } - foreach (var item in removeItems) - { - Worksheet.MergedCells.Remove(item); - } - } - #endregion - #region IDisposable Members - - public void Dispose() - { - } - - #endregion - #region "Enumerator" - //int _index; - //ulong _toCellId; - //int _enumAddressIx; - CellsStoreEnumerator<object> cellEnum; - public IEnumerator<ExcelRangeBase> GetEnumerator() - { - Reset(); - return this; - } - - IEnumerator IEnumerable.GetEnumerator() - { - Reset(); - return this; - } - - /// <summary> - /// The current range when enumerating - /// </summary> - public ExcelRangeBase Current - { - get - { - return new ExcelRangeBase(_worksheet, ExcelAddressBase.GetAddress(cellEnum.Row, cellEnum.Column)); - } - } - - /// <summary> - /// The current range when enumerating - /// </summary> - object IEnumerator.Current - { - get - { - return ((object)(new ExcelRangeBase(_worksheet, ExcelAddressBase.GetAddress(cellEnum.Row, cellEnum.Column)))); - } - } - - int _enumAddressIx = -1; - public bool MoveNext() - { - if (cellEnum.Next()) - { - return true; - } - else if (_addresses!=null) - { - _enumAddressIx++; - if (_enumAddressIx < _addresses.Count) - { - cellEnum = new CellsStoreEnumerator<object>(_worksheet._values, - _addresses[_enumAddressIx]._fromRow, - _addresses[_enumAddressIx]._fromCol, - _addresses[_enumAddressIx]._toRow, - _addresses[_enumAddressIx]._toCol); - return MoveNext(); - } - else - { - return false; - } - } - return false; - } - - public void Reset() - { - _enumAddressIx = -1; - cellEnum = new CellsStoreEnumerator<object>(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol); - } - - //private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol) - //{ - // if (_index >= _worksheet._cells.Count) return; - // ExcelCell cell = _worksheet._cells[_index] as ExcelCell; - // while (cell.Column > toCol || cell.Column < fromCol) - // { - // if (cell.Column < fromCol) - // { - // _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol)); - // } - // else - // { - // _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol)); - // } - - // if (_index < 0) - // { - // _index = ~_index; - // } - // if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId) - // { - // break; - // } - // cell = _worksheet._cells[_index] as ExcelCell; - // } - //} - - //private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol) - //{ - // _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol)); - // _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol); - // if (_index < 0) - // { - // _index = ~_index; - // } - // _index--; - //} - #endregion + private void ExcelRangeBase_AddressChange(object sender, EventArgs e) { + if (Table != null) { + SetRcFromTable(_workbook._package, null); } + SetDelegate(); + } + + internal ExcelRangeBase(ExcelWorksheet xlWorksheet, string address) + : base(xlWorksheet == null ? "" : xlWorksheet.Name, address) { + _worksheet = xlWorksheet; + _workbook = _worksheet.Workbook; + SetRcFromTable(_worksheet._package, null); + if (string.IsNullOrEmpty(_ws)) { + _ws = _worksheet == null ? "" : _worksheet.Name; + } + AddressChange += ExcelRangeBase_AddressChange; + SetDelegate(); + } + + internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName) + : base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName) { + SetRcFromTable(wb._package, null); + _worksheet = xlWorksheet; + _workbook = wb; + if (string.IsNullOrEmpty(_ws)) { + _ws = (xlWorksheet == null ? null : xlWorksheet.Name); + } + AddressChange += ExcelRangeBase_AddressChange; + SetDelegate(); + } + + ~ExcelRangeBase() { + //this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange); + } + + private void SetDelegate() { + if (_fromRow == -1) { + _changePropMethod = SetUnknown; + } + //Single cell + else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null) { + _changePropMethod = SetSingle; + } + //Range (ex A1:A2) + else if (Addresses == null) { + _changePropMethod = SetRange; + } + //Multi Range (ex A1:A2,C1:C2) + else { + _changePropMethod = SetMultiRange; + } + } + + /// <summary> + /// We dont know the address yet. Set the delegate first time a property is set. + /// </summary> + /// <param name="valueMethod"></param> + /// <param name="value"></param> + private void SetUnknown(SetValueHandler valueMethod, object value) { + //Address is not set use, selected range + if (_fromRow == -1) { + SetToSelectedRange(); + } + SetDelegate(); + _changePropMethod(valueMethod, value); + } + + /// <summary> + /// Set a single cell + /// </summary> + /// <param name="valueMethod"></param> + /// <param name="value"></param> + private void SetSingle(SetValueHandler valueMethod, object value) { + valueMethod(value, _fromRow, _fromCol); + } + + /// <summary> + /// Set a range + /// </summary> + /// <param name="valueMethod"></param> + /// <param name="value"></param> + private void SetRange(SetValueHandler valueMethod, object value) { + SetValueAddress(this, valueMethod, value); + } + + /// <summary> + /// Set a multirange (A1:A2,C1:C2) + /// </summary> + /// <param name="valueMethod"></param> + /// <param name="value"></param> + private void SetMultiRange(SetValueHandler valueMethod, object value) { + SetValueAddress(this, valueMethod, value); + foreach (var address in Addresses) { + SetValueAddress(address, valueMethod, value); + } + } + + /// <summary> + /// Set the property for an address + /// </summary> + /// <param name="address"></param> + /// <param name="valueMethod"></param> + /// <param name="value"></param> + private void SetValueAddress(ExcelAddress address, SetValueHandler valueMethod, object value) { + IsRangeValid(""); + if (_fromRow == 1 + && _fromCol == 1 + && _toRow == ExcelPackage.MaxRows + && _toCol + == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging + { + throw (new ArgumentException( + "Can't reference all cells. Please use the indexer to set the range")); + } + for (int col = address.Start.Column; col <= address.End.Column; col++) { + for (int row = address.Start.Row; row <= address.End.Row; row++) { + valueMethod(value, row, col); + } + } + } + + private void Set_StyleID(object value, int row, int col) { + _worksheet._styles.SetValue(row, col, (int)value); + } + + private void Set_StyleName(object value, int row, int col) { + //_worksheet.Cell(row, col).SetNewStyleName(value.ToString(), _styleID); + _worksheet._styles.SetValue(row, col, _styleID); + } + + private void Set_Value(object value, int row, int col) { + //ExcelCell c = _worksheet.Cell(row, col); + var sfi = _worksheet._formulas.GetValue(row, col); + if (sfi is int) { + SplitFormulas(_worksheet.Cells[row, col]); + } + if (sfi != null) { + _worksheet._formulas.SetValue(row, col, string.Empty); + } + _worksheet._values.SetValue(row, col, value); + } + + private void Set_Formula(object value, int row, int col) { + //ExcelCell c = _worksheet.Cell(row, col); + var f = _worksheet._formulas.GetValue(row, col); + if (f is int && (int)f >= 0) { + SplitFormulas(_worksheet.Cells[row, col]); + } + + string formula = (value == null ? string.Empty : value.ToString()); + if (formula == string.Empty) { + _worksheet._formulas.SetValue(row, col, string.Empty); + } else { + if (formula[0] == '=') { + value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign. + } + _worksheet._formulas.SetValue(row, col, formula); + _worksheet._values.SetValue(row, col, null); + } + } + + /// <summary> + /// Handles shared formulas + /// </summary> + /// <param name="value">The formula</param> + /// <param name="address">The address of the formula</param> + /// <param name="isArray">If the forumla is an array formula.</param> + private void Set_SharedFormula(string value, ExcelAddress address, bool isArray) { + if (_fromRow == 1 + && _fromCol == 1 + && _toRow == ExcelPackage.MaxRows + && _toCol + == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging + { + throw (new InvalidOperationException("Can't set a formula for the entire worksheet")); + } + if (address.Start.Row == address.End.Row + && address.Start.Column == address.End.Column + && !isArray) //is it really a shared formula? Arrayformulas can be one cell only + { + //Nope, single cell. Set the formula + Set_Formula(value, address.Start.Row, address.Start.Column); + return; + } + //RemoveFormuls(address); + CheckAndSplitSharedFormula(address); + ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default); + f.Formula = value; + f.Index = _worksheet.GetMaxShareFunctionIndex(isArray); + f.Address = address.FirstAddress; + f.StartCol = address.Start.Column; + f.StartRow = address.Start.Row; + f.IsArray = isArray; + + _worksheet._sharedFormulas.Add(f.Index, f); + //_worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index; + //_worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value; + + for (int col = address.Start.Column; col <= address.End.Column; col++) { + for (int row = address.Start.Row; row <= address.End.Row; row++) { + //_worksheet.Cell(row, col).SharedFormulaID = f.Index; + _worksheet._formulas.SetValue(row, col, f.Index); + _worksheet._values.SetValue(row, col, null); + } + } + } + + private void Set_HyperLink(object value, int row, int col) { + //_worksheet.Cell(row, col).Hyperlink = value as Uri; + if (value is Uri) { + _worksheet._hyperLinks.SetValue(row, col, (Uri)value); + + if (value is ExcelHyperLink) { + _worksheet._values.SetValue(row, col, ((ExcelHyperLink)value).Display); + } else { + _worksheet._values.SetValue(row, col, ((Uri)value).OriginalString); + } + } else { + _worksheet._hyperLinks.SetValue(row, col, null); + _worksheet._values.SetValue(row, col, null); + } + } + + private void Set_IsArrayFormula(object value, int row, int col) { + _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.ArrayFormula); + } + + private void Set_IsRichText(object value, int row, int col) { + //_worksheet.Cell(row, col).IsRichText = (bool)value; + _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.RichText); + } + + private void Exists_Comment(object value, int row, int col) { + ulong cellId = GetCellId(_worksheet.SheetID, row, col); + if (_worksheet.Comments._comments.ContainsKey(cellId)) { + throw (new InvalidOperationException( + string.Format( + "Cell {0} already contain a comment.", + new ExcelCellAddress(row, col).Address))); + } + } + + private void Set_Comment(object value, int row, int col) { + string[] v = (string[])value; + Worksheet.Comments.Add(new(_worksheet, GetAddress(_fromRow, _fromCol)), v[0], v[1]); + // _worksheet.Cell(row, col).Comment = comment; + } + + private void SetToSelectedRange() { + if (_worksheet.View.SelectedRange == "") { + Address = "A1"; + } else { + Address = _worksheet.View.SelectedRange; + } + } + + private void IsRangeValid(string type) { + if (_fromRow <= 0) { + if (_address == "") { + SetToSelectedRange(); + } else { + if (type == "") { + throw (new InvalidOperationException( + string.Format("Range is not valid for this operation: {0}", _address))); + } + throw (new InvalidOperationException( + string.Format("Range is not valid for {0} : {1}", type, _address))); + } + } + } + + /// <summary> + /// The styleobject for the range. + /// </summary> + public ExcelStyle Style { + get { + IsRangeValid("styling"); + int s = 0; + if (!_worksheet._styles.Exists( + _fromRow, + _fromCol, + ref s)) //Cell exists + { + if (!_worksheet._styles.Exists( + _fromRow, + 0, + ref s)) //No, check Row style + { + var c = Worksheet.GetColumn(_fromCol); + if (c == null) { + s = 0; + } else { + s = c.StyleID; + } + } + } + return _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, Address); + } + } + + /// <summary> + /// The named style + /// </summary> + public string StyleName { + get { + IsRangeValid("styling"); + int xfId; + if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows) { + xfId = GetColumnStyle(_fromCol); + } else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) { + xfId = 0; + if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) { + xfId = GetColumnStyle(_fromCol); + } + } else { + xfId = 0; + if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref xfId)) { + if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) { + xfId = GetColumnStyle(_fromCol); + } + } + } + int nsId; + if (xfId <= 0) { + nsId = Style.Styles.CellXfs[0].XfId; + } else { + nsId = Style.Styles.CellXfs[xfId].XfId; + } + foreach (var ns in Style.Styles.NamedStyles) { + if (ns.StyleXfId == nsId) { + return ns.Name; + } + } + + return ""; + } + set { + _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); + int col = _fromCol; + if (_fromRow == 1 + && _toRow + == ExcelPackage.MaxRows) //Full column + { + ExcelColumn column; + //Get the startcolumn + //ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, column); + var c = _worksheet.GetValue(0, _fromCol); + if (c == null) { + column = _worksheet.Column(_fromCol); + //if (_worksheet._values.PrevCell(ref row, ref col)) + //{ + // var prevCol = (ExcelColumn)_worksheet._values.GetValue(row, col); + // column = prevCol.Clone(_worksheet, column); + // prevCol.ColumnMax = column - 1; + //} + } else { + column = (ExcelColumn)c; + } + + column.StyleName = value; + column.StyleID = _styleID; + + //var index = _worksheet._columns.IndexOf(colID); + var cols = new CellsStoreEnumerator<object>(_worksheet._values, 0, _fromCol + 1, 0, _toCol); + if (cols.Next()) { + col = _fromCol; + while (column.ColumnMin <= _toCol) { + if (column.ColumnMax > _toCol) { + var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax); + column.ColumnMax = _toCol; + } + + column._styleName = value; + column.StyleID = _styleID; + + if (cols.Value == null) { + break; + } + var nextCol = (ExcelColumn)cols.Value; + if (column.ColumnMax < nextCol.ColumnMax - 1) { + column.ColumnMax = nextCol.ColumnMax - 1; + } + column = nextCol; + cols.Next(); + } + } + if (column.ColumnMax < _toCol) { + column.ColumnMax = _toCol; + } + //if (column.ColumnMin == column) + //{ + // column.ColumnMax = _toCol; + //} + //else if (column._columnMax < _toCol) + //{ + // var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn; + // newCol._columnMax = _toCol; + + // newCol._styleID = _styleID; + // newCol._styleName = value; + //} + if (_fromCol == 1 + && _toCol + == ExcelPackage.MaxColumns) //FullRow + { + var rows = new CellsStoreEnumerator<object>( + _worksheet._values, + 1, + 0, + ExcelPackage.MaxRows, + 0); + rows.Next(); + while (rows.Value != null) { + _worksheet._styles.SetValue(rows.Row, 0, _styleID); + if (!rows.Next()) { + break; + } + } + } + } else if (_fromCol == 1 + && _toCol + == ExcelPackage.MaxColumns) //FullRow + { + for (int r = _fromRow; r <= _toRow; r++) { + _worksheet.Row(r)._styleName = value; + _worksheet.Row(r).StyleID = _styleID; + } + } + + if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows) + || (_fromCol == 1 + && _toCol + == ExcelPackage.MaxColumns))) //Cell specific + { + for (int c = _fromCol; c <= _toCol; c++) { + for (int r = _fromRow; r <= _toRow; r++) { + _worksheet._styles.SetValue(r, c, _styleID); + } + } + } else //Only set name on created cells. (uncreated cells is set on full row or full column). + { + var cells = new CellsStoreEnumerator<object>( + _worksheet._values, + _fromRow, + _fromCol, + _toRow, + _toCol); + while (cells.Next()) { + _worksheet._styles.SetValue(cells.Row, cells.Column, _styleID); + } + } + //_changePropMethod(Set_StyleName, value); + } + } + + private int GetColumnStyle(int col) { + object c = null; + if (_worksheet._values.Exists(0, col, ref c)) { + return (c as ExcelColumn).StyleID; + } + int row = 0; + if (_worksheet._values.PrevCell(ref row, ref col)) { + var column = _worksheet._values.GetValue(row, col) as ExcelColumn; + if (column.ColumnMax >= col) { + return _worksheet._styles.GetValue(row, col); + } + } + return 0; + } + + /// <summary> + /// The style ID. + /// It is not recomended to use this one. Use Named styles as an alternative. + /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook. + /// </summary> + public int StyleID { + get { + int s = 0; + if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref s)) { + if (!_worksheet._styles.Exists(_fromRow, 0, ref s)) { + s = _worksheet._styles.GetValue(0, _fromCol); + } + } + return s; + } + set => _changePropMethod(Set_StyleID, value); + } + + /// <summary> + /// Set the range to a specific value + /// </summary> + public object Value { + get { + if (IsName) { + if (_worksheet == null) { + return _workbook._names[_address].NameValue; + } + return _worksheet.Names[_address].NameValue; + } + if (_fromRow == _toRow && _fromCol == _toCol) { + return _worksheet.GetValue(_fromRow, _fromCol); + } + return GetValueArray(); + } + set { + if (IsName) { + if (_worksheet == null) { + _workbook._names[_address].NameValue = value; + } else { + _worksheet.Names[_address].NameValue = value; + } + } else { + _changePropMethod(Set_Value, value); + } + } + } + + private bool IsInfinityValue(object value) { + double? valueAsDouble = value as double?; + + if (valueAsDouble.HasValue + && (double.IsNegativeInfinity(valueAsDouble.Value) + || double.IsPositiveInfinity(valueAsDouble.Value))) { + return true; + } + + return false; + } + + private object GetValueArray() { + ExcelAddressBase addr; + if (_fromRow == 1 + && _fromCol == 1 + && _toRow == ExcelPackage.MaxRows + && _toCol == ExcelPackage.MaxColumns) { + addr = _worksheet.Dimension; + if (addr == null) { + return null; + } + } else { + addr = this; + } + object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1]; + + for (int col = addr._fromCol; col <= addr._toCol; col++) { + for (int row = addr._fromRow; row <= addr._toRow; row++) { + if (_worksheet._values.Exists(row, col)) { + if (_worksheet._flags.GetFlagValue(row, col, CellFlags.RichText)) { + v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text; + } else { + v[row - addr._fromRow, col - addr._fromCol] = _worksheet._values.GetValue(row, col); + } + } + } + } + return v; + } + + private ExcelAddressBase GetAddressDim(ExcelRangeBase addr) { + int fromRow, + fromCol, + toRow, + toCol; + var d = _worksheet.Dimension; + fromRow = addr._fromRow < d._fromRow ? d._fromRow : addr._fromRow; + fromCol = addr._fromCol < d._fromCol ? d._fromCol : addr._fromCol; + + toRow = addr._toRow > d._toRow ? d._toRow : addr._toRow; + toCol = addr._toCol > d._toCol ? d._toCol : addr._toCol; + + if (addr._fromCol == fromRow && addr._toRow == toRow && addr._toCol == _toCol) { + return addr; + } + if (_fromRow > _toRow || _fromCol > _toCol) { + return null; + } + return new(fromRow, fromCol, toRow, toCol); + } + + private object GetSingleValue() { + if (IsRichText) { + return RichText.Text; + } + return _worksheet._values.GetValue(_fromRow, _fromCol); + } + + /// <summary> + /// Returns the formatted value. + /// </summary> + public string Text => GetFormattedText(false); + + private void SetMinWidth(double minimumWidth, int fromCol, int toCol) { + var iterator = new CellsStoreEnumerator<object>(_worksheet._values, 0, fromCol, 0, toCol); + var prevCol = fromCol; + foreach (ExcelColumn col in iterator) { + col.Width = minimumWidth; + if (_worksheet.DefaultColWidth > minimumWidth && col.ColumnMin > prevCol) { + var newCol = _worksheet.Column(prevCol); + newCol.ColumnMax = col.ColumnMin - 1; + newCol.Width = minimumWidth; + } + prevCol = col.ColumnMax + 1; + } + if (_worksheet.DefaultColWidth > minimumWidth && prevCol < toCol) { + var newCol = _worksheet.Column(prevCol); + newCol.ColumnMax = toCol; + newCol.Width = minimumWidth; + } + } + + internal string TextForWidth => GetFormattedText(true); + + private string GetFormattedText(bool forWidthCalc) { + object v = Value; + if (v == null) { + return ""; + } + var styles = Worksheet.Workbook.Styles; + var nfId = styles.CellXfs[StyleID].NumberFormatId; + ExcelNumberFormatXml.ExcelFormatTranslator nf = null; + for (int i = 0; i < styles.NumberFormats.Count; i++) { + if (nfId == styles.NumberFormats[i].NumFmtId) { + nf = styles.NumberFormats[i].FormatTranslator; + break; + } + } + + string format, + textFormat; + if (forWidthCalc) { + format = nf.NetFormatForWidth; + textFormat = nf.NetTextFormatForWidth; + } else { + format = nf.NetFormat; + textFormat = nf.NetTextFormat; + } + + return FormatValue(v, nf, format, textFormat); + } + + internal static string FormatValue( + object v, + ExcelNumberFormatXml.ExcelFormatTranslator nf, + string format, + string textFormat) { + if (v is decimal || v.GetType().IsPrimitive) { + double d; + try { + d = Convert.ToDouble(v); + } catch { + return ""; + } + + if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number) { + if (string.IsNullOrEmpty(nf.FractionFormat)) { + return d.ToString(format, nf.Culture); + } + return nf.FormatFraction(d); + } + if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { + var date = DateTime.FromOADate(d); + return date.ToString(format, nf.Culture); + } + } else if (v is DateTime) { + if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { + return ((DateTime)v).ToString(format, nf.Culture); + } + double d = ((DateTime)v).ToOADate(); + if (string.IsNullOrEmpty(nf.FractionFormat)) { + return d.ToString(format, nf.Culture); + } + return nf.FormatFraction(d); + } else if (v is TimeSpan) { + if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { + return new DateTime(((TimeSpan)v).Ticks).ToString(format, nf.Culture); + } + double d = (new DateTime(((TimeSpan)v).Ticks)).ToOADate(); + if (string.IsNullOrEmpty(nf.FractionFormat)) { + return d.ToString(format, nf.Culture); + } + return nf.FormatFraction(d); + } else { + if (textFormat == "") { + return v.ToString(); + } + return string.Format(textFormat, v); + } + return v.ToString(); + } + + /// <summary> + /// Gets or sets a formula for a range. + /// </summary> + public string Formula { + get { + if (IsName) { + if (_worksheet == null) { + return _workbook._names[_address].NameFormula; + } + return _worksheet.Names[_address].NameFormula; + } + return _worksheet.GetFormula(_fromRow, _fromCol); + } + set { + if (IsName) { + if (_worksheet == null) { + _workbook._names[_address].NameFormula = value; + } else { + _worksheet.Names[_address].NameFormula = value; + } + } else { + if (value == null || value.Trim() == "") { + //Set the cells to null + Value = null; + } else if (_fromRow == _toRow && _fromCol == _toCol) { + Set_Formula(value, _fromRow, _fromCol); + } else { + Set_SharedFormula(value, this, false); + if (Addresses != null) { + foreach (var address in Addresses) { + Set_SharedFormula(value, address, false); + } + } + } + } + } + } + + /// <summary> + /// Gets or Set a formula in R1C1 format. + /// </summary> + public string FormulaR1C1 { + get { + IsRangeValid("FormulaR1C1"); + return _worksheet.GetFormulaR1C1(_fromRow, _fromCol); + } + set { + IsRangeValid("FormulaR1C1"); + if (value.Length > 0 && value[0] == '=') { + value = value.Substring(1, value.Length - 1); // remove any starting equalsign. + } + + if (value == null || value.Trim() == "") { + //Set the cells to null + _worksheet.Cells[TranslateFromR1C1(value, _fromRow, _fromCol)].Value = null; + } else if (Addresses == null) { + Set_SharedFormula(TranslateFromR1C1(value, _fromRow, _fromCol), this, false); + } else { + Set_SharedFormula( + TranslateFromR1C1(value, _fromRow, _fromCol), + new(WorkSheet, FirstAddress), + false); + foreach (var address in Addresses) { + Set_SharedFormula( + TranslateFromR1C1(value, address.Start.Row, address.Start.Column), + address, + false); + } + } + } + } + + /// <summary> + /// Gets or Set a formula in R1C1 format. + /// + public string FormulaR1C1_V1 { + get { + IsRangeValid("FormulaR1C1"); + return _worksheet.GetFormulaR1C1_V1(_fromRow, _fromCol); + } + } + + public string ArrayFormulaAddress { + get { + IsRangeValid("FormulaR1C1"); + return _worksheet.GetArrayFormulaAddress(_fromRow, _fromCol); + } + } + + /// <summary> + /// Set the hyperlink property for a range of cells + /// </summary> + public Uri Hyperlink { + get { + IsRangeValid("formulaR1C1"); + return _worksheet._hyperLinks.GetValue(_fromRow, _fromCol); + } + set => _changePropMethod(Set_HyperLink, value); + } + + /// <summary> + /// If the cells in the range are merged. + /// </summary> + public bool Merge { + get { + IsRangeValid("merging"); + for (int col = _fromCol; col <= _toCol; col++) { + for (int row = _fromRow; row <= _toRow; row++) { + if (_worksheet.MergedCells[row, col] == null) { + return false; + } + //if (!_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged)) + //{ + // return false; + //} + } + } + return true; + } + set { + IsRangeValid("merging"); + //SetMerge(value, FirstAddress); + if (value) { + _worksheet.MergedCells.Add(new(FirstAddress), true); + if (Addresses != null) { + foreach (var address in Addresses) { + _worksheet.MergedCells.Add(address, true); + //SetMerge(value, address._address); + } + } + } else { + _worksheet.MergedCells.Clear(this); + if (Addresses != null) { + foreach (var address in Addresses) { + _worksheet.MergedCells.Clear(address); + ; + } + } + } + } + } + + //private void SetMerge(bool value, string address) + //{ + // if (!value) + // { + // if (_worksheet.MergedCells.List.Contains(address)) + // { + // SetCellMerge(false, address); + // _worksheet.MergedCells.List.Remove(address); + // } + // else if (!CheckMergeDiff(false, address)) + // { + // throw (new Exception("Range is not fully merged.Specify the exact range")); + // } + // } + // else + // { + // if (CheckMergeDiff(false, address)) + // { + // SetCellMerge(true, address); + // _worksheet.MergedCells.List.Add(address); + // } + // else + // { + // if (!_worksheet.MergedCells.List.Contains(address)) + // { + // throw (new Exception("Cells are already merged")); + // } + // } + // } + //} + /// <summary> + /// Set an autofilter for the range + /// </summary> + public bool AutoFilter { + get { + IsRangeValid("autofilter"); + ExcelAddressBase address = _worksheet.AutoFilterAddress; + if (address == null) { + return false; + } + if (_fromRow >= address.Start.Row + && _toRow <= address.End.Row + && _fromCol >= address.Start.Column + && _toCol <= address.End.Column) { + return true; + } + return false; + } + set { + IsRangeValid("autofilter"); + _worksheet.AutoFilterAddress = this; + if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase")) { + _worksheet.Names.Remove("_xlnm._FilterDatabase"); + } + var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this); + result.IsNameHidden = true; + } + } + + /// <summary> + /// If the value is in richtext format. + /// </summary> + public bool IsRichText { + get { + IsRangeValid("richtext"); + return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.RichText); + } + set => _changePropMethod(Set_IsRichText, value); + } + + /// <summary> + /// Is the range a part of an Arrayformula + /// </summary> + public bool IsArrayFormula { + get { + IsRangeValid("arrayformulas"); + return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.ArrayFormula); + } + set => _changePropMethod(Set_IsArrayFormula, value); + } + + private ExcelRichTextCollection _rtc; + + /// <summary> + /// Cell value is richtext formatted. + /// Richtext-property only apply to the left-top cell of the range. + /// </summary> + public ExcelRichTextCollection RichText { + get { + IsRangeValid("richtext"); + if (_rtc == null) { + _rtc = GetRichText(_fromRow, _fromCol); + } + return _rtc; + } + } + + private ExcelRichTextCollection GetRichText(int row, int col) { + XmlDocument xml = new XmlDocument(); + var v = _worksheet._values.GetValue(row, col); + var isRt = _worksheet._flags.GetFlagValue(row, col, CellFlags.RichText); + if (v != null) { + if (isRt) { + XmlHelper.LoadXmlSafe( + xml, + "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >" + + v + + "</d:si>", + Encoding.UTF8); + } else { + xml.LoadXml( + "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ><d:r><d:t>" + + SecurityElement.Escape(v.ToString()) + + "</d:t></d:r></d:si>"); + } + } else { + xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />"); + } + var rtc = new ExcelRichTextCollection( + _worksheet.NameSpaceManager, + xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager), + this); + return rtc; + } + + /// <summary> + /// returns the comment object of the first cell in the range + /// </summary> + public ExcelComment Comment { + get { + IsRangeValid("comments"); + ulong cellId = GetCellId(_worksheet.SheetID, _fromRow, _fromCol); + if (_worksheet.Comments._comments.ContainsKey(cellId)) { + return _worksheet._comments._comments[cellId] as ExcelComment; + } + return null; + } + } + + /// <summary> + /// WorkSheet object + /// </summary> + public ExcelWorksheet Worksheet => _worksheet; + + /// <summary> + /// Address including sheetname + /// </summary> + public string FullAddress { + get { + string fullAddress = GetFullAddress(_worksheet.Name, _address); + if (Addresses != null) { + foreach (var a in Addresses) { + fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address); + ; + } + } + return fullAddress; + } + } + + /// <summary> + /// Address including sheetname + /// </summary> + public string FullAddressAbsolute { + get { + string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws; + string fullAddress = GetFullAddress( + wbwsRef, + GetAddress(_fromRow, _fromCol, _toRow, _toCol, true)); + if (Addresses != null) { + foreach (var a in Addresses) { + fullAddress += + "," + + GetFullAddress( + wbwsRef, + GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true)); + ; + } + } + return fullAddress; + } + } + + /// <summary> + /// Address including sheetname + /// </summary> + internal string FullAddressAbsoluteNoFullRowCol { + get { + string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws; + string fullAddress = GetFullAddress( + wbwsRef, + GetAddress(_fromRow, _fromCol, _toRow, _toCol, true), + false); + if (Addresses != null) { + foreach (var a in Addresses) { + fullAddress += + "," + + GetFullAddress( + wbwsRef, + GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true), + false); + ; + } + } + return fullAddress; + } + } + + /// <summary> + /// Set the value without altering the richtext property + /// </summary> + /// <param name="value">the value</param> + internal void SetValueRichText(object value) { + if (_fromRow == 1 + && _fromCol == 1 + && _toRow == ExcelPackage.MaxRows + && _toCol + == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging + { + //_worksheet.Cell(1, 1).SetValueRichText(value); + SetValue(value, 1, 1); + } else { + //for (int col = _fromCol; col <= _toCol; col++) + //{ + // for (int row = _fromRow; row <= _toRow; row++) + // { + //_worksheet.Cell(row, col).SetValueRichText(value); + SetValue(value, _fromRow, _fromCol); + //} + //} + } + } + + private void SetValue(object value, int row, int col) { + _worksheet.SetValue(row, col, value); + // if (value is string) _worksheet._types.SetValue(row, col, "S"); else _worksheet._types.SetValue(row, col, ""); + _worksheet._formulas.SetValue(row, col, ""); + } + + internal void SetSharedFormulaId(int id) { + for (int col = _fromCol; col <= _toCol; col++) { + for (int row = _fromRow; row <= _toRow; row++) { + _worksheet._formulas.SetValue(row, col, id); + } + } + } + + private void CheckAndSplitSharedFormula(ExcelAddressBase address) { + for (int col = address._fromCol; col <= address._toCol; col++) { + for (int row = address._fromRow; row <= address._toRow; row++) { + var f = _worksheet._formulas.GetValue(row, col); + if (f is int && (int)f >= 0) { + SplitFormulas(address); + return; + } + } + } + } + + private void SplitFormulas(ExcelAddressBase address) { + List<int> formulas = new List<int>(); + for (int col = address._fromCol; col <= address._toCol; col++) { + for (int row = address._fromRow; row <= address._toRow; row++) { + var f = _worksheet._formulas.GetValue(row, col); + if (f is int) { + int id = (int)f; + if (id >= 0 && !formulas.Contains(id)) { + if (_worksheet._sharedFormulas[id].IsArray + && Collide(_worksheet.Cells[_worksheet._sharedFormulas[id].Address]) + == eAddressCollition.Partly) // If the formula is an array formula and its on the inside the overwriting range throw an exception + { + throw (new InvalidOperationException("Can not overwrite a part of an array-formula")); + } + formulas.Add(id); + } + } + } + } + + foreach (int ix in formulas) { + SplitFormula(address, ix); + } + + ////Clear any formula references inside the refered range + //_worksheet._formulas.Clear(address._fromRow, address._toRow, address._toRow - address._fromRow + 1, address._toCol - address.column + 1); + } + + private void SplitFormula(ExcelAddressBase address, int ix) { + var f = _worksheet._sharedFormulas[ix]; + var fRange = _worksheet.Cells[f.Address]; + var collide = address.Collide(fRange); + + //The formula is inside the currenct range, remove it + if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside) { + _worksheet._sharedFormulas.Remove(ix); + return; + //fRange.SetSharedFormulaID(int.MinValue); + } + var firstCellCollide = address.Collide( + new(fRange._fromRow, fRange._fromCol, fRange._fromRow, fRange._fromCol)); + if (collide == eAddressCollition.Partly + && (firstCellCollide == eAddressCollition.Inside + || firstCellCollide + == eAddressCollition.Equal)) //Do we need to split? Only if the functions first row is inside the new range. + { + //The formula partly collides with the current range + bool fIsSet = false; + string formulaR1C1 = fRange.FormulaR1C1; + //Top Range + if (fRange._fromRow < _fromRow) { + f.Address = GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol); + fIsSet = true; + } + //Left Range + if (fRange._fromCol < address._fromCol) { + if (fIsSet) { + f = new(SourceCodeTokenizer.Default); + f.Index = _worksheet.GetMaxShareFunctionIndex(false); + f.StartCol = fRange._fromCol; + f.IsArray = false; + _worksheet._sharedFormulas.Add(f.Index, f); + } else { + fIsSet = true; + } + if (fRange._fromRow < address._fromRow) { + f.StartRow = address._fromRow; + } else { + f.StartRow = fRange._fromRow; + } + if (fRange._toRow < address._toRow) { + f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, address._fromCol - 1); + } else { + f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, address._fromCol - 1); + } + f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); + _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); + } + //Right Range + if (fRange._toCol > address._toCol) { + if (fIsSet) { + f = new(SourceCodeTokenizer.Default); + f.Index = _worksheet.GetMaxShareFunctionIndex(false); + f.IsArray = false; + _worksheet._sharedFormulas.Add(f.Index, f); + } else { + fIsSet = true; + } + f.StartCol = address._toCol + 1; + if (address._fromRow < fRange._fromRow) { + f.StartRow = fRange._fromRow; + } else { + f.StartRow = address._fromRow; + } + + if (fRange._toRow < address._toRow) { + f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol); + } else { + f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, fRange._toCol); + } + f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); + _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); + } + //Bottom Range + if (fRange._toRow > address._toRow) { + if (fIsSet) { + f = new(SourceCodeTokenizer.Default); + f.Index = _worksheet.GetMaxShareFunctionIndex(false); + f.IsArray = false; + _worksheet._sharedFormulas.Add(f.Index, f); + } + + f.StartCol = fRange._fromCol; + f.StartRow = _toRow + 1; + + f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); + + f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol); + _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); + } + } + } + + private object ConvertData(ExcelTextFormat format, string v, int col, bool isText) { + if (isText && (format.DataTypes == null || format.DataTypes.Length < col)) { + return v; + } + + double d; + DateTime dt; + if (format.DataTypes == null + || format.DataTypes.Length <= col + || format.DataTypes[col] == eDataTypes.Unknown) { + string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; + if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) { + if (v2 == v) { + return d; + } + return d / 100; + } + if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) { + return dt; + } + return v; + } + switch (format.DataTypes[col]) { + case eDataTypes.Number: + if (double.TryParse(v, NumberStyles.Any, format.Culture, out d)) { + return d; + } + return v; + case eDataTypes.DateTime: + if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) { + return dt; + } + return v; + case eDataTypes.Percent: + string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; + if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) { + return d / 100; + } + return v; + + default: + return v; + } + } + + /// <summary> + /// Conditional Formatting for this range. + /// </summary> + public IRangeConditionalFormatting ConditionalFormatting => + new RangeConditionalFormatting(_worksheet, new(Address)); + + /// <summary> + /// Data validation for this range. + /// </summary> + public IRangeDataValidation DataValidation => new RangeDataValidation(_worksheet, Address); + + /// <summary> + /// Load the data from the datareader starting from the top left cell of the range + /// </summary> + /// <param name="reader">The datareader to loadfrom</param> + /// <param name="printHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param> + /// <param name="tableName">The name of the table</param> + /// <param name="tableStyle">The table style to apply to the data</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromDataReader( + IDataReader reader, + bool printHeaders, + string tableName, + TableStyles tableStyle = TableStyles.None) { + var r = LoadFromDataReader(reader, printHeaders); + + int rows = r.Rows - 1; + if (rows >= 0 && r.Columns > 0) { + var tbl = _worksheet.Tables.Add( + new(_fromRow, _fromCol, _fromRow + (rows <= 0 ? 1 : rows), _fromCol + r.Columns - 1), + tableName); + tbl.ShowHeader = printHeaders; + tbl.TableStyle = tableStyle; + } + return r; + } + + /// <summary> + /// Load the data from the datareader starting from the top left cell of the range + /// </summary> + /// <param name="reader">The datareader to load from</param> + /// <param name="printHeaders">Print the caption property (if set) or the columnname property if not, on first row</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromDataReader(IDataReader reader, bool printHeaders) { + if (reader == null) { + throw (new ArgumentNullException("reader", "Reader can't be null")); + } + int fieldCount = reader.FieldCount; + + int col = _fromCol, + row = _fromRow; + if (printHeaders) { + for (int i = 0; i < fieldCount; i++) { + // If no caption is set, the ColumnName property is called implicitly. + _worksheet._values.SetValue(row, col++, reader.GetName(i)); + } + row++; + col = _fromCol; + } + while (reader.Read()) { + for (int i = 0; i < fieldCount; i++) { + _worksheet._values.SetValue(row, col++, reader.GetValue(i)); + } + row++; + col = _fromCol; + } + return _worksheet.Cells[_fromRow, _fromCol, row - 1, _fromCol + fieldCount - 1]; + } + + /// <summary> + /// Load the data from the datatable starting from the top left cell of the range + /// </summary> + /// <param name="table">The datatable to load</param> + /// <param name="printHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param> + /// <param name="tableStyle">The table style to apply to the data</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromDataTable( + DataTable table, + bool printHeaders, + TableStyles tableStyle) { + var r = LoadFromDataTable(table, printHeaders); + + int rows = (table.Rows.Count == 0 ? 1 : table.Rows.Count) + (printHeaders ? 1 : 0); + if (rows >= 0 && table.Columns.Count > 0) { + var tbl = _worksheet.Tables.Add( + new(_fromRow, _fromCol, _fromRow + rows - 1, _fromCol + table.Columns.Count - 1), + table.TableName); + tbl.ShowHeader = printHeaders; + tbl.TableStyle = tableStyle; + } + return r; + } + + /// <summary> + /// Load the data from the datatable starting from the top left cell of the range + /// </summary> + /// <param name="table">The datatable to load</param> + /// <param name="printHeaders">Print the caption property (if set) or the columnname property if not, on first row</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromDataTable(DataTable table, bool printHeaders) { + if (table == null) { + throw (new ArgumentNullException("Table can't be null")); + } + + int col = _fromCol, + row = _fromRow; + if (printHeaders) { + foreach (DataColumn dc in table.Columns) { + // If no caption is set, the ColumnName property is called implicitly. + _worksheet._values.SetValue(row, col++, dc.Caption); + } + row++; + col = _fromCol; + } else if (table.Rows.Count == 0) { + return null; + } + foreach (DataRow dr in table.Rows) { + foreach (object value in dr.ItemArray) { + if (value != null && value != DBNull.Value && !string.IsNullOrEmpty(value.ToString())) { + _worksheet._values.SetValue(row, col++, value); + } else { + col++; + } + } + row++; + col = _fromCol; + } + return _worksheet.Cells[_fromRow, + _fromCol, + (row == _fromRow ? _fromRow : row - 1), + _fromCol + table.Columns.Count - 1]; + } + + /// <summary> + /// Loads data from the collection of arrays of objects into the range, starting from + /// the top-left cell. + /// </summary> + /// <param name="data">The data.</param> + public ExcelRangeBase LoadFromArrays(IEnumerable<object[]> data) { + //thanx to Abdullin for the code contribution + if (data == null) { + throw new ArgumentNullException("data"); + } + + int column = _fromCol, + row = _fromRow; + + foreach (var rowData in data) { + column = _fromCol; + foreach (var cellData in rowData) { + _worksheet._values.SetValue(row, column, cellData); + column += 1; + } + row += 1; + } + return _worksheet.Cells[_fromRow, _fromCol, row - 1, column - 1]; + } + + /// <summary> + /// Load a collection into a the worksheet starting from the top left row of the range. + /// </summary> + /// <typeparam name="T">The datatype in the collection</typeparam> + /// <param name="collection">The collection to load</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> collection) { + return LoadFromCollection( + collection, + false, + TableStyles.None, + BindingFlags.Public | BindingFlags.Instance, + null); + } + + /// <summary> + /// Load a collection of T into the worksheet starting from the top left row of the range. + /// Default option will load all public instance properties of T + /// </summary> + /// <typeparam name="T">The datatype in the collection</typeparam> + /// <param name="collection">The collection to load</param> + /// <param name="printHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> collection, bool printHeaders) { + return LoadFromCollection( + collection, + printHeaders, + TableStyles.None, + BindingFlags.Public | BindingFlags.Instance, + null); + } + + /// <summary> + /// Load a collection of T into the worksheet starting from the top left row of the range. + /// Default option will load all public instance properties of T + /// </summary> + /// <typeparam name="T">The datatype in the collection</typeparam> + /// <param name="collection">The collection to load</param> + /// <param name="printHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> + /// <param name="tableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromCollection<T>( + IEnumerable<T> collection, + bool printHeaders, + TableStyles tableStyle) { + return LoadFromCollection( + collection, + printHeaders, + tableStyle, + BindingFlags.Public | BindingFlags.Instance, + null); + } + + /// <summary> + /// Load a collection into the worksheet starting from the top left row of the range. + /// </summary> + /// <typeparam name="T">The datatype in the collection</typeparam> + /// <param name="collection">The collection to load</param> + /// <param name="printHeaders">Print the property names on the first row. Any underscore in the property name will be converted to a space. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param> + /// <param name="tableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param> + /// <param name="memberFlags">Property flags to use</param> + /// <param name="members">The properties to output. Must be of type T</param> + /// <returns>The filled range</returns> + public ExcelRangeBase LoadFromCollection<T>( + IEnumerable<T> collection, + bool printHeaders, + TableStyles tableStyle, + BindingFlags memberFlags, + MemberInfo[] members) { + var type = typeof(T); + if (members == null) { + members = type.GetProperties(memberFlags); + } else { + foreach (var t in members) { + if (t.DeclaringType != null + && t.DeclaringType != type + && !t.DeclaringType.IsSubclassOf(type)) { + throw new InvalidCastException( + "Supplied properties in parameter Properties must be of the same type as T (or an assignable type from T"); + } + } + } + + int col = _fromCol, + row = _fromRow; + if (members.Length > 0 && printHeaders) { + foreach (var t in members) { + var descriptionAttribute = + t.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() + as DescriptionAttribute; + var header = string.Empty; + if (descriptionAttribute != null) { + header = descriptionAttribute.Description; + } else { + var displayNameAttribute = + t.GetCustomAttributes(typeof(DisplayNameAttribute), false).FirstOrDefault() + as DisplayNameAttribute; + if (displayNameAttribute != null) { + header = displayNameAttribute.DisplayName; + } else { + header = t.Name.Replace('_', ' '); + } + } + _worksheet._values.SetValue(row, col++, header); + } + row++; + } + + if (!collection.Any() && (members.Length == 0 || printHeaders == false)) { + return null; + } + + if (members.Length == 0) { + foreach (var item in collection) { + _worksheet.Cells[row++, col].Value = item; + } + } else { + foreach (var item in collection) { + col = _fromCol; + if (item is string || item is decimal || item is DateTime || item.GetType().IsPrimitive) { + _worksheet.Cells[row, col++].Value = item; + } else { + foreach (var t in members) { + if (t is PropertyInfo) { + _worksheet.Cells[row, col++].Value = ((PropertyInfo)t).GetValue(item, null); + } else if (t is FieldInfo) { + _worksheet.Cells[row, col++].Value = ((FieldInfo)t).GetValue(item); + } else if (t is MethodInfo) { + _worksheet.Cells[row, col++].Value = ((MethodInfo)t).Invoke(item, null); + } + } + } + row++; + } + } + + if (_fromRow == row - 1 && printHeaders) { + row++; + } + + var r = _worksheet.Cells[_fromRow, _fromCol, row - 1, members.Length == 0 ? col : col - 1]; + + if (tableStyle != TableStyles.None) { + var tbl = _worksheet.Tables.Add(r, ""); + tbl.ShowHeader = printHeaders; + tbl.TableStyle = tableStyle; + } + return r; + } + + /// <summary> + /// Loads a CSV text into a range starting from the top left cell. + /// Default settings is Comma separation + /// </summary> + /// <param name="text">The Text</param> + /// <returns>The range containing the data</returns> + public ExcelRangeBase LoadFromText(string text) { + return LoadFromText(text, new()); + } + + /// <summary> + /// Loads a CSV text into a range starting from the top left cell. + /// </summary> + /// <param name="text">The Text</param> + /// <param name="format">Information how to load the text</param> + /// <returns>The range containing the data</returns> + public ExcelRangeBase LoadFromText(string text, ExcelTextFormat format) { + if (string.IsNullOrEmpty(text)) { + var r = _worksheet.Cells[_fromRow, _fromCol]; + r.Value = ""; + return r; + } + + if (format == null) { + format = new(); + } + + string splitRegex = String.Format( + "{0}(?=(?:[^{1}]*{1}[^{1}]*{1})*[^{1}]*$)", + format.EOL, + format.TextQualifier); + string[] lines = Regex.Split(text, splitRegex); + int row = _fromRow; + int col = _fromCol; + int maxCol = col; + int lineNo = 1; + foreach (string line in lines) { + if (lineNo > format.SkipLinesBeginning && lineNo <= lines.Length - format.SkipLinesEnd) { + col = _fromCol; + string v = ""; + bool isText = false, + isQualifier = false; + int qCount = 0; + int lineQCount = 0; + foreach (char c in line) { + if (format.TextQualifier != 0 && c == format.TextQualifier) { + if (!isText && v != "") { + throw (new(string.Format("Invalid Text Qualifier in line : {0}", line))); + } + isQualifier = !isQualifier; + qCount += 1; + lineQCount++; + isText = true; + } else { + if (qCount > 1 && !string.IsNullOrEmpty(v)) { + v += new string(format.TextQualifier, qCount / 2); + } else if (qCount > 2 && string.IsNullOrEmpty(v)) { + v += new string(format.TextQualifier, (qCount - 1) / 2); + } + + if (isQualifier) { + v += c; + } else { + if (c == format.Delimiter) { + _worksheet.SetValue(row, col, ConvertData(format, v, col - _fromCol, isText)); + v = ""; + isText = false; + col++; + } else { + if (qCount % 2 == 1) { + throw (new(string.Format("Text delimiter is not closed in line : {0}", line))); + } + v += c; + } + } + qCount = 0; + } + } + if (qCount > 1) { + v += new string(format.TextQualifier, qCount / 2); + } + if (lineQCount % 2 == 1) { + throw (new(string.Format("Text delimiter is not closed in line : {0}", line))); + } + + _worksheet._values.SetValue(row, col, ConvertData(format, v, col - _fromCol, isText)); + if (col > maxCol) { + maxCol = col; + } + row++; + } + lineNo++; + } + return _worksheet.Cells[_fromRow, _fromCol, row - 1, maxCol]; + } + + /// <summary> + /// Loads a CSV text into a range starting from the top left cell. + /// </summary> + /// <param name="text">The Text</param> + /// <param name="format">Information how to load the text</param> + /// <param name="tableStyle">Create a table with this style</param> + /// <param name="firstRowIsHeader">Use the first row as header</param> + /// <returns></returns> + public ExcelRangeBase LoadFromText( + string text, + ExcelTextFormat format, + TableStyles tableStyle, + bool firstRowIsHeader) { + var r = LoadFromText(text, format); + + var tbl = _worksheet.Tables.Add(r, ""); + tbl.ShowHeader = firstRowIsHeader; + tbl.TableStyle = tableStyle; + + return r; + } + + /// <summary> + /// Loads a CSV file into a range starting from the top left cell. + /// </summary> + /// <param name="textFile">The Textfile</param> + /// <returns></returns> + public ExcelRangeBase LoadFromText(FileInfo textFile) { + return LoadFromText(File.ReadAllText(textFile.FullName, Encoding.ASCII)); + } + + /// <summary> + /// Loads a CSV file into a range starting from the top left cell. + /// </summary> + /// <param name="textFile">The Textfile</param> + /// <param name="format">Information how to load the text</param> + /// <returns></returns> + public ExcelRangeBase LoadFromText(FileInfo textFile, ExcelTextFormat format) { + return LoadFromText(File.ReadAllText(textFile.FullName, format.Encoding), format); + } + + /// <summary> + /// Loads a CSV file into a range starting from the top left cell. + /// </summary> + /// <param name="textFile">The Textfile</param> + /// <param name="format">Information how to load the text</param> + /// <param name="tableStyle">Create a table with this style</param> + /// <param name="firstRowIsHeader">Use the first row as header</param> + /// <returns></returns> + public ExcelRangeBase LoadFromText( + FileInfo textFile, + ExcelTextFormat format, + TableStyles tableStyle, + bool firstRowIsHeader) { + return LoadFromText( + File.ReadAllText(textFile.FullName, format.Encoding), + format, + tableStyle, + firstRowIsHeader); + } + + /// <summary> + /// Get the strongly typed value of the cell. + /// </summary> + /// <typeparam name="T">The type</typeparam> + /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns> + public T GetValue<T>() { + return _worksheet.GetTypedValue<T>(Value); + } + + /// <summary> + /// Get a range with an offset from the top left cell. + /// The new range has the same dimensions as the current range + /// </summary> + /// <param name="rowOffset">Row Offset</param> + /// <param name="columnOffset">Column Offset</param> + /// <returns></returns> + public ExcelRangeBase Offset(int rowOffset, int columnOffset) { + if (_fromRow + rowOffset < 1 + || _fromCol + columnOffset < 1 + || _fromRow + rowOffset > ExcelPackage.MaxRows + || _fromCol + columnOffset > ExcelPackage.MaxColumns) { + throw (new ArgumentOutOfRangeException("Offset value out of range")); + } + string address = GetAddress( + _fromRow + rowOffset, + _fromCol + columnOffset, + _toRow + rowOffset, + _toCol + columnOffset); + return new(_worksheet, address); + } + + /// <summary> + /// Get a range with an offset from the top left cell. + /// </summary> + /// <param name="rowOffset">Row Offset</param> + /// <param name="columnOffset">Column Offset</param> + /// <param name="numberOfRows">Number of rows. Minimum 1</param> + /// <param name="numberOfColumns">Number of colums. Minimum 1</param> + /// <returns></returns> + public ExcelRangeBase Offset( + int rowOffset, + int columnOffset, + int numberOfRows, + int numberOfColumns) { + if (numberOfRows < 1 || numberOfColumns < 1) { + throw (new("Number of rows/columns must be greater than 0")); + } + numberOfRows--; + numberOfColumns--; + if (_fromRow + rowOffset < 1 + || _fromCol + columnOffset < 1 + || _fromRow + rowOffset > ExcelPackage.MaxRows + || _fromCol + columnOffset > ExcelPackage.MaxColumns + || _fromRow + rowOffset + numberOfRows < 1 + || _fromCol + columnOffset + numberOfColumns < 1 + || _fromRow + rowOffset + numberOfRows > ExcelPackage.MaxRows + || _fromCol + columnOffset + numberOfColumns > ExcelPackage.MaxColumns) { + throw (new ArgumentOutOfRangeException("Offset value out of range")); + } + string address = GetAddress( + _fromRow + rowOffset, + _fromCol + columnOffset, + _fromRow + rowOffset + numberOfRows, + _fromCol + columnOffset + numberOfColumns); + return new(_worksheet, address); + } + + /// <summary> + /// Adds a new comment for the range. + /// If this range contains more than one cell, the top left comment is returned by the method. + /// </summary> + /// <param name="text"></param> + /// <param name="author"></param> + /// <returns>A reference comment of the top left cell</returns> + public ExcelComment AddComment(string text, string author) { + if (string.IsNullOrEmpty(author)) { + author = Thread.CurrentPrincipal.Identity.Name; + } + //Check if any comments exists in the range and throw an exception + _changePropMethod(Exists_Comment, null); + //Create the comments + _changePropMethod(Set_Comment, new[] { text, author }); + + return _worksheet.Comments[new ExcelCellAddress(_fromRow, _fromCol)]; + } + + ///// <summary> + ///// Copies the range of cells to an other range + ///// </summary> + ///// <param name="Destination">The start cell where the range will be copied.</param> + public void Copy(ExcelRangeBase destination) { + bool sameWorkbook = destination._worksheet.Workbook == _worksheet.Workbook; + ExcelStyles sourceStyles = _worksheet.Workbook.Styles, + styles = destination._worksheet.Workbook.Styles; + Dictionary<int, int> styleCashe = new Dictionary<int, int>(); + + //Clear all existing cells; + int toRow = _toRow - _fromRow + 1, + toCol = _toCol - _fromCol + 1; + + string s = ""; + int i = 0; + object o = null; + byte flag = 0; + Uri hl = null; + ExcelComment comment = null; + + var cse = new CellsStoreEnumerator<object>( + _worksheet._values, + _fromRow, + _fromCol, + _toRow, + _toCol); + var copiedValue = new List<CopiedCell>(); + while (cse.Next()) { + var row = cse.Row; + var col = cse.Column; //Issue 15070 + var cell = new CopiedCell { + Row = destination._fromRow + (row - _fromRow), + Column = destination._fromCol + (col - _fromCol), + Value = cse.Value, + }; + + //Destination._worksheet._values.SetValue(row, col, cse.Value); + + if (_worksheet._types.Exists(row, col, ref s)) { + //Destination._worksheet._types.SetValue(row, col,s); + cell.Type = s; + } + + if (_worksheet._formulas.Exists(row, col, ref o)) { + if (o is int) { + // Destination._worksheet._formulas.SetValue(row, col, _worksheet.GetFormula(cse.Row, cse.Column)); //Shared formulas, set the formula per cell to simplify + cell.Formula = _worksheet.GetFormula(cse.Row, cse.Column); + } else { + //Destination._worksheet._formulas.SetValue(row, col, o); + cell.Formula = o; + } + } + if (_worksheet._styles.Exists(row, col, ref i)) { + if (sameWorkbook) { + //Destination._worksheet._styles.SetValue(row, col, i); + cell.StyleID = i; + } else { + if (styleCashe.ContainsKey(i)) { + i = styleCashe[i]; + } else { + var oldStyleId = i; + i = styles.CloneStyle(sourceStyles, i); + styleCashe.Add(oldStyleId, i); + } + //Destination._worksheet._styles.SetValue(row, col, i); + cell.StyleID = i; + } + } + + if (_worksheet._hyperLinks.Exists(row, col, ref hl)) { + //Destination._worksheet._hyperLinks.SetValue(row, col, hl); + cell.HyperLink = hl; + } + + if (_worksheet._commentsStore.Exists(row, col, ref comment)) { + cell.Comment = comment; + } + + if (_worksheet._flags.Exists(row, col, ref flag)) { + cell.Flag = flag; + } + copiedValue.Add(cell); + } + + //Copy styles with no cell value + var cses = new CellsStoreEnumerator<int>( + _worksheet._styles, + _fromRow, + _fromCol, + _toRow, + _toCol); + while (cses.Next()) { + if (!_worksheet._values.Exists(cses.Row, cses.Column)) { + var row = destination._fromRow + (cses.Row - _fromRow); + var col = destination._fromCol + (cses.Column - _fromCol); + var cell = new CopiedCell { + Row = row, + Column = col, + Value = null, + }; + + i = cses.Value; + if (sameWorkbook) { + cell.StyleID = i; + } else { + if (styleCashe.ContainsKey(i)) { + i = styleCashe[i]; + } else { + var oldStyleId = i; + i = styles.CloneStyle(sourceStyles, i); + styleCashe.Add(oldStyleId, i); + } + //Destination._worksheet._styles.SetValue(row, col, i); + cell.StyleID = i; + } + copiedValue.Add(cell); + } + } + var copiedMergedCells = new Dictionary<int, ExcelAddress>(); + //Merged cells + var csem = new CellsStoreEnumerator<int>( + _worksheet.MergedCells._cells, + _fromRow, + _fromCol, + _toRow, + _toCol); + while (csem.Next()) { + if (!copiedMergedCells.ContainsKey(csem.Value)) { + var adr = new ExcelAddress(_worksheet.Name, _worksheet.MergedCells.List[csem.Value]); + if (Collide(adr) == eAddressCollition.Inside) { + copiedMergedCells.Add( + csem.Value, + new( + destination._fromRow + (adr.Start.Row - _fromRow), + destination._fromCol + (adr.Start.Column - _fromCol), + destination._fromRow + (adr.End.Row - _fromRow), + destination._fromCol + (adr.End.Column - _fromCol))); + } else { + //Partial merge of the address ignore. + copiedMergedCells.Add(csem.Value, null); + } + } + } + + destination._worksheet.MergedCells.Clear( + new( + destination._fromRow, + destination._fromCol, + destination._fromRow + toRow - 1, + destination._fromCol + toCol - 1)); + + destination._worksheet._values.Clear(destination._fromRow, destination._fromCol, toRow, toCol); + destination._worksheet._formulas.Clear( + destination._fromRow, + destination._fromCol, + toRow, + toCol); + destination._worksheet._styles.Clear(destination._fromRow, destination._fromCol, toRow, toCol); + destination._worksheet._types.Clear(destination._fromRow, destination._fromCol, toRow, toCol); + destination._worksheet._hyperLinks.Clear( + destination._fromRow, + destination._fromCol, + toRow, + toCol); + destination._worksheet._flags.Clear(destination._fromRow, destination._fromCol, toRow, toCol); + destination._worksheet._commentsStore.Clear( + destination._fromRow, + destination._fromCol, + toRow, + toCol); + + foreach (var cell in copiedValue) { + destination._worksheet._values.SetValue(cell.Row, cell.Column, cell.Value); + + if (cell.Type != null) { + destination._worksheet._types.SetValue(cell.Row, cell.Column, cell.Type); + } + + if (cell.StyleID != null) { + destination._worksheet._styles.SetValue(cell.Row, cell.Column, cell.StyleID.Value); + } + + if (cell.Formula != null) { + cell.Formula = UpdateFormulaReferences( + cell.Formula.ToString(), + destination._fromRow - _fromRow, + destination._fromCol - _fromCol, + 0, + 0, + true); + destination._worksheet._formulas.SetValue(cell.Row, cell.Column, cell.Formula); + } + if (cell.HyperLink != null) { + destination._worksheet._hyperLinks.SetValue(cell.Row, cell.Column, cell.HyperLink); + } + + if (cell.Comment != null) { + //Destination._worksheet._commentsStore.SetValue(cell.Row, cell.Column, cell.Comment); + } + if (cell.Flag != 0) { + destination._worksheet._flags.SetValue(cell.Row, cell.Column, cell.Flag); + } + } + + //Add merged cells + foreach (var m in copiedMergedCells.Values) { + if (m != null) { + destination._worksheet.MergedCells.Add(m, true); + } + } + + //Clone the cell + //var copiedCell = (_worksheet._cells[GetCellID(_worksheet.SheetID, cell._fromRow, cell.column)] as ExcelCell); + + //var newCell = copiedCell.Clone(Destination._worksheet, + // Destination._fromRow + (copiedCell.Row - _fromRow), + // Destination.column + (copiedCell.Column - column)); + + // newCell.MergeId = _worksheet.GetMergeCellId(copiedCell.Row, copiedCell.Column); + + // if (!string.IsNullOrEmpty(newCell.Formula)) + // { + // newCell.Formula = ExcelCell.UpdateFormulaReferences(newCell.Formula, newCell.Row - copiedCell.Row, (newCell.Column - copiedCell.Column), 1, 1); + // } + + // //If its not the same workbook we must copy the styles to the new workbook. + // if (!sameWorkbook) + // { + // if (styleCashe.ContainsKey(cell.StyleID)) + // { + // newCell.StyleID = styleCashe[cell.StyleID]; + // } + // else + // { + // newCell.StyleID = styles.CloneStyle(sourceStyles, cell.StyleID); + // styleCashe.Add(cell.StyleID, newCell.StyleID); + // } + // } + // newCells.Add(newCell); + // if (newCell.Merge) mergedCells.Add(newCell.CellID, newCell); + // } + + // //Now clear the destination. + // Destination.Offset(0, 0, (_toRow - _fromRow) + 1, (_toCol - column) + 1).Clear(); + + // //And last add the new cells to the worksheet + // foreach (var cell in newCells) + // { + // Destination.Worksheet._cells.Add(cell); + // } + // //Add merged cells + // if (mergedCells.Count > 0) + // { + // List<ExcelAddressBase> mergedAddresses = new List<ExcelAddressBase>(); + // foreach (var cell in mergedCells.Values) + // { + // if (!IsAdded(cell, mergedAddresses)) + // { + // int startRow = cell.Row, startCol = cell.Column, endRow = cell.Row, endCol = cell.Column + 1; + // while (mergedCells.ContainsKey(ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol))) + // { + // ExcelCell next = mergedCells[ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)]; + // if (cell.MergeId != next.MergeId) + // { + // break; + // } + // endCol++; + // } + + // while (IsMerged(mergedCells, Destination.Worksheet, endRow, startCol, endCol - 1, cell)) + // { + // endRow++; + // } + + // mergedAddresses.Add(new ExcelAddressBase(startRow, startCol, endRow - 1, endCol - 1)); + // } + // } + // Destination.Worksheet.MergedCells.List.AddRange((from r in mergedAddresses select r.Address)); + // } + //} + + //private bool IsAdded(ExcelCell cell, List<ExcelAddressBase> mergedAddresses) + //{ + // foreach (var address in mergedAddresses) + // { + // if (address.Collide(new ExcelAddressBase(cell.CellAddress)) == eAddressCollition.Inside) + // { + // return true; + // } + // } + // return false; + //} + + //private bool IsMerged(Dictionary<ulong, ExcelCell> mergedCells, ExcelWorksheet worksheet, int row, int startCol, int endCol, ExcelCell cell) + //{ + // for (int col = startCol; col <= endCol; col++) + // { + // if (!mergedCells.ContainsKey(ExcelCell.GetCellID(worksheet.SheetID, row, col))) + // { + // return false; + // } + // else + // { + // ExcelCell next = mergedCells[ExcelCell.GetCellID(worksheet.SheetID, row, col)]; + // if (cell.MergeId != next.MergeId) + // { + // return false; + // } + // } + // } + // return true; + } + + /// <summary> + /// Clear all cells + /// </summary> + public void Clear() { + Delete(this, false); + } + + /// <summary> + /// Creates an array-formula. + /// </summary> + /// <param name="arrayFormula">The formula</param> + public void CreateArrayFormula(string arrayFormula) { + if (Addresses != null) { + throw (new("An Arrayformula can not have more than one address")); + } + Set_SharedFormula(arrayFormula, this, true); + } + + //private void Clear(ExcelAddressBase Range) + //{ + // Clear(Range, true); + //} + internal void Delete(ExcelAddressBase range, bool shift) { + //DeleteCheckMergedCells(Range); + _worksheet.MergedCells.Clear(range); + //First find the start cell + int fromRow, + fromCol; + var d = Worksheet.Dimension; + if (d != null + && range._fromRow <= d._fromRow + && range._toRow + >= d._toRow) //EntireRow? + { + fromRow = 0; + } else { + fromRow = range._fromRow; + } + if (d != null + && range._fromCol <= d._fromCol + && range._toCol + >= d._toCol) //EntireRow? + { + fromCol = 0; + } else { + fromCol = range._fromCol; + } + + var rows = range._toRow - fromRow + 1; + var cols = range._toCol - fromCol + 1; + + _worksheet._values.Delete(fromRow, fromCol, rows, cols, shift); + _worksheet._types.Delete(fromRow, fromCol, rows, cols, shift); + _worksheet._styles.Delete(fromRow, fromCol, rows, cols, shift); + _worksheet._formulas.Delete(fromRow, fromCol, rows, cols, shift); + _worksheet._hyperLinks.Delete(fromRow, fromCol, rows, cols, shift); + _worksheet._flags.Delete(fromRow, fromCol, rows, cols, shift); + _worksheet._commentsStore.Delete(fromRow, fromCol, rows, cols, shift); + + //if(shift) + //{ + // _worksheet.AdjustFormulasRow(fromRow, rows); + //} + + //Clear multi addresses as well + if (Addresses != null) { + foreach (var sub in Addresses) { + Delete(sub, shift); + } + } + } + + private void DeleteCheckMergedCells(ExcelAddressBase range) { + var removeItems = new List<string>(); + foreach (var addr in Worksheet.MergedCells) { + var addrCol = range.Collide(new ExcelAddress(range.WorkSheet, addr)); + if (addrCol != eAddressCollition.No) { + if (addrCol == eAddressCollition.Inside) { + removeItems.Add(addr); + } else { + throw (new InvalidOperationException( + "Can't remove/overwrite a part of cells that are merged")); + } + } + } + foreach (var item in removeItems) { + Worksheet.MergedCells.Remove(item); + } + } + + public void Dispose() {} + + //int _index; + //ulong _toCellId; + //int _enumAddressIx; + private CellsStoreEnumerator<object> cellEnum; + + public IEnumerator<ExcelRangeBase> GetEnumerator() { + Reset(); + return this; + } + + IEnumerator IEnumerable.GetEnumerator() { + Reset(); + return this; + } + + /// <summary> + /// The current range when enumerating + /// </summary> + public ExcelRangeBase Current => new(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column)); + + /// <summary> + /// The current range when enumerating + /// </summary> + object IEnumerator.Current => + new ExcelRangeBase(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column)); + + private int _enumAddressIx = -1; + + public bool MoveNext() { + if (cellEnum.Next()) { + return true; + } + if (_addresses != null) { + _enumAddressIx++; + if (_enumAddressIx < _addresses.Count) { + cellEnum = new( + _worksheet._values, + _addresses[_enumAddressIx]._fromRow, + _addresses[_enumAddressIx]._fromCol, + _addresses[_enumAddressIx]._toRow, + _addresses[_enumAddressIx]._toCol); + return MoveNext(); + } + return false; + } + return false; + } + + public void Reset() { + _enumAddressIx = -1; + cellEnum = new(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol); + } + + //private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol) + //{ + // if (_index >= _worksheet._cells.Count) return; + // ExcelCell cell = _worksheet._cells[_index] as ExcelCell; + // while (cell.Column > toCol || cell.Column < fromCol) + // { + // if (cell.Column < fromCol) + // { + // _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol)); + // } + // else + // { + // _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol)); + // } + + // if (_index < 0) + // { + // _index = ~_index; + // } + // if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId) + // { + // break; + // } + // cell = _worksheet._cells[_index] as ExcelCell; + // } + //} + + //private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol) + //{ + // _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol)); + // _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol); + // if (_index < 0) + // { + // _index = ~_index; + // } + // _index--; + //} }
diff --git a/EPPlus/ExcelRangeCopyOptionFlags.cs b/EPPlus/ExcelRangeCopyOptionFlags.cs index 39853ca..684a49c 100644 --- a/EPPlus/ExcelRangeCopyOptionFlags.cs +++ b/EPPlus/ExcelRangeCopyOptionFlags.cs
@@ -1,16 +1,14 @@ using System; -namespace OfficeOpenXml -{ - /// <summary> - /// Flag enum, specify all flags that you want to exclude from the copy. - /// </summary> - [Flags] - public enum ExcelRangeCopyOptionFlags : int - { - /// <summary> - /// Exclude formulas from being copied - /// </summary> - ExcludeFormulas = 0x1, - } +namespace OfficeOpenXml; + +/// <summary> +/// Flag enum, specify all flags that you want to exclude from the copy. +/// </summary> +[Flags] +public enum ExcelRangeCopyOptionFlags { + /// <summary> + /// Exclude formulas from being copied + /// </summary> + ExcludeFormulas = 0x1, }
diff --git a/EPPlus/ExcelRow.cs b/EPPlus/ExcelRow.cs index 18eaf34..fbb0db3 100644 --- a/EPPlus/ExcelRow.cs +++ b/EPPlus/ExcelRow.cs
@@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan K�llman Initial Release 2009-10-01 @@ -33,352 +33,264 @@ using System; using System.Xml; using OfficeOpenXml.Style; -namespace OfficeOpenXml -{ - internal class RowInternal - { - internal double Height=-1; - internal bool Hidden; - internal bool Collapsed; - internal short OutlineLevel; - internal bool PageBreak; - internal bool Phonetic; - internal bool CustomHeight; - internal int MergeID; - internal RowInternal Clone() - { - return new RowInternal() - { - Height=Height, - Hidden=Hidden, - Collapsed=Collapsed, - OutlineLevel=OutlineLevel, - PageBreak=PageBreak, - Phonetic=Phonetic, - CustomHeight=CustomHeight, - MergeID=MergeID - }; - } + +namespace OfficeOpenXml; + +internal class RowInternal { + internal double Height = -1; + internal bool Hidden; + internal bool Collapsed; + internal short OutlineLevel; + internal bool PageBreak; + internal bool Phonetic; + internal bool CustomHeight; + internal int MergeID; + + internal RowInternal Clone() { + return new() { + Height = Height, + Hidden = Hidden, + Collapsed = Collapsed, + OutlineLevel = OutlineLevel, + PageBreak = PageBreak, + Phonetic = Phonetic, + CustomHeight = CustomHeight, + MergeID = MergeID, + }; + } +} + +/// <summary> +/// Represents an individual row in the spreadsheet. +/// </summary> +public class ExcelRow : IRangeId { + private ExcelWorksheet _worksheet; + private XmlElement _rowElement = null; + + /// <summary> + /// Internal RowID. + /// </summary> + [Obsolete] + public ulong RowID => GetRowId(_worksheet.SheetID, Row); + + /// <summary> + /// Creates a new instance of the ExcelRow class. + /// For internal use only! + /// </summary> + /// <param name="worksheet">The parent worksheet</param> + /// <param name="row">The row number</param> + internal ExcelRow(ExcelWorksheet worksheet, int row) { + _worksheet = worksheet; + Row = row; + } + + /// <summary> + /// Provides access to the node representing the row. + /// </summary> + internal XmlNode Node { + get { return (_rowElement); } + } + + /// <summary> + /// Allows the row to be hidden in the worksheet + /// </summary> + public bool Hidden { + get { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null) { + return false; + } + return r.Hidden; } - /// <summary> - /// Represents an individual row in the spreadsheet. - /// </summary> - public class ExcelRow : IRangeID - { - private ExcelWorksheet _worksheet; - private XmlElement _rowElement = null; - /// <summary> - /// Internal RowID. - /// </summary> - [Obsolete] - public ulong RowID - { - get - { - return GetRowID(_worksheet.SheetID, Row); - } - } - #region ExcelRow Constructor - /// <summary> - /// Creates a new instance of the ExcelRow class. - /// For internal use only! - /// </summary> - /// <param name="Worksheet">The parent worksheet</param> - /// <param name="row">The row number</param> - internal ExcelRow(ExcelWorksheet Worksheet, int row) - { - _worksheet = Worksheet; - Row = row; - } - #endregion - - /// <summary> - /// Provides access to the node representing the row. - /// </summary> - internal XmlNode Node { get { return (_rowElement); } } - - #region ExcelRow Hidden - /// <summary> - /// Allows the row to be hidden in the worksheet - /// </summary> - public bool Hidden - { - get - { - var r=(RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null) - { - return false; - } - else - { - return r.Hidden; - } - } - set - { - var r = GetRowInternal(); - r.Hidden=value; - } - } - #endregion - - #region ExcelRow Height - /// <summary> - /// Sets the height of the row - /// </summary> - public double Height - { - get - { - var r = (RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null || r.Height<0) - { - return _worksheet.DefaultRowHeight; - } - else - { - return r.Height; - } - } - set - { - var r = GetRowInternal(); - r.Height = value; - - if (r.Hidden && value != 0) - { - Hidden = false; - } - r.CustomHeight = (value != _worksheet.DefaultRowHeight); - } - } - /// <summary> - /// Set to true if You don't want the row to Autosize - /// </summary> - public bool CustomHeight - { - get - { - var r = (RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null) - { - return false; - } - else - { - return r.CustomHeight; - } - } - set - { - var r = GetRowInternal(); - r.CustomHeight = value; - } - } - #endregion - - internal string _styleName = ""; - /// <summary> - /// Sets the style for the entire column using a style name. - /// </summary> - public string StyleName - { - get - { - return _styleName; - } - set - { - StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); - _styleName = value; - } - } - /// <summary> - /// Sets the style for the entire row using the style ID. - /// </summary> - public int StyleID - { - get - { - return _worksheet._styles.GetValue(Row, 0); - } - set - { - _worksheet._styles.SetValue(Row, 0, value); - } - } - - /// <summary> - /// Rownumber - /// </summary> - public int Row - { - get; - set; - } - /// <summary> - /// If outline level is set this tells that the row is collapsed - /// </summary> - public bool Collapsed - { - get - { - var r=(RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null) - { - return false; - } - else - { - return r.Collapsed; - } - } - set - { - var r = GetRowInternal(); - r.Collapsed = value; - } - } - /// <summary> - /// Outline level. - /// </summary> - public int OutlineLevel - { - get - { - var r=(RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null) - { - return 0; - } - else - { - return r.OutlineLevel; - } - } - set - { - var r = GetRowInternal(); - r.OutlineLevel=(short)value; - } - } - - private RowInternal GetRowInternal() - { - var r = (RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null) - { - r = new RowInternal(); - _worksheet._values.SetValue(Row, 0, r); - } - return r; - } - /// <summary> - /// Show phonetic Information - /// </summary> - public bool Phonetic - { - get - { - var r = (RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null) - { - return false; - } - else - { - return r.Phonetic; - } - } - set - { - var r = GetRowInternal(); - r.Phonetic = value; - } - } - /// <summary> - /// The Style applied to the whole row. Only effekt cells with no individual style set. - /// Use ExcelRange object if you want to set specific styles. - /// </summary> - public ExcelStyle Style - { - get - { - return _worksheet.Workbook.Styles.GetStyleObject(StyleID,_worksheet.PositionID ,Row.ToString() + ":" + Row.ToString()); - } - } - /// <summary> - /// Adds a manual page break after the row. - /// </summary> - public bool PageBreak - { - get - { - var r = (RowInternal)_worksheet._values.GetValue(Row, 0); - if (r == null) - { - return false; - } - else - { - return r.PageBreak; - } - } - set - { - var r = GetRowInternal(); - r.PageBreak = value; - } - } - public bool Merged - { - get - { - return _worksheet.MergedCells[Row, 0] != null; - } - set - { - _worksheet.MergedCells.Add(new ExcelAddressBase(Row, 1, Row, ExcelPackage.MaxColumns), true); - } - } - internal static ulong GetRowID(int sheetID, int row) - { - return ((ulong)sheetID) + (((ulong)row) << 29); - - } - - #region IRangeID Members - - [Obsolete] - ulong IRangeID.RangeID - { - get - { - return RowID; - } - set - { - Row = ((int)(value >> 29)); - } - } - - #endregion - /// <summary> - /// Copies the current row to a new worksheet - /// </summary> - /// <param name="added">The worksheet where the copy will be created</param> - internal void Clone(ExcelWorksheet added) - { - ExcelRow newRow = added.Row(Row); - newRow.Collapsed = Collapsed; - newRow.Height = Height; - newRow.Hidden = Hidden; - newRow.OutlineLevel = OutlineLevel; - newRow.PageBreak = PageBreak; - newRow.Phonetic = Phonetic; - newRow._styleName = _styleName; - newRow.StyleID = StyleID; - } + set { + var r = GetRowInternal(); + r.Hidden = value; } + } + + /// <summary> + /// Sets the height of the row + /// </summary> + public double Height { + get { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null || r.Height < 0) { + return _worksheet.DefaultRowHeight; + } + return r.Height; + } + set { + var r = GetRowInternal(); + r.Height = value; + + if (r.Hidden && value != 0) { + Hidden = false; + } + r.CustomHeight = (value != _worksheet.DefaultRowHeight); + } + } + + /// <summary> + /// Set to true if You don't want the row to Autosize + /// </summary> + public bool CustomHeight { + get { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null) { + return false; + } + return r.CustomHeight; + } + set { + var r = GetRowInternal(); + r.CustomHeight = value; + } + } + + internal string _styleName = ""; + + /// <summary> + /// Sets the style for the entire column using a style name. + /// </summary> + public string StyleName { + get { return _styleName; } + set { + StyleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); + _styleName = value; + } + } + + /// <summary> + /// Sets the style for the entire row using the style ID. + /// </summary> + public int StyleID { + get { return _worksheet._styles.GetValue(Row, 0); } + set { _worksheet._styles.SetValue(Row, 0, value); } + } + + /// <summary> + /// Rownumber + /// </summary> + public int Row { get; set; } + + /// <summary> + /// If outline level is set this tells that the row is collapsed + /// </summary> + public bool Collapsed { + get { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null) { + return false; + } + return r.Collapsed; + } + set { + var r = GetRowInternal(); + r.Collapsed = value; + } + } + + /// <summary> + /// Outline level. + /// </summary> + public int OutlineLevel { + get { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null) { + return 0; + } + return r.OutlineLevel; + } + set { + var r = GetRowInternal(); + r.OutlineLevel = (short)value; + } + } + + private RowInternal GetRowInternal() { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null) { + r = new(); + _worksheet._values.SetValue(Row, 0, r); + } + return r; + } + + /// <summary> + /// Show phonetic Information + /// </summary> + public bool Phonetic { + get { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null) { + return false; + } + return r.Phonetic; + } + set { + var r = GetRowInternal(); + r.Phonetic = value; + } + } + + /// <summary> + /// The Style applied to the whole row. Only effekt cells with no individual style set. + /// Use ExcelRange object if you want to set specific styles. + /// </summary> + public ExcelStyle Style { + get { + return _worksheet.Workbook.Styles.GetStyleObject( + StyleID, + _worksheet.PositionID, + Row + ":" + Row); + } + } + + /// <summary> + /// Adds a manual page break after the row. + /// </summary> + public bool PageBreak { + get { + var r = (RowInternal)_worksheet._values.GetValue(Row, 0); + if (r == null) { + return false; + } + return r.PageBreak; + } + set { + var r = GetRowInternal(); + r.PageBreak = value; + } + } + + public bool Merged { + get { return _worksheet.MergedCells[Row, 0] != null; } + set { _worksheet.MergedCells.Add(new(Row, 1, Row, ExcelPackage.MaxColumns), true); } + } + + internal static ulong GetRowId(int sheetId, int row) { + return ((ulong)sheetId) + (((ulong)row) << 29); + } + + [Obsolete] + ulong IRangeId.RangeID { + get { return RowID; } + set { Row = ((int)(value >> 29)); } + } + + /// <summary> + /// Copies the current row to a new worksheet + /// </summary> + /// <param name="added">The worksheet where the copy will be created</param> + internal void Clone(ExcelWorksheet added) { + ExcelRow newRow = added.Row(Row); + newRow.Collapsed = Collapsed; + newRow.Height = Height; + newRow.Hidden = Hidden; + newRow.OutlineLevel = OutlineLevel; + newRow.PageBreak = PageBreak; + newRow.Phonetic = Phonetic; + newRow._styleName = _styleName; + newRow.StyleID = StyleID; + } }
diff --git a/EPPlus/ExcelSheetProtection.cs b/EPPlus/ExcelSheetProtection.cs index 2caa7b9..bc7996d 100644 --- a/EPPlus/ExcelSheetProtection.cs +++ b/EPPlus/ExcelSheetProtection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,290 +13,203 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2010-03-14 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System.Xml; -namespace OfficeOpenXml -{ - /// <summary> - /// Sheet protection - ///<seealso cref="ExcelEncryption"/> - ///<seealso cref="ExcelProtection"/> - /// </summary> - public sealed class ExcelSheetProtection : XmlHelper - { - internal ExcelSheetProtection (XmlNamespaceManager nsm, XmlNode topNode,ExcelWorksheet ws) : - base(nsm, topNode) - { - SchemaNodeOrder = ws.SchemaNodeOrder; - } - private const string _isProtectedPath="d:sheetProtection/@sheet"; - /// <summary> - /// If the worksheet is protected. - /// </summary> - public bool IsProtected - { - get - { - return GetXmlNodeBool(_isProtectedPath, false); - } - set - { - SetXmlNodeBool(_isProtectedPath, value, false); - if (value) - { - AllowEditObject = true; - AllowEditScenarios = true; - } - else - { - DeleteAllNode(_isProtectedPath); //delete the whole sheetprotection node - } - } - } - private const string _allowSelectLockedCellsPath = "d:sheetProtection/@selectLockedCells"; - /// <summary> - /// Allow users to select locked cells - /// </summary> - public bool AllowSelectLockedCells - { - get - { - return !GetXmlNodeBool(_allowSelectLockedCellsPath, false); - } - set - { - SetXmlNodeBool(_allowSelectLockedCellsPath, !value, false); - } - } - private const string _allowSelectUnlockedCellsPath = "d:sheetProtection/@selectUnlockedCells"; - /// <summary> - /// Allow users to select unlocked cells - /// </summary> - public bool AllowSelectUnlockedCells - { - get - { - return !GetXmlNodeBool(_allowSelectUnlockedCellsPath, false); - } - set - { - SetXmlNodeBool(_allowSelectUnlockedCellsPath, !value, false); - } - } - private const string _allowObjectPath="d:sheetProtection/@objects"; - /// <summary> - /// Allow users to edit objects - /// </summary> - public bool AllowEditObject - { - get - { - return !GetXmlNodeBool(_allowObjectPath, false); - } - set - { - SetXmlNodeBool(_allowObjectPath, !value, false); - } - } - private const string _allowScenariosPath="d:sheetProtection/@scenarios"; - /// <summary> - /// Allow users to edit senarios - /// </summary> - public bool AllowEditScenarios - { - get - { - return !GetXmlNodeBool(_allowScenariosPath, false); - } - set - { - SetXmlNodeBool(_allowScenariosPath, !value, false); - } - } - private const string _allowFormatCellsPath="d:sheetProtection/@formatCells"; - /// <summary> - /// Allow users to format cells - /// </summary> - public bool AllowFormatCells - { - get - { - return !GetXmlNodeBool(_allowFormatCellsPath, true); - } - set - { - SetXmlNodeBool(_allowFormatCellsPath, !value, true ); - } - } - private const string _allowFormatColumnsPath = "d:sheetProtection/@formatColumns"; - /// <summary> - /// Allow users to Format columns - /// </summary> - public bool AllowFormatColumns - { - get - { - return !GetXmlNodeBool(_allowFormatColumnsPath, true); - } - set - { - SetXmlNodeBool(_allowFormatColumnsPath, !value, true); - } - } - private const string _allowFormatRowsPath = "d:sheetProtection/@formatRows"; - /// <summary> - /// Allow users to Format rows - /// </summary> - public bool AllowFormatRows - { - get - { - return !GetXmlNodeBool(_allowFormatRowsPath, true); - } - set - { - SetXmlNodeBool(_allowFormatRowsPath, !value, true); - } - } +namespace OfficeOpenXml; - private const string _allowInsertColumnsPath = "d:sheetProtection/@insertColumns"; - /// <summary> - /// Allow users to insert columns - /// </summary> - public bool AllowInsertColumns - { - get - { - return !GetXmlNodeBool(_allowInsertColumnsPath, true); - } - set - { - SetXmlNodeBool(_allowInsertColumnsPath, !value, true); - } - } +/// <summary> +/// Sheet protection +///<seealso cref="ExcelEncryption"/> +///<seealso cref="ExcelProtection"/> +/// </summary> +public sealed class ExcelSheetProtection : XmlHelper { + internal ExcelSheetProtection(XmlNamespaceManager nsm, XmlNode topNode, ExcelWorksheet ws) + : base(nsm, topNode) { + SchemaNodeOrder = ws.SchemaNodeOrder; + } - private const string _allowInsertRowsPath = "d:sheetProtection/@insertRows"; - /// <summary> - /// Allow users to Format rows - /// </summary> - public bool AllowInsertRows - { - get - { - return !GetXmlNodeBool(_allowInsertRowsPath, true); - } - set - { - SetXmlNodeBool(_allowInsertRowsPath, !value, true); - } - } - private const string _allowInsertHyperlinksPath = "d:sheetProtection/@insertHyperlinks"; - /// <summary> - /// Allow users to insert hyperlinks - /// </summary> - public bool AllowInsertHyperlinks - { - get - { - return !GetXmlNodeBool(_allowInsertHyperlinksPath, true); - } - set - { - SetXmlNodeBool(_allowInsertHyperlinksPath, !value, true); - } - } - private const string _allowDeleteColumns = "d:sheetProtection/@deleteColumns"; - /// <summary> - /// Allow users to delete columns - /// </summary> - public bool AllowDeleteColumns - { - get - { - return !GetXmlNodeBool(_allowDeleteColumns, true); - } - set - { - SetXmlNodeBool(_allowDeleteColumns, !value, true); - } - } - private const string _allowDeleteRowsPath = "d:sheetProtection/@deleteRows"; - /// <summary> - /// Allow users to delete rows - /// </summary> - public bool AllowDeleteRows - { - get - { - return !GetXmlNodeBool(_allowDeleteRowsPath, true); - } - set - { - SetXmlNodeBool(_allowDeleteRowsPath, !value, true); - } - } + private const string _isProtectedPath = "d:sheetProtection/@sheet"; - private const string _allowSortPath = "d:sheetProtection/@sort"; - /// <summary> - /// Allow users to sort a range - /// </summary> - public bool AllowSort - { - get - { - return !GetXmlNodeBool(_allowSortPath, true); - } - set - { - SetXmlNodeBool(_allowSortPath, !value, true); - } - } - - private const string _allowAutoFilterPath = "d:sheetProtection/@autoFilter"; - /// <summary> - /// Allow users to use autofilters - /// </summary> - public bool AllowAutoFilter - { - get - { - return !GetXmlNodeBool(_allowAutoFilterPath, true); - } - set - { - SetXmlNodeBool(_allowAutoFilterPath, !value, true); - } - } - private const string _allowPivotTablesPath = "d:sheetProtection/@pivotTables"; - /// <summary> - /// Allow users to use pivottables - /// </summary> - public bool AllowPivotTables - { - get - { - return !GetXmlNodeBool(_allowPivotTablesPath, true); - } - set - { - SetXmlNodeBool(_allowPivotTablesPath, !value, true); - } - } + /// <summary> + /// If the worksheet is protected. + /// </summary> + public bool IsProtected { + get => GetXmlNodeBool(_isProtectedPath, false); + set { + SetXmlNodeBool(_isProtectedPath, value, false); + if (value) { + AllowEditObject = true; + AllowEditScenarios = true; + } else { + DeleteAllNode(_isProtectedPath); //delete the whole sheetprotection node + } } + } + + private const string _allowSelectLockedCellsPath = "d:sheetProtection/@selectLockedCells"; + + /// <summary> + /// Allow users to select locked cells + /// </summary> + public bool AllowSelectLockedCells { + get => !GetXmlNodeBool(_allowSelectLockedCellsPath, false); + set => SetXmlNodeBool(_allowSelectLockedCellsPath, !value, false); + } + + private const string _allowSelectUnlockedCellsPath = "d:sheetProtection/@selectUnlockedCells"; + + /// <summary> + /// Allow users to select unlocked cells + /// </summary> + public bool AllowSelectUnlockedCells { + get => !GetXmlNodeBool(_allowSelectUnlockedCellsPath, false); + set => SetXmlNodeBool(_allowSelectUnlockedCellsPath, !value, false); + } + + private const string _allowObjectPath = "d:sheetProtection/@objects"; + + /// <summary> + /// Allow users to edit objects + /// </summary> + public bool AllowEditObject { + get => !GetXmlNodeBool(_allowObjectPath, false); + set => SetXmlNodeBool(_allowObjectPath, !value, false); + } + + private const string _allowScenariosPath = "d:sheetProtection/@scenarios"; + + /// <summary> + /// Allow users to edit senarios + /// </summary> + public bool AllowEditScenarios { + get => !GetXmlNodeBool(_allowScenariosPath, false); + set => SetXmlNodeBool(_allowScenariosPath, !value, false); + } + + private const string _allowFormatCellsPath = "d:sheetProtection/@formatCells"; + + /// <summary> + /// Allow users to format cells + /// </summary> + public bool AllowFormatCells { + get => !GetXmlNodeBool(_allowFormatCellsPath, true); + set => SetXmlNodeBool(_allowFormatCellsPath, !value, true); + } + + private const string _allowFormatColumnsPath = "d:sheetProtection/@formatColumns"; + + /// <summary> + /// Allow users to Format columns + /// </summary> + public bool AllowFormatColumns { + get => !GetXmlNodeBool(_allowFormatColumnsPath, true); + set => SetXmlNodeBool(_allowFormatColumnsPath, !value, true); + } + + private const string _allowFormatRowsPath = "d:sheetProtection/@formatRows"; + + /// <summary> + /// Allow users to Format rows + /// </summary> + public bool AllowFormatRows { + get => !GetXmlNodeBool(_allowFormatRowsPath, true); + set => SetXmlNodeBool(_allowFormatRowsPath, !value, true); + } + + private const string _allowInsertColumnsPath = "d:sheetProtection/@insertColumns"; + + /// <summary> + /// Allow users to insert columns + /// </summary> + public bool AllowInsertColumns { + get => !GetXmlNodeBool(_allowInsertColumnsPath, true); + set => SetXmlNodeBool(_allowInsertColumnsPath, !value, true); + } + + private const string _allowInsertRowsPath = "d:sheetProtection/@insertRows"; + + /// <summary> + /// Allow users to Format rows + /// </summary> + public bool AllowInsertRows { + get => !GetXmlNodeBool(_allowInsertRowsPath, true); + set => SetXmlNodeBool(_allowInsertRowsPath, !value, true); + } + + private const string _allowInsertHyperlinksPath = "d:sheetProtection/@insertHyperlinks"; + + /// <summary> + /// Allow users to insert hyperlinks + /// </summary> + public bool AllowInsertHyperlinks { + get => !GetXmlNodeBool(_allowInsertHyperlinksPath, true); + set => SetXmlNodeBool(_allowInsertHyperlinksPath, !value, true); + } + + private const string _allowDeleteColumns = "d:sheetProtection/@deleteColumns"; + + /// <summary> + /// Allow users to delete columns + /// </summary> + public bool AllowDeleteColumns { + get => !GetXmlNodeBool(_allowDeleteColumns, true); + set => SetXmlNodeBool(_allowDeleteColumns, !value, true); + } + + private const string _allowDeleteRowsPath = "d:sheetProtection/@deleteRows"; + + /// <summary> + /// Allow users to delete rows + /// </summary> + public bool AllowDeleteRows { + get => !GetXmlNodeBool(_allowDeleteRowsPath, true); + set => SetXmlNodeBool(_allowDeleteRowsPath, !value, true); + } + + private const string _allowSortPath = "d:sheetProtection/@sort"; + + /// <summary> + /// Allow users to sort a range + /// </summary> + public bool AllowSort { + get => !GetXmlNodeBool(_allowSortPath, true); + set => SetXmlNodeBool(_allowSortPath, !value, true); + } + + private const string _allowAutoFilterPath = "d:sheetProtection/@autoFilter"; + + /// <summary> + /// Allow users to use autofilters + /// </summary> + public bool AllowAutoFilter { + get => !GetXmlNodeBool(_allowAutoFilterPath, true); + set => SetXmlNodeBool(_allowAutoFilterPath, !value, true); + } + + private const string _allowPivotTablesPath = "d:sheetProtection/@pivotTables"; + + /// <summary> + /// Allow users to use pivottables + /// </summary> + public bool AllowPivotTables { + get => !GetXmlNodeBool(_allowPivotTablesPath, true); + set => SetXmlNodeBool(_allowPivotTablesPath, !value, true); + } }
diff --git a/EPPlus/ExcelStyleCollection.cs b/EPPlus/ExcelStyleCollection.cs index da408fe..6ca76f9 100644 --- a/EPPlus/ExcelStyleCollection.cs +++ b/EPPlus/ExcelStyleCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,132 +13,114 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Xml; -using System.Linq; -namespace OfficeOpenXml -{ - /// <summary> - /// Base collection class for styles. - /// </summary> - /// <typeparam name="T">The style type</typeparam> - public class ExcelStyleCollection<T> : IEnumerable<T> - { - public ExcelStyleCollection() - { - _setNextIdManual = false; - } - bool _setNextIdManual; - public ExcelStyleCollection(bool SetNextIdManual) - { - _setNextIdManual = SetNextIdManual; - } - public XmlNode TopNode { get; set; } - internal List<T> _list = new List<T>(); - Dictionary<string, int> _dic = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase); - internal int NextId=0; - #region IEnumerable<T> Members - public IEnumerator<T> GetEnumerator() - { - return _list.GetEnumerator(); - } +namespace OfficeOpenXml; - #endregion - #region IEnumerable Members +/// <summary> +/// Base collection class for styles. +/// </summary> +/// <typeparam name="T">The style type</typeparam> +public class ExcelStyleCollection<T> : IEnumerable<T> { + public ExcelStyleCollection() { + _setNextIdManual = false; + } - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _list.GetEnumerator(); - } - #endregion - public T this[int PositionID] - { - get - { - return _list[PositionID]; - } - } - public int Count - { - get - { - return _list.Count; - } - } - //internal int Add(T item) - //{ - // _list.Add(item); - // if (_setNextIdManual) NextId++; - // return _list.Count-1; - //} - internal int Add(string key, T item) - { - _list.Add(item); - if (!_dic.ContainsKey(key.ToLower(CultureInfo.InvariantCulture))) _dic.Add(key.ToLower(CultureInfo.InvariantCulture), _list.Count - 1); - if (_setNextIdManual) NextId++; - return _list.Count-1; - } - /// <summary> - /// Finds the key - /// </summary> - /// <param name="key">the key to be found</param> - /// <param name="obj">The found object.</param> - /// <returns>True if found</returns> - internal bool FindByID(string key, ref T obj) - { - if (_dic.ContainsKey(key)) - { - obj = _list[_dic[key.ToLower(CultureInfo.InvariantCulture)]]; - return true; - } - else - { - return false; - } - } - /// <summary> - /// Find Index - /// </summary> - /// <param name="key"></param> - /// <returns></returns> - internal int FindIndexByID(string key) - { - if (_dic.ContainsKey(key)) - { - return _dic[key]; - } - else - { - return int.MinValue; - } - } - internal bool ExistsKey(string key) - { - return _dic.ContainsKey(key); - } - internal void Sort(Comparison<T> c) - { - _list.Sort(c); - } + private bool _setNextIdManual; + + public ExcelStyleCollection(bool setNextIdManual) { + _setNextIdManual = setNextIdManual; + } + + public XmlNode TopNode { get; set; } + + internal List<T> _list = new(); + private Dictionary<string, int> _dic = new(StringComparer.InvariantCultureIgnoreCase); + internal int NextId; + + public IEnumerator<T> GetEnumerator() { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _list.GetEnumerator(); + } + + public T this[int positionId] => _list[positionId]; + + public int Count { + get { return _list.Count; } + } + + //internal int Add(T item) + //{ + // _list.Add(item); + // if (_setNextIdManual) NextId++; + // return _list.Count-1; + //} + internal int Add(string key, T item) { + _list.Add(item); + if (!_dic.ContainsKey(key.ToLower(CultureInfo.InvariantCulture))) { + _dic.Add(key.ToLower(CultureInfo.InvariantCulture), _list.Count - 1); } + if (_setNextIdManual) { + NextId++; + } + return _list.Count - 1; + } + + /// <summary> + /// Finds the key + /// </summary> + /// <param name="key">the key to be found</param> + /// <param name="obj">The found object.</param> + /// <returns>True if found</returns> + internal bool FindById(string key, ref T obj) { + if (_dic.ContainsKey(key)) { + obj = _list[_dic[key.ToLower(CultureInfo.InvariantCulture)]]; + return true; + } + return false; + } + + /// <summary> + /// Find Index + /// </summary> + /// <param name="key"></param> + /// <returns></returns> + internal int FindIndexById(string key) { + if (_dic.ContainsKey(key)) { + return _dic[key]; + } + return int.MinValue; + } + + internal bool ExistsKey(string key) { + return _dic.ContainsKey(key); + } + + internal void Sort(Comparison<T> c) { + _list.Sort(c); + } }
diff --git a/EPPlus/ExcelStyles.cs b/EPPlus/ExcelStyles.cs index cfaed4d..086189d 100644 --- a/EPPlus/ExcelStyles.cs +++ b/EPPlus/ExcelStyles.cs
@@ -13,993 +13,877 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan K�llman Initial Release 2009-10-01 * Jan K�llman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Xml; -using System.Linq; using System.Collections.Generic; -using OfficeOpenXml.Style; -using OfficeOpenXml.Style.XmlAccess; -using OfficeOpenXml.Style.Dxf; +using System.Linq; +using System.Xml; using OfficeOpenXml.ConditionalFormatting; -namespace OfficeOpenXml -{ - /// <summary> - /// Containts all shared cell styles for a workbook - /// </summary> - public sealed class ExcelStyles : XmlHelper - { - const string NumberFormatsPath = "d:styleSheet/d:numFmts"; - const string FontsPath = "d:styleSheet/d:fonts"; - const string FillsPath = "d:styleSheet/d:fills"; - const string BordersPath = "d:styleSheet/d:borders"; - const string CellStyleXfsPath = "d:styleSheet/d:cellStyleXfs"; - const string CellXfsPath = "d:styleSheet/d:cellXfs"; - const string CellStylesPath = "d:styleSheet/d:cellStyles"; - const string dxfsPath = "d:styleSheet/d:dxfs"; +using OfficeOpenXml.Style; +using OfficeOpenXml.Style.Dxf; +using OfficeOpenXml.Style.XmlAccess; - //internal Dictionary<int, ExcelXfs> Styles = new Dictionary<int, ExcelXfs>(); - XmlDocument _styleXml; - ExcelWorkbook _wb; - XmlNamespaceManager _nameSpaceManager; - internal int _nextDfxNumFmtID = 164; - internal ExcelStyles(XmlNamespaceManager NameSpaceManager, XmlDocument xml, ExcelWorkbook wb) : - base(NameSpaceManager, xml) - { - _styleXml=xml; - _wb = wb; - _nameSpaceManager = NameSpaceManager; - SchemaNodeOrder = new string[] { "numFmts", "fonts", "fills", "borders", "cellStyleXfs", "cellXfs", "cellStyles", "dxfs" }; - LoadFromDocument(); +namespace OfficeOpenXml; + +/// <summary> +/// Containts all shared cell styles for a workbook +/// </summary> +public sealed class ExcelStyles : XmlHelper { + private const string _numberFormatsPath = "d:styleSheet/d:numFmts"; + private const string _fontsPath = "d:styleSheet/d:fonts"; + private const string _fillsPath = "d:styleSheet/d:fills"; + private const string _bordersPath = "d:styleSheet/d:borders"; + private const string _cellStyleXfsPath = "d:styleSheet/d:cellStyleXfs"; + private const string _cellXfsPath = "d:styleSheet/d:cellXfs"; + private const string _cellStylesPath = "d:styleSheet/d:cellStyles"; + private const string _dxfsPath = "d:styleSheet/d:dxfs"; + + //internal Dictionary<int, ExcelXfs> Styles = new Dictionary<int, ExcelXfs>(); + private XmlDocument _styleXml; + private ExcelWorkbook _wb; + private XmlNamespaceManager _nameSpaceManager; + internal int _nextDfxNumFmtID = 164; + + internal ExcelStyles(XmlNamespaceManager nameSpaceManager, XmlDocument xml, ExcelWorkbook wb) + : base(nameSpaceManager, xml) { + _styleXml = xml; + _wb = wb; + _nameSpaceManager = nameSpaceManager; + SchemaNodeOrder = new[] { + "numFmts", + "fonts", + "fills", + "borders", + "cellStyleXfs", + "cellXfs", + "cellStyles", + "dxfs", + }; + LoadFromDocument(); + } + + /// <summary> + /// Loads the style XML to memory + /// </summary> + private void LoadFromDocument() { + //NumberFormats + ExcelNumberFormatXml.AddBuildIn(NameSpaceManager, NumberFormats); + XmlNode numNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager); + if (numNode != null) { + foreach (XmlNode n in numNode) { + ExcelNumberFormatXml nf = new ExcelNumberFormatXml(_nameSpaceManager, n); + NumberFormats.Add(nf.Id, nf); + if (nf.NumFmtId >= NumberFormats.NextId) { + NumberFormats.NextId = nf.NumFmtId + 1; } - /// <summary> - /// Loads the style XML to memory - /// </summary> - private void LoadFromDocument() - { - //NumberFormats - ExcelNumberFormatXml.AddBuildIn(NameSpaceManager, NumberFormats); - XmlNode numNode = _styleXml.SelectSingleNode(NumberFormatsPath, _nameSpaceManager); - if (numNode != null) - { - foreach (XmlNode n in numNode) - { - ExcelNumberFormatXml nf = new ExcelNumberFormatXml(_nameSpaceManager, n); - NumberFormats.Add(nf.Id, nf); - if (nf.NumFmtId >= NumberFormats.NextId) NumberFormats.NextId=nf.NumFmtId+1; - } - } - - //Fonts - XmlNode fontNode = _styleXml.SelectSingleNode(FontsPath, _nameSpaceManager); - foreach (XmlNode n in fontNode) - { - ExcelFontXml f = new ExcelFontXml(_nameSpaceManager, n); - Fonts.Add(f.Id, f); - } - - //Fills - XmlNode fillNode = _styleXml.SelectSingleNode(FillsPath, _nameSpaceManager); - foreach (XmlNode n in fillNode) - { - ExcelFillXml f; - if (n.FirstChild != null && n.FirstChild.LocalName == "gradientFill") - { - f = new ExcelGradientFillXml(_nameSpaceManager, n); - } - else - { - f = new ExcelFillXml(_nameSpaceManager, n); - } - Fills.Add(f.Id, f); - } - - //Borders - XmlNode borderNode = _styleXml.SelectSingleNode(BordersPath, _nameSpaceManager); - foreach (XmlNode n in borderNode) - { - ExcelBorderXml b = new ExcelBorderXml(_nameSpaceManager, n); - Borders.Add(b.Id, b); - } - - //cellStyleXfs - XmlNode styleXfsNode = _styleXml.SelectSingleNode(CellStyleXfsPath, _nameSpaceManager); - if (styleXfsNode != null) - { - foreach (XmlNode n in styleXfsNode) - { - ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this); - CellStyleXfs.Add(item.Id, item); - } - } - - XmlNode styleNode = _styleXml.SelectSingleNode(CellXfsPath, _nameSpaceManager); - for (int i = 0; i < styleNode.ChildNodes.Count; i++) - { - XmlNode n = styleNode.ChildNodes[i]; - ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this); - CellXfs.Add(item.Id, item); - } - - //cellStyle - XmlNode namedStyleNode = _styleXml.SelectSingleNode(CellStylesPath, _nameSpaceManager); - if (namedStyleNode != null) - { - foreach (XmlNode n in namedStyleNode) - { - ExcelNamedStyleXml item = new ExcelNamedStyleXml(_nameSpaceManager, n, this); - NamedStyles.Add(item.Name, item); - } - } - - //dxfsPath - XmlNode dxfsNode = _styleXml.SelectSingleNode(dxfsPath, _nameSpaceManager); - if (dxfsNode != null) - { - foreach (XmlNode x in dxfsNode) - { - ExcelDxfStyleConditionalFormatting item = new ExcelDxfStyleConditionalFormatting(_nameSpaceManager, x, this); - Dxfs.Add(item.Id, item); - } - } - } - internal ExcelStyle GetStyleObject(int Id,int PositionID, string Address) - { - if (Id < 0) Id = 0; - return new ExcelStyle(this, PropertyChange, PositionID, Address, Id); - } - /// <summary> - /// Handels changes of properties on the style objects - /// </summary> - /// <param name="sender"></param> - /// <param name="e"></param> - /// <returns></returns> - internal int PropertyChange(StyleBase sender, Style.StyleChangeEventArgs e) - { - var address = new ExcelAddressBase(e.Address); - var ws = _wb.Worksheets[e.PositionID]; - Dictionary<int, int> styleCashe = new Dictionary<int, int>(); - //Set single address - lock (ws._styles) - { - SetStyleAddress(sender, e, address, ws, ref styleCashe); - if (address.Addresses != null) - { - //Handle multiaddresses - foreach (var innerAddress in address.Addresses) - { - SetStyleAddress(sender, e, innerAddress, ws, ref styleCashe); - } - } - } - return 0; - } - - private void SetStyleAddress(StyleBase sender, Style.StyleChangeEventArgs e, ExcelAddressBase address, ExcelWorksheet ws, ref Dictionary<int, int> styleCashe) - { - if (address.Start.Column == 0 || address.Start.Row == 0) - { - throw (new Exception("error address")); - } - //Columns - else if (address.Start.Row == 1 && address.End.Row == ExcelPackage.MaxRows) - { - ExcelColumn column; - int col = address.Start.Column, row = 0; - //Get the startcolumn - if (!ws._values.Exists(0, address.Start.Column)) - { - column = ws.Column(address.Start.Column); - } - else - { - column = (ExcelColumn)ws._values.GetValue(0, address.Start.Column); - } - - - while (column.ColumnMin <= address.End.Column) - { - if (column.ColumnMax > address.End.Column) - { - var newCol = ws.CopyColumn(column, address.End.Column + 1, column.ColumnMax); - column.ColumnMax = address.End.Column; - } - var s = ws._styles.GetValue(0, column.ColumnMin); - if (styleCashe.ContainsKey(s)) - { - ws.SetStyle(0, column.ColumnMin, styleCashe[s]); - } - else - { - ExcelXfs st = CellXfs[s]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(s, newId); - ws.SetStyle(0, column.ColumnMin, newId); - } - - //index++; - - if (!ws._values.NextCell(ref row, ref col) || row > 0) - { - column._columnMax = address.End.Column; - break; - } - else - { - column = (ws._values.GetValue(0, col) as ExcelColumn); - } - } - - if (column._columnMax < address.End.Column) - { - var newCol = ws.Column(column._columnMax + 1) as ExcelColumn; - newCol._columnMax = address.End.Column; - - var s = ws._styles.GetValue(0, column.ColumnMin); - if (styleCashe.ContainsKey(s)) - { - ws.SetStyle(0, column.ColumnMin, styleCashe[s]); - } - else - { - ExcelXfs st = CellXfs[s]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(s, newId); - ws.SetStyle(0, column.ColumnMin, newId); - } - - column._columnMax = address.End.Column; - } - - //Set for individual cells in the span. We loop all cells here since the cells are sorted with columns first. - var cse = new CellsStoreEnumerator<int>(ws._styles, 1, address._fromCol, address._toRow, address._toCol); - while (cse.Next()) - { - if (cse.Column >= address.Start.Column && - cse.Column <= address.End.Column) - { - if (styleCashe.ContainsKey(cse.Value)) - { - ws.SetStyle(cse.Row, cse.Column, styleCashe[cse.Value]); - } - else - { - ExcelXfs st = CellXfs[cse.Value]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(cse.Value, newId); - cse.Value = newId; - //ws.SetStyle(cse.Row, cse.Column, newId); - } - } - } - - //Update cells with styled columns - cse = new CellsStoreEnumerator<int>(ws._styles, 1, 0, address._toRow, 0); - while (cse.Next()) - { - for (int c = address._fromRow; c <= address._toCol; c++) - { - if (!ws._styles.Exists(cse.Row, c)) - { - if (styleCashe.ContainsKey(cse.Value)) - { - ws.SetStyle(cse.Row, c, styleCashe[cse.Value]); - } - else - { - ExcelXfs st = CellXfs[cse.Value]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(cse.Value, newId); - ws.SetStyle(cse.Row, c, newId); - } - } - } - } - } - - //Rows - else if (address.Start.Column == 1 && address.End.Column == ExcelPackage.MaxColumns) - { - for (int rowNum = address.Start.Row; rowNum <= address.End.Row; rowNum++) - { - var s = ws._styles.GetValue(rowNum, 0); - if (s == 0) - { - //iterate all columns and set the row to the style of the last column - var cse = new CellsStoreEnumerator<int>(ws._styles, 0, 1, 0, ExcelPackage.MaxColumns); - while (cse.Next()) - { - s = cse.Value; - var c = ws._values.GetValue(cse.Row, cse.Column) as ExcelColumn; - if (c != null && c.ColumnMax < ExcelPackage.MaxColumns) - { - for (int col = c.ColumnMin; col < c.ColumnMax; col++) - { - if (!ws._styles.Exists(rowNum, col)) - { - ws._styles.SetValue(rowNum, col, s); - } - } - } - } - ws.SetStyle(rowNum, 0, s); - } - if (styleCashe.ContainsKey(s)) - { - ws.SetStyle(rowNum, 0, styleCashe[s]); - } - else - { - ExcelXfs st = CellXfs[s]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(s, newId); - ws._styles.SetValue(rowNum, 0, newId); - ws.SetStyle(rowNum, 0, newId); - } - } - - //Update individual cells - var cse2 = new CellsStoreEnumerator<int>(ws._styles, address._fromRow, address._fromCol, address._toRow, address._toCol); - while (cse2.Next()) - { - var s = cse2.Value; - if (styleCashe.ContainsKey(s)) - { - ws.SetStyle(cse2.Row, cse2.Column, styleCashe[s]); - } - else - { - ExcelXfs st = CellXfs[s]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(s, newId); - cse2.Value = newId; - } - } - - //Update cells with styled rows - cse2 = new CellsStoreEnumerator<int>(ws._styles, 0, 1, 0, address._toCol); - while (cse2.Next()) - { - for (int r = address._fromRow; r <= address._toRow; r++) - { - if (!ws._styles.Exists(r, cse2.Column)) - { - var s = cse2.Value; - if (styleCashe.ContainsKey(s)) - { - ws.SetStyle(r, cse2.Column, styleCashe[s]); - } - else - { - ExcelXfs st = CellXfs[s]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(s, newId); - ws.SetStyle(r, cse2.Column, newId); - } - } - } - } - } - else //Cellrange - { - for (int col = address.Start.Column; col <= address.End.Column; col++) - { - for (int row = address.Start.Row; row <= address.End.Row; row++) - { - var s = GetStyleId(ws, row, col); - if (styleCashe.ContainsKey(s)) - { - ws.SetStyle(row, col, styleCashe[s]); - } - else - { - ExcelXfs st = CellXfs[s]; - int newId = st.GetNewID(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - styleCashe.Add(s, newId); - ws.SetStyle(row, col, newId); - } - } - } - } - } - - internal int GetStyleId(ExcelWorksheet ws, int row, int col) - { - int v=0; - if (ws._styles.Exists(row, col, ref v)) - { - return v; - } - else - { - if (ws._styles.Exists(row, 0, ref v)) //First Row - { - return v; - } - else // then column - { - if (ws._styles.Exists(0, col, ref v)) - { - return v; - } - else - { - int r=0,c=col; - if(ws._values.PrevCell(ref r,ref c)) - { - var column=ws._values.GetValue(0,c) as ExcelColumn; - if (column != null && column.ColumnMax >= col) //Fixes issue 15174 - { - return ws._styles.GetValue(0, c); - } - else - { - return 0; - } - } - else - { - return 0; - } - } - - } - } - - } - /// <summary> - /// Handles property changes on Named styles. - /// </summary> - /// <param name="sender"></param> - /// <param name="e"></param> - /// <returns></returns> - internal int NamedStylePropertyChange(StyleBase sender, Style.StyleChangeEventArgs e) - { - - int index = NamedStyles.FindIndexByID(e.Address); - if (index >= 0) - { - int newId = CellStyleXfs[NamedStyles[index].StyleXfId].GetNewID(CellStyleXfs, sender, e.StyleClass, e.StyleProperty, e.Value); - int prevIx=NamedStyles[index].StyleXfId; - NamedStyles[index].StyleXfId = newId; - NamedStyles[index].Style.Index = newId; - - NamedStyles[index].XfId = int.MinValue; - foreach (var style in CellXfs) - { - if (style.XfId == prevIx) - { - style.XfId = newId; - } - } - } - return 0; - } - public ExcelStyleCollection<ExcelNumberFormatXml> NumberFormats = new ExcelStyleCollection<ExcelNumberFormatXml>(); - public ExcelStyleCollection<ExcelFontXml> Fonts = new ExcelStyleCollection<ExcelFontXml>(); - public ExcelStyleCollection<ExcelFillXml> Fills = new ExcelStyleCollection<ExcelFillXml>(); - public ExcelStyleCollection<ExcelBorderXml> Borders = new ExcelStyleCollection<ExcelBorderXml>(); - public ExcelStyleCollection<ExcelXfs> CellStyleXfs = new ExcelStyleCollection<ExcelXfs>(); - public ExcelStyleCollection<ExcelXfs> CellXfs = new ExcelStyleCollection<ExcelXfs>(); - public ExcelStyleCollection<ExcelNamedStyleXml> NamedStyles = new ExcelStyleCollection<ExcelNamedStyleXml>(); - public ExcelStyleCollection<ExcelDxfStyleConditionalFormatting> Dxfs = new ExcelStyleCollection<ExcelDxfStyleConditionalFormatting>(); - - internal string Id - { - get { return ""; } - } - - public ExcelNamedStyleXml CreateNamedStyle(string name) - { - return CreateNamedStyle(name, null); - } - public ExcelNamedStyleXml CreateNamedStyle(string name, ExcelStyle Template) - { - if (_wb.Styles.NamedStyles.ExistsKey(name)) - { - throw new Exception(string.Format("Key {0} already exists in collection", name)); - } - - ExcelNamedStyleXml style; - style = new ExcelNamedStyleXml(NameSpaceManager, this); - int xfIdCopy, positionID; - ExcelStyles styles; - if (Template == null) - { -// style.Style = new ExcelStyle(this, NamedStylePropertyChange, -1, name, 0); - xfIdCopy = 0; - positionID = -1; - styles = this; - } - else - { - if (Template.PositionID < 0 && Template.Styles==this) - { - xfIdCopy = Template.Index; - positionID=Template.PositionID; - styles = this; - //style.Style = new ExcelStyle(this, NamedStylePropertyChange, Template.PositionID, name, Template.Index); - //style.StyleXfId = Template.Index; - } - else - { - xfIdCopy = Template.XfId; - positionID = -1; - styles = Template.Styles; - } - } - //Clone namedstyle - int styleXfId = CloneStyle(styles, xfIdCopy, true); - //Close cells style - CellStyleXfs[styleXfId].XfId = CellStyleXfs.Count-1; - int xfid = CloneStyle(styles, xfIdCopy, false, true); //Always add a new style (We create a new named style here) - CellXfs[xfid].XfId = styleXfId; - style.Style = new ExcelStyle(this, NamedStylePropertyChange, positionID, name, styleXfId); - style.StyleXfId = styleXfId; - - style.Name = name; - int ix =_wb.Styles.NamedStyles.Add(style.Name, style); - style.Style.SetIndex(ix); - //style.Style.XfId = ix; - return style; - } - public void UpdateXml() - { - RemoveUnusedStyles(); - - //NumberFormat - XmlNode nfNode=_styleXml.SelectSingleNode(NumberFormatsPath, _nameSpaceManager); - if (nfNode == null) - { - CreateNode(NumberFormatsPath, true); - nfNode = _styleXml.SelectSingleNode(NumberFormatsPath, _nameSpaceManager); - } - else - { - nfNode.RemoveAll(); - } - - int count = 0; - int normalIx = NamedStyles.FindIndexByID("Normal"); - if (NamedStyles.Count > 0 && normalIx>=0 && NamedStyles[normalIx].Style.Numberformat.NumFmtID >= 164) - { - ExcelNumberFormatXml nf = NumberFormats[NumberFormats.FindIndexByID(NamedStyles[normalIx].Style.Numberformat.Id)]; - nfNode.AppendChild(nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage.schemaMain))); - nf.newID = count++; - } - foreach (ExcelNumberFormatXml nf in NumberFormats) - { - if(!nf.BuildIn /*&& nf.newID<0*/) //Buildin formats are not updated. - { - nfNode.AppendChild(nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage.schemaMain))); - nf.newID = count; - count++; - } - } - (nfNode as XmlElement).SetAttribute("count", count.ToString()); - - //Font - count=0; - XmlNode fntNode = _styleXml.SelectSingleNode(FontsPath, _nameSpaceManager); - fntNode.RemoveAll(); - - //Normal should be first in the collection - if (NamedStyles.Count > 0 && normalIx >= 0 && NamedStyles[normalIx].Style.Font.Index > 0) - { - ExcelFontXml fnt = Fonts[NamedStyles[normalIx].Style.Font.Index]; - fntNode.AppendChild(fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage.schemaMain))); - fnt.newID = count++; - } - - foreach (ExcelFontXml fnt in Fonts) - { - if (fnt.useCnt > 0/* && fnt.newID<0*/) - { - fntNode.AppendChild(fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage.schemaMain))); - fnt.newID = count; - count++; - } - } - (fntNode as XmlElement).SetAttribute("count", count.ToString()); - - - //Fills - count = 0; - XmlNode fillsNode = _styleXml.SelectSingleNode(FillsPath, _nameSpaceManager); - fillsNode.RemoveAll(); - Fills[0].useCnt = 1; //Must exist (none); - Fills[1].useCnt = 1; //Must exist (gray125); - foreach (ExcelFillXml fill in Fills) - { - if (fill.useCnt > 0) - { - fillsNode.AppendChild(fill.CreateXmlNode(_styleXml.CreateElement("fill", ExcelPackage.schemaMain))); - fill.newID = count; - count++; - } - } - - (fillsNode as XmlElement).SetAttribute("count", count.ToString()); - - //Borders - count = 0; - XmlNode bordersNode = _styleXml.SelectSingleNode(BordersPath, _nameSpaceManager); - bordersNode.RemoveAll(); - Borders[0].useCnt = 1; //Must exist blank; - foreach (ExcelBorderXml border in Borders) - { - if (border.useCnt > 0) - { - bordersNode.AppendChild(border.CreateXmlNode(_styleXml.CreateElement("border", ExcelPackage.schemaMain))); - border.newID = count; - count++; - } - } - (bordersNode as XmlElement).SetAttribute("count", count.ToString()); - - XmlNode styleXfsNode = _styleXml.SelectSingleNode(CellStyleXfsPath, _nameSpaceManager); - if (styleXfsNode == null && NamedStyles.Count > 0) - { - CreateNode(CellStyleXfsPath); - styleXfsNode = _styleXml.SelectSingleNode(CellStyleXfsPath, _nameSpaceManager); - } - if (NamedStyles.Count > 0) - { - styleXfsNode.RemoveAll(); - } - //NamedStyles - count = normalIx > -1 ? 1 : 0; //If we have a normal style, we make sure it's added first. - - XmlNode cellStyleNode = _styleXml.SelectSingleNode(CellStylesPath, _nameSpaceManager); - if(cellStyleNode!=null) - { - cellStyleNode.RemoveAll(); - } - XmlNode cellXfsNode = _styleXml.SelectSingleNode(CellXfsPath, _nameSpaceManager); - cellXfsNode.RemoveAll(); - - if (NamedStyles.Count > 0 && normalIx >= 0) - { - NamedStyles[normalIx].newID = 0; - AddNamedStyle(0, styleXfsNode, cellXfsNode, NamedStyles[normalIx]); - } - foreach (ExcelNamedStyleXml style in NamedStyles) - { - if (!style.Name.Equals("normal", StringComparison.InvariantCultureIgnoreCase)) - { - AddNamedStyle(count++, styleXfsNode, cellXfsNode, style); - } - else - { - style.newID = 0; - } - cellStyleNode.AppendChild(style.CreateXmlNode(_styleXml.CreateElement("cellStyle", ExcelPackage.schemaMain))); - } - if (cellStyleNode!=null) (cellStyleNode as XmlElement).SetAttribute("count", count.ToString()); - if (styleXfsNode != null) (styleXfsNode as XmlElement).SetAttribute("count", count.ToString()); - - //CellStyle - int xfix = 0; - foreach (ExcelXfs xf in CellXfs) - { - if (xf.useCnt > 0 && !(normalIx >= 0 && NamedStyles[normalIx].XfId == xfix)) - { - cellXfsNode.AppendChild(xf.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage.schemaMain))); - xf.newID = count; - count++; - } - xfix++; - } - (cellXfsNode as XmlElement).SetAttribute("count", count.ToString()); - - //Set dxf styling for conditional Formatting - XmlNode dxfsNode = _styleXml.SelectSingleNode(dxfsPath, _nameSpaceManager); - foreach (var ws in _wb.Worksheets) - { - if (ws is ExcelChartsheet) continue; - foreach (var cf in ws.ConditionalFormatting) - { - if (cf.Style.HasValue) - { - int ix = Dxfs.FindIndexByID(cf.Style.Id); - if (ix < 0) - { - ((ExcelConditionalFormattingRule)cf).DxfId = Dxfs.Count; - Dxfs.Add(cf.Style.Id, cf.Style); - var elem = ((XmlDocument)TopNode).CreateElement("d", "dxf", ExcelPackage.schemaMain); - cf.Style.CreateNodes(new XmlHelperInstance(NameSpaceManager, elem), ""); - dxfsNode.AppendChild(elem); - } - else - { - ((ExcelConditionalFormattingRule)cf).DxfId = ix; - } - } - } - } - if (dxfsNode != null) (dxfsNode as XmlElement).SetAttribute("count", Dxfs.Count.ToString()); - } - - private void AddNamedStyle(int id, XmlNode styleXfsNode,XmlNode cellXfsNode, ExcelNamedStyleXml style) - { - var styleXfs = CellStyleXfs[style.StyleXfId]; - styleXfsNode.AppendChild(styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage.schemaMain), true)); - styleXfs.newID = id; - styleXfs.XfId = style.StyleXfId; - - var ix = CellXfs.FindIndexByID(styleXfs.Id); - if (ix < 0) - { - cellXfsNode.AppendChild(styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage.schemaMain))); - } - else - { - if(id<0) CellXfs[ix].XfId = id; - cellXfsNode.AppendChild(CellXfs[ix].CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage.schemaMain))); - CellXfs[ix].useCnt = 0; - CellXfs[ix].newID = id; - } - - if (style.XfId >= 0) - style.XfId = CellXfs[style.XfId].newID; - else - style.XfId = 0; - } - - private void RemoveUnusedStyles() - { - CellXfs[0].useCnt = 1; //First item is allways used. - foreach (ExcelWorksheet sheet in _wb.Worksheets) - { - var cse = new CellsStoreEnumerator<int>(sheet._styles); - while(cse.Next()) - { - var v = cse.Value; - if (v >= 0) - { - CellXfs[v].useCnt++; - } - } - } - foreach (ExcelNamedStyleXml ns in NamedStyles) - { - CellStyleXfs[ns.StyleXfId].useCnt++; - } - - foreach (ExcelXfs xf in CellXfs) - { - if (xf.useCnt > 0) - { - if (xf.FontId >= 0) Fonts[xf.FontId].useCnt++; - if (xf.FillId >= 0) Fills[xf.FillId].useCnt++; - if (xf.BorderId >= 0) Borders[xf.BorderId].useCnt++; - } - } - foreach (ExcelXfs xf in CellStyleXfs) - { - if (xf.useCnt > 0) - { - if (xf.FontId >= 0) Fonts[xf.FontId].useCnt++; - if (xf.FillId >= 0) Fills[xf.FillId].useCnt++; - if (xf.BorderId >= 0) Borders[xf.BorderId].useCnt++; - } - } - } - internal int GetStyleIdFromName(string Name) - { - int i = NamedStyles.FindIndexByID(Name); - if (i >= 0) - { - int id = NamedStyles[i].XfId; - if (id < 0) - { - int styleXfId=NamedStyles[i].StyleXfId; - ExcelXfs newStyle = CellStyleXfs[styleXfId].Copy(); - newStyle.XfId = styleXfId; - id = CellXfs.FindIndexByID(newStyle.Id); - if (id < 0) - { - id = CellXfs.Add(newStyle.Id, newStyle); - } - NamedStyles[i].XfId=id; - } - return id; - } - else - { - return 0; - //throw(new Exception("Named style does not exist")); - } - } - #region XmlHelpFunctions - private int GetXmlNodeInt(XmlNode node) - { - int i; - if (int.TryParse(GetXmlNode(node), out i)) - { - return i; - } - else - { - return 0; - } - } - private string GetXmlNode(XmlNode node) - { - if (node == null) - { - return ""; - } - if (node.Value != null) - { - return node.Value; - } - else - { - return ""; - } - } - -#endregion - internal int CloneStyle(ExcelStyles style, int styleID) - { - return CloneStyle(style, styleID, false, false); - } - internal int CloneStyle(ExcelStyles style, int styleID, bool isNamedStyle) - { - return CloneStyle(style, styleID, isNamedStyle, false); - } - internal int CloneStyle(ExcelStyles style, int styleID, bool isNamedStyle, bool allwaysAdd) - { - ExcelXfs xfs; - lock (style) - { - if (isNamedStyle) - { - xfs = style.CellStyleXfs[styleID]; - } - else - { - xfs = style.CellXfs[styleID]; - } - ExcelXfs newXfs = xfs.Copy(this); - //Numberformat - if (xfs.NumberFormatId > 0) - { - //rake36: Two problems here... - //rake36: 1. the first time through when format stays equal to String.Empty, it adds a string.empty to the list of Number Formats - //rake36: 2. when adding a second sheet, if the numberformatid == 164, it finds the 164 added by previous sheets but was using the array index - //rake36: for the numberformatid - - string format = string.Empty; - foreach (var fmt in style.NumberFormats) - { - if (fmt.NumFmtId == xfs.NumberFormatId) - { - format = fmt.Format; - break; - } - } - //rake36: Don't add another format if it's blank - if (!String.IsNullOrEmpty(format)) - { - int ix = NumberFormats.FindIndexByID(format); - if (ix < 0) - { - var item = new ExcelNumberFormatXml(NameSpaceManager) { Format = format, NumFmtId = NumberFormats.NextId++ }; - NumberFormats.Add(format, item); - //rake36: Use the just added format id - newXfs.NumberFormatId = item.NumFmtId; - } - else - { - //rake36: Use the format id defined by the index... not the index itself - newXfs.NumberFormatId = NumberFormats[ix].NumFmtId; - } - } - } - - //Font - if (xfs.FontId > -1) - { - int ix = Fonts.FindIndexByID(xfs.Font.Id); - if (ix < 0) - { - ExcelFontXml item = style.Fonts[xfs.FontId].Copy(); - ix = Fonts.Add(xfs.Font.Id, item); - } - newXfs.FontId = ix; - } - - //Border - if (xfs.BorderId > -1) - { - int ix = Borders.FindIndexByID(xfs.Border.Id); - if (ix < 0) - { - ExcelBorderXml item = style.Borders[xfs.BorderId].Copy(); - ix = Borders.Add(xfs.Border.Id, item); - } - newXfs.BorderId = ix; - } - - //Fill - if (xfs.FillId > -1) - { - int ix = Fills.FindIndexByID(xfs.Fill.Id); - if (ix < 0) - { - var item = style.Fills[xfs.FillId].Copy(); - ix = Fills.Add(xfs.Fill.Id, item); - } - newXfs.FillId = ix; - } - - //Named style reference - if (xfs.XfId > 0) - { - var id = style.CellStyleXfs[xfs.XfId].Id; - var newId = CellStyleXfs.FindIndexByID(id); - if (newId >= 0) - { - newXfs.XfId = newId; - } - else if(style._wb!=_wb && allwaysAdd==false) //Not the same workbook, copy the namedstyle to the workbook or match the id - { - var nsFind = style.NamedStyles.ToDictionary(d => (d.StyleXfId)); - if (nsFind.ContainsKey(xfs.XfId)) - { - var st = nsFind[xfs.XfId]; - if (NamedStyles.ExistsKey(st.Name)) - { - newXfs.XfId = NamedStyles.FindIndexByID(st.Name); - } - else - { - var ns = CreateNamedStyle(st.Name, st.Style); - newXfs.XfId = NamedStyles.Count - 1; - } - } - } - } - - int index; - if (isNamedStyle) - { - index = CellStyleXfs.Add(newXfs.Id, newXfs); - } - else - { - if (allwaysAdd) - { - index = CellXfs.Add(newXfs.Id, newXfs); - } - else - { - index = CellXfs.FindIndexByID(newXfs.Id); - if (index < 0) - { - index = CellXfs.Add(newXfs.Id, newXfs); - } - } - } - return index; - } - } + } } + + //Fonts + XmlNode fontNode = _styleXml.SelectSingleNode(_fontsPath, _nameSpaceManager); + foreach (XmlNode n in fontNode) { + ExcelFontXml f = new ExcelFontXml(_nameSpaceManager, n); + Fonts.Add(f.Id, f); + } + + //Fills + XmlNode fillNode = _styleXml.SelectSingleNode(_fillsPath, _nameSpaceManager); + foreach (XmlNode n in fillNode) { + ExcelFillXml f; + if (n.FirstChild != null && n.FirstChild.LocalName == "gradientFill") { + f = new ExcelGradientFillXml(_nameSpaceManager, n); + } else { + f = new(_nameSpaceManager, n); + } + Fills.Add(f.Id, f); + } + + //Borders + XmlNode borderNode = _styleXml.SelectSingleNode(_bordersPath, _nameSpaceManager); + foreach (XmlNode n in borderNode) { + ExcelBorderXml b = new ExcelBorderXml(_nameSpaceManager, n); + Borders.Add(b.Id, b); + } + + //cellStyleXfs + XmlNode styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager); + if (styleXfsNode != null) { + foreach (XmlNode n in styleXfsNode) { + ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this); + CellStyleXfs.Add(item.Id, item); + } + } + + XmlNode styleNode = _styleXml.SelectSingleNode(_cellXfsPath, _nameSpaceManager); + for (int i = 0; i < styleNode.ChildNodes.Count; i++) { + XmlNode n = styleNode.ChildNodes[i]; + ExcelXfs item = new ExcelXfs(_nameSpaceManager, n, this); + CellXfs.Add(item.Id, item); + } + + //cellStyle + XmlNode namedStyleNode = _styleXml.SelectSingleNode(_cellStylesPath, _nameSpaceManager); + if (namedStyleNode != null) { + foreach (XmlNode n in namedStyleNode) { + ExcelNamedStyleXml item = new ExcelNamedStyleXml(_nameSpaceManager, n, this); + NamedStyles.Add(item.Name, item); + } + } + + //dxfsPath + XmlNode dxfsNode = _styleXml.SelectSingleNode(_dxfsPath, _nameSpaceManager); + if (dxfsNode != null) { + foreach (XmlNode x in dxfsNode) { + ExcelDxfStyleConditionalFormatting item = new ExcelDxfStyleConditionalFormatting( + _nameSpaceManager, + x, + this); + Dxfs.Add(item.Id, item); + } + } + } + + internal ExcelStyle GetStyleObject(int id, int positionId, string address) { + if (id < 0) { + id = 0; + } + return new(this, PropertyChange, positionId, address, id); + } + + /// <summary> + /// Handels changes of properties on the style objects + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + /// <returns></returns> + internal int PropertyChange(StyleBase sender, StyleChangeEventArgs e) { + var address = new ExcelAddressBase(e.Address); + var ws = _wb.Worksheets[e.PositionID]; + Dictionary<int, int> styleCashe = new Dictionary<int, int>(); + //Set single address + lock (ws._styles) { + SetStyleAddress(sender, e, address, ws, ref styleCashe); + if (address.Addresses != null) { + //Handle multiaddresses + foreach (var innerAddress in address.Addresses) { + SetStyleAddress(sender, e, innerAddress, ws, ref styleCashe); + } + } + } + return 0; + } + + private void SetStyleAddress( + StyleBase sender, + StyleChangeEventArgs e, + ExcelAddressBase address, + ExcelWorksheet ws, + ref Dictionary<int, int> styleCashe) { + if (address.Start.Column == 0 || address.Start.Row == 0) { + throw (new("error address")); + } + //Columns + if (address.Start.Row == 1 && address.End.Row == ExcelPackage.MaxRows) { + ExcelColumn column; + int col = address.Start.Column, + row = 0; + //Get the startcolumn + if (!ws._values.Exists(0, address.Start.Column)) { + column = ws.Column(address.Start.Column); + } else { + column = (ExcelColumn)ws._values.GetValue(0, address.Start.Column); + } + + while (column.ColumnMin <= address.End.Column) { + if (column.ColumnMax > address.End.Column) { + var newCol = ws.CopyColumn(column, address.End.Column + 1, column.ColumnMax); + column.ColumnMax = address.End.Column; + } + var s = ws._styles.GetValue(0, column.ColumnMin); + if (styleCashe.ContainsKey(s)) { + ws.SetStyle(0, column.ColumnMin, styleCashe[s]); + } else { + ExcelXfs st = CellXfs[s]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(s, newId); + ws.SetStyle(0, column.ColumnMin, newId); + } + + //index++; + + if (!ws._values.NextCell(ref row, ref col) || row > 0) { + column._columnMax = address.End.Column; + break; + } + column = (ws._values.GetValue(0, col) as ExcelColumn); + } + + if (column._columnMax < address.End.Column) { + var newCol = ws.Column(column._columnMax + 1); + newCol._columnMax = address.End.Column; + + var s = ws._styles.GetValue(0, column.ColumnMin); + if (styleCashe.ContainsKey(s)) { + ws.SetStyle(0, column.ColumnMin, styleCashe[s]); + } else { + ExcelXfs st = CellXfs[s]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(s, newId); + ws.SetStyle(0, column.ColumnMin, newId); + } + + column._columnMax = address.End.Column; + } + + //Set for individual cells in the span. We loop all cells here since the cells are sorted with columns first. + var cse = new CellsStoreEnumerator<int>( + ws._styles, + 1, + address._fromCol, + address._toRow, + address._toCol); + while (cse.Next()) { + if (cse.Column >= address.Start.Column && cse.Column <= address.End.Column) { + if (styleCashe.ContainsKey(cse.Value)) { + ws.SetStyle(cse.Row, cse.Column, styleCashe[cse.Value]); + } else { + ExcelXfs st = CellXfs[cse.Value]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(cse.Value, newId); + cse.Value = newId; + //ws.SetStyle(cse.Row, cse.Column, newId); + } + } + } + + //Update cells with styled columns + cse = new(ws._styles, 1, 0, address._toRow, 0); + while (cse.Next()) { + for (int c = address._fromRow; c <= address._toCol; c++) { + if (!ws._styles.Exists(cse.Row, c)) { + if (styleCashe.ContainsKey(cse.Value)) { + ws.SetStyle(cse.Row, c, styleCashe[cse.Value]); + } else { + ExcelXfs st = CellXfs[cse.Value]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(cse.Value, newId); + ws.SetStyle(cse.Row, c, newId); + } + } + } + } + } + //Rows + else if (address.Start.Column == 1 && address.End.Column == ExcelPackage.MaxColumns) { + for (int rowNum = address.Start.Row; rowNum <= address.End.Row; rowNum++) { + var s = ws._styles.GetValue(rowNum, 0); + if (s == 0) { + //iterate all columns and set the row to the style of the last column + var cse = new CellsStoreEnumerator<int>(ws._styles, 0, 1, 0, ExcelPackage.MaxColumns); + while (cse.Next()) { + s = cse.Value; + var c = ws._values.GetValue(cse.Row, cse.Column) as ExcelColumn; + if (c != null && c.ColumnMax < ExcelPackage.MaxColumns) { + for (int col = c.ColumnMin; col < c.ColumnMax; col++) { + if (!ws._styles.Exists(rowNum, col)) { + ws._styles.SetValue(rowNum, col, s); + } + } + } + } + ws.SetStyle(rowNum, 0, s); + } + if (styleCashe.ContainsKey(s)) { + ws.SetStyle(rowNum, 0, styleCashe[s]); + } else { + ExcelXfs st = CellXfs[s]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(s, newId); + ws._styles.SetValue(rowNum, 0, newId); + ws.SetStyle(rowNum, 0, newId); + } + } + + //Update individual cells + var cse2 = new CellsStoreEnumerator<int>( + ws._styles, + address._fromRow, + address._fromCol, + address._toRow, + address._toCol); + while (cse2.Next()) { + var s = cse2.Value; + if (styleCashe.ContainsKey(s)) { + ws.SetStyle(cse2.Row, cse2.Column, styleCashe[s]); + } else { + ExcelXfs st = CellXfs[s]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(s, newId); + cse2.Value = newId; + } + } + + //Update cells with styled rows + cse2 = new(ws._styles, 0, 1, 0, address._toCol); + while (cse2.Next()) { + for (int r = address._fromRow; r <= address._toRow; r++) { + if (!ws._styles.Exists(r, cse2.Column)) { + var s = cse2.Value; + if (styleCashe.ContainsKey(s)) { + ws.SetStyle(r, cse2.Column, styleCashe[s]); + } else { + ExcelXfs st = CellXfs[s]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(s, newId); + ws.SetStyle(r, cse2.Column, newId); + } + } + } + } + } else //Cellrange + { + for (int col = address.Start.Column; col <= address.End.Column; col++) { + for (int row = address.Start.Row; row <= address.End.Row; row++) { + var s = GetStyleId(ws, row, col); + if (styleCashe.ContainsKey(s)) { + ws.SetStyle(row, col, styleCashe[s]); + } else { + ExcelXfs st = CellXfs[s]; + int newId = st.GetNewId(CellXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + styleCashe.Add(s, newId); + ws.SetStyle(row, col, newId); + } + } + } + } + } + + internal int GetStyleId(ExcelWorksheet ws, int row, int col) { + int v = 0; + if (ws._styles.Exists(row, col, ref v)) { + return v; + } + if (ws._styles.Exists( + row, + 0, + ref v)) //First Row + { + return v; + } // then column + if (ws._styles.Exists(0, col, ref v)) { + return v; + } + int r = 0, + c = col; + if (ws._values.PrevCell(ref r, ref c)) { + var column = ws._values.GetValue(0, c) as ExcelColumn; + if (column != null + && column.ColumnMax + >= col) //Fixes issue 15174 + { + return ws._styles.GetValue(0, c); + } + return 0; + } + return 0; + } + + /// <summary> + /// Handles property changes on Named styles. + /// </summary> + /// <param name="sender"></param> + /// <param name="e"></param> + /// <returns></returns> + internal int NamedStylePropertyChange(StyleBase sender, StyleChangeEventArgs e) { + int index = NamedStyles.FindIndexById(e.Address); + if (index >= 0) { + int newId = CellStyleXfs[NamedStyles[index].StyleXfId] + .GetNewId(CellStyleXfs, sender, e.StyleClass, e.StyleProperty, e.Value); + int prevIx = NamedStyles[index].StyleXfId; + NamedStyles[index].StyleXfId = newId; + NamedStyles[index].Style.Index = newId; + + NamedStyles[index].XfId = int.MinValue; + foreach (var style in CellXfs) { + if (style.XfId == prevIx) { + style.XfId = newId; + } + } + } + return 0; + } + + public ExcelStyleCollection<ExcelNumberFormatXml> NumberFormats = new(); + public ExcelStyleCollection<ExcelFontXml> Fonts = new(); + public ExcelStyleCollection<ExcelFillXml> Fills = new(); + public ExcelStyleCollection<ExcelBorderXml> Borders = new(); + public ExcelStyleCollection<ExcelXfs> CellStyleXfs = new(); + public ExcelStyleCollection<ExcelXfs> CellXfs = new(); + public ExcelStyleCollection<ExcelNamedStyleXml> NamedStyles = new(); + public ExcelStyleCollection<ExcelDxfStyleConditionalFormatting> Dxfs = new(); + + internal string Id => ""; + + public ExcelNamedStyleXml CreateNamedStyle(string name) { + return CreateNamedStyle(name, null); + } + + public ExcelNamedStyleXml CreateNamedStyle(string name, ExcelStyle template) { + if (_wb.Styles.NamedStyles.ExistsKey(name)) { + throw new(string.Format("Key {0} already exists in collection", name)); + } + + ExcelNamedStyleXml style; + style = new(NameSpaceManager, this); + int xfIdCopy, + positionId; + ExcelStyles styles; + if (template == null) { + // style.Style = new ExcelStyle(this, NamedStylePropertyChange, -1, name, 0); + xfIdCopy = 0; + positionId = -1; + styles = this; + } else { + if (template.PositionID < 0 && template.Styles == this) { + xfIdCopy = template.Index; + positionId = template.PositionID; + styles = this; + //style.Style = new ExcelStyle(this, NamedStylePropertyChange, Template.PositionID, name, Template.Index); + //style.StyleXfId = Template.Index; + } else { + xfIdCopy = template.XfId; + positionId = -1; + styles = template.Styles; + } + } + //Clone namedstyle + int styleXfId = CloneStyle(styles, xfIdCopy, true); + //Close cells style + CellStyleXfs[styleXfId].XfId = CellStyleXfs.Count - 1; + int xfid = CloneStyle(styles, xfIdCopy, false, true); //Always add a new style (We create a new named style here) + CellXfs[xfid].XfId = styleXfId; + style.Style = new(this, NamedStylePropertyChange, positionId, name, styleXfId); + style.StyleXfId = styleXfId; + + style.Name = name; + int ix = _wb.Styles.NamedStyles.Add(style.Name, style); + style.Style.SetIndex(ix); + //style.Style.XfId = ix; + return style; + } + + public void UpdateXml() { + RemoveUnusedStyles(); + + //NumberFormat + XmlNode nfNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager); + if (nfNode == null) { + CreateNode(_numberFormatsPath, true); + nfNode = _styleXml.SelectSingleNode(_numberFormatsPath, _nameSpaceManager); + } else { + nfNode.RemoveAll(); + } + + int count = 0; + int normalIx = NamedStyles.FindIndexById("Normal"); + if (NamedStyles.Count > 0 + && normalIx >= 0 + && NamedStyles[normalIx].Style.Numberformat.NumFmtID >= 164) { + ExcelNumberFormatXml nf = NumberFormats[NumberFormats.FindIndexById( + NamedStyles[normalIx].Style.Numberformat.Id)]; + nfNode.AppendChild( + nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage._schemaMain))); + nf.newID = count++; + } + foreach (ExcelNumberFormatXml nf in NumberFormats) { + if (!nf.BuildIn /*&& nf.newID<0*/) //Buildin formats are not updated. + { + nfNode.AppendChild( + nf.CreateXmlNode(_styleXml.CreateElement("numFmt", ExcelPackage._schemaMain))); + nf.newID = count; + count++; + } + } + (nfNode as XmlElement).SetAttribute("count", count.ToString()); + + //Font + count = 0; + XmlNode fntNode = _styleXml.SelectSingleNode(_fontsPath, _nameSpaceManager); + fntNode.RemoveAll(); + + //Normal should be first in the collection + if (NamedStyles.Count > 0 && normalIx >= 0 && NamedStyles[normalIx].Style.Font.Index > 0) { + ExcelFontXml fnt = Fonts[NamedStyles[normalIx].Style.Font.Index]; + fntNode.AppendChild( + fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage._schemaMain))); + fnt.newID = count++; + } + + foreach (ExcelFontXml fnt in Fonts) { + if (fnt.useCnt + > 0 /* && fnt.newID<0*/) { + fntNode.AppendChild( + fnt.CreateXmlNode(_styleXml.CreateElement("font", ExcelPackage._schemaMain))); + fnt.newID = count; + count++; + } + } + (fntNode as XmlElement).SetAttribute("count", count.ToString()); + + //Fills + count = 0; + XmlNode fillsNode = _styleXml.SelectSingleNode(_fillsPath, _nameSpaceManager); + fillsNode.RemoveAll(); + Fills[0].useCnt = 1; //Must exist (none); + Fills[1].useCnt = 1; //Must exist (gray125); + foreach (ExcelFillXml fill in Fills) { + if (fill.useCnt > 0) { + fillsNode.AppendChild( + fill.CreateXmlNode(_styleXml.CreateElement("fill", ExcelPackage._schemaMain))); + fill.newID = count; + count++; + } + } + + (fillsNode as XmlElement).SetAttribute("count", count.ToString()); + + //Borders + count = 0; + XmlNode bordersNode = _styleXml.SelectSingleNode(_bordersPath, _nameSpaceManager); + bordersNode.RemoveAll(); + Borders[0].useCnt = 1; //Must exist blank; + foreach (ExcelBorderXml border in Borders) { + if (border.useCnt > 0) { + bordersNode.AppendChild( + border.CreateXmlNode(_styleXml.CreateElement("border", ExcelPackage._schemaMain))); + border.newID = count; + count++; + } + } + (bordersNode as XmlElement).SetAttribute("count", count.ToString()); + + XmlNode styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager); + if (styleXfsNode == null && NamedStyles.Count > 0) { + CreateNode(_cellStyleXfsPath); + styleXfsNode = _styleXml.SelectSingleNode(_cellStyleXfsPath, _nameSpaceManager); + } + if (NamedStyles.Count > 0) { + styleXfsNode.RemoveAll(); + } + //NamedStyles + count = normalIx > -1 ? 1 : 0; //If we have a normal style, we make sure it's added first. + + XmlNode cellStyleNode = _styleXml.SelectSingleNode(_cellStylesPath, _nameSpaceManager); + if (cellStyleNode != null) { + cellStyleNode.RemoveAll(); + } + XmlNode cellXfsNode = _styleXml.SelectSingleNode(_cellXfsPath, _nameSpaceManager); + cellXfsNode.RemoveAll(); + + if (NamedStyles.Count > 0 && normalIx >= 0) { + NamedStyles[normalIx].newID = 0; + AddNamedStyle(0, styleXfsNode, cellXfsNode, NamedStyles[normalIx]); + } + foreach (ExcelNamedStyleXml style in NamedStyles) { + if (!style.Name.Equals("normal", StringComparison.InvariantCultureIgnoreCase)) { + AddNamedStyle(count++, styleXfsNode, cellXfsNode, style); + } else { + style.newID = 0; + } + cellStyleNode.AppendChild( + style.CreateXmlNode(_styleXml.CreateElement("cellStyle", ExcelPackage._schemaMain))); + } + if (cellStyleNode != null) { + (cellStyleNode as XmlElement).SetAttribute("count", count.ToString()); + } + if (styleXfsNode != null) { + (styleXfsNode as XmlElement).SetAttribute("count", count.ToString()); + } + + //CellStyle + int xfix = 0; + foreach (ExcelXfs xf in CellXfs) { + if (xf.useCnt > 0 && !(normalIx >= 0 && NamedStyles[normalIx].XfId == xfix)) { + cellXfsNode.AppendChild( + xf.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain))); + xf.newID = count; + count++; + } + xfix++; + } + (cellXfsNode as XmlElement).SetAttribute("count", count.ToString()); + + //Set dxf styling for conditional Formatting + XmlNode dxfsNode = _styleXml.SelectSingleNode(_dxfsPath, _nameSpaceManager); + foreach (var ws in _wb.Worksheets) { + if (ws is ExcelChartsheet) { + continue; + } + foreach (var cf in ws.ConditionalFormatting) { + if (cf.Style.HasValue) { + int ix = Dxfs.FindIndexById(cf.Style.Id); + if (ix < 0) { + ((ExcelConditionalFormattingRule)cf).DxfId = Dxfs.Count; + Dxfs.Add(cf.Style.Id, cf.Style); + var elem = ((XmlDocument)TopNode).CreateElement("d", "dxf", ExcelPackage._schemaMain); + cf.Style.CreateNodes(new XmlHelperInstance(NameSpaceManager, elem), ""); + dxfsNode.AppendChild(elem); + } else { + ((ExcelConditionalFormattingRule)cf).DxfId = ix; + } + } + } + } + if (dxfsNode != null) { + (dxfsNode as XmlElement).SetAttribute("count", Dxfs.Count.ToString()); + } + } + + private void AddNamedStyle( + int id, + XmlNode styleXfsNode, + XmlNode cellXfsNode, + ExcelNamedStyleXml style) { + var styleXfs = CellStyleXfs[style.StyleXfId]; + styleXfsNode.AppendChild( + styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain), true)); + styleXfs.newID = id; + styleXfs.XfId = style.StyleXfId; + + var ix = CellXfs.FindIndexById(styleXfs.Id); + if (ix < 0) { + cellXfsNode.AppendChild( + styleXfs.CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain))); + } else { + if (id < 0) { + CellXfs[ix].XfId = id; + } + cellXfsNode.AppendChild( + CellXfs[ix].CreateXmlNode(_styleXml.CreateElement("xf", ExcelPackage._schemaMain))); + CellXfs[ix].useCnt = 0; + CellXfs[ix].newID = id; + } + + if (style.XfId >= 0) { + style.XfId = CellXfs[style.XfId].newID; + } else { + style.XfId = 0; + } + } + + private void RemoveUnusedStyles() { + CellXfs[0].useCnt = 1; //First item is allways used. + foreach (ExcelWorksheet sheet in _wb.Worksheets) { + var cse = new CellsStoreEnumerator<int>(sheet._styles); + while (cse.Next()) { + var v = cse.Value; + if (v >= 0) { + CellXfs[v].useCnt++; + } + } + } + foreach (ExcelNamedStyleXml ns in NamedStyles) { + CellStyleXfs[ns.StyleXfId].useCnt++; + } + + foreach (ExcelXfs xf in CellXfs) { + if (xf.useCnt > 0) { + if (xf.FontId >= 0) { + Fonts[xf.FontId].useCnt++; + } + if (xf.FillId >= 0) { + Fills[xf.FillId].useCnt++; + } + if (xf.BorderId >= 0) { + Borders[xf.BorderId].useCnt++; + } + } + } + foreach (ExcelXfs xf in CellStyleXfs) { + if (xf.useCnt > 0) { + if (xf.FontId >= 0) { + Fonts[xf.FontId].useCnt++; + } + if (xf.FillId >= 0) { + Fills[xf.FillId].useCnt++; + } + if (xf.BorderId >= 0) { + Borders[xf.BorderId].useCnt++; + } + } + } + } + + internal int GetStyleIdFromName(string name) { + int i = NamedStyles.FindIndexById(name); + if (i >= 0) { + int id = NamedStyles[i].XfId; + if (id < 0) { + int styleXfId = NamedStyles[i].StyleXfId; + ExcelXfs newStyle = CellStyleXfs[styleXfId].Copy(); + newStyle.XfId = styleXfId; + id = CellXfs.FindIndexById(newStyle.Id); + if (id < 0) { + id = CellXfs.Add(newStyle.Id, newStyle); + } + NamedStyles[i].XfId = id; + } + return id; + } + return 0; + //throw(new Exception("Named style does not exist")); + } + + private int GetXmlNodeInt(XmlNode node) { + int i; + if (int.TryParse(GetXmlNode(node), out i)) { + return i; + } + return 0; + } + + private string GetXmlNode(XmlNode node) { + if (node == null) { + return ""; + } + if (node.Value != null) { + return node.Value; + } + return ""; + } + + internal int CloneStyle(ExcelStyles style, int styleId) { + return CloneStyle(style, styleId, false, false); + } + + internal int CloneStyle(ExcelStyles style, int styleId, bool isNamedStyle) { + return CloneStyle(style, styleId, isNamedStyle, false); + } + + internal int CloneStyle(ExcelStyles style, int styleId, bool isNamedStyle, bool allwaysAdd) { + ExcelXfs xfs; + lock (style) { + if (isNamedStyle) { + xfs = style.CellStyleXfs[styleId]; + } else { + xfs = style.CellXfs[styleId]; + } + ExcelXfs newXfs = xfs.Copy(this); + //Numberformat + if (xfs.NumberFormatId > 0) { + //rake36: Two problems here... + //rake36: 1. the first time through when format stays equal to String.Empty, it adds a string.empty to the list of Number Formats + //rake36: 2. when adding a second sheet, if the numberformatid == 164, it finds the 164 added by previous sheets but was using the array index + //rake36: for the numberformatid + + string format = string.Empty; + foreach (var fmt in style.NumberFormats) { + if (fmt.NumFmtId == xfs.NumberFormatId) { + format = fmt.Format; + break; + } + } + //rake36: Don't add another format if it's blank + if (!String.IsNullOrEmpty(format)) { + int ix = NumberFormats.FindIndexById(format); + if (ix < 0) { + var item = new ExcelNumberFormatXml(NameSpaceManager) { + Format = format, + NumFmtId = NumberFormats.NextId++, + }; + NumberFormats.Add(format, item); + //rake36: Use the just added format id + newXfs.NumberFormatId = item.NumFmtId; + } else { + //rake36: Use the format id defined by the index... not the index itself + newXfs.NumberFormatId = NumberFormats[ix].NumFmtId; + } + } + } + + //Font + if (xfs.FontId > -1) { + int ix = Fonts.FindIndexById(xfs.Font.Id); + if (ix < 0) { + ExcelFontXml item = style.Fonts[xfs.FontId].Copy(); + ix = Fonts.Add(xfs.Font.Id, item); + } + newXfs.FontId = ix; + } + + //Border + if (xfs.BorderId > -1) { + int ix = Borders.FindIndexById(xfs.Border.Id); + if (ix < 0) { + ExcelBorderXml item = style.Borders[xfs.BorderId].Copy(); + ix = Borders.Add(xfs.Border.Id, item); + } + newXfs.BorderId = ix; + } + + //Fill + if (xfs.FillId > -1) { + int ix = Fills.FindIndexById(xfs.Fill.Id); + if (ix < 0) { + var item = style.Fills[xfs.FillId].Copy(); + ix = Fills.Add(xfs.Fill.Id, item); + } + newXfs.FillId = ix; + } + + //Named style reference + if (xfs.XfId > 0) { + var id = style.CellStyleXfs[xfs.XfId].Id; + var newId = CellStyleXfs.FindIndexById(id); + if (newId >= 0) { + newXfs.XfId = newId; + } else if (style._wb != _wb + && allwaysAdd + == false) //Not the same workbook, copy the namedstyle to the workbook or match the id + { + var nsFind = style.NamedStyles.ToDictionary(d => (d.StyleXfId)); + if (nsFind.ContainsKey(xfs.XfId)) { + var st = nsFind[xfs.XfId]; + if (NamedStyles.ExistsKey(st.Name)) { + newXfs.XfId = NamedStyles.FindIndexById(st.Name); + } else { + var ns = CreateNamedStyle(st.Name, st.Style); + newXfs.XfId = NamedStyles.Count - 1; + } + } + } + } + + int index; + if (isNamedStyle) { + index = CellStyleXfs.Add(newXfs.Id, newXfs); + } else { + if (allwaysAdd) { + index = CellXfs.Add(newXfs.Id, newXfs); + } else { + index = CellXfs.FindIndexById(newXfs.Id); + if (index < 0) { + index = CellXfs.Add(newXfs.Id, newXfs); + } + } + } + return index; + } + } }
diff --git a/EPPlus/ExcelTextFormat.cs b/EPPlus/ExcelTextFormat.cs index 0484925..83b0c59 100644 --- a/EPPlus/ExcelTextFormat.cs +++ b/EPPlus/ExcelTextFormat.cs
@@ -13,119 +13,127 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -using System.Globalization; -namespace OfficeOpenXml -{ - /// <summary> - /// Discribes a column when reading a text using the ExcelRangeBase.LoadFromText method - /// </summary> - public enum eDataTypes - { - /// <summary> - /// Let the the import decide. - /// </summary> - Unknown, - /// <summary> - /// Always a string. - /// </summary> - String, - /// <summary> - /// Try to convert it to a number. If it fails then add it as a string. - /// </summary> - Number, - /// <summary> - /// Try to convert it to a date. If it fails then add it as a string. - /// </summary> - DateTime, - /// <summary> - /// Try to convert it to a number and divide with 100. - /// Removes any tailing percent sign (%). If it fails then add it as a string. - /// </summary> - Percent - } - /// <summary> - /// Describes how to split a CSV text. Used by the ExcelRange.LoadFromText method - /// </summary> - public class ExcelTextFormat - { - /// <summary> - /// Describes how to split a CSV text - /// - /// Default values - /// <list> - /// <listheader><term>Property</term><description>Value</description></listheader> - /// <item><term>Delimiter</term><description>,</description></item> - /// <item><term>TextQualifier</term><description>None (\0)</description></item> - /// <item><term>EOL</term><description>CRLF</description></item> - /// <item><term>Culture</term><description>CultureInfo.InvariantCulture</description></item> - /// <item><term>DataTypes</term><description>End of line default CRLF</description></item> - /// <item><term>SkipLinesBeginning</term><description>0</description></item> - /// <item><term>SkipLinesEnd</term><description>0</description></item> - /// <item><term>Encoding</term><description>Encoding.ASCII</description></item> - /// </list> - /// </summary> - public ExcelTextFormat() - { - Delimiter = ','; - TextQualifier = '\0'; - EOL = "\r\n"; - Culture = CultureInfo.InvariantCulture; - DataTypes=null; - SkipLinesBeginning = 0; - SkipLinesEnd = 0; - Encoding=Encoding.ASCII; - } - /// <summary> - /// Delimiter character - /// </summary> - public char Delimiter { get; set; } - /// <summary> - /// Text qualifier character - /// </summary> - public char TextQualifier {get; set; } - /// <summary> - /// End of line characters. Default CRLF - /// </summary> - public string EOL { get; set; } - /// <summary> - /// Datatypes list for each column (if column is not present Unknown is assumed) - /// </summary> - public eDataTypes[] DataTypes { get; set; } - /// <summary> - /// Culture used when parsing. Default CultureInfo.InvariantCulture - /// </summary> - public CultureInfo Culture {get; set; } - /// <summary> - /// Number of lines skiped in the begining of the file. Default 0. - /// </summary> - public int SkipLinesBeginning { get; set; } - /// <summary> - /// Number of lines skiped at the end of the file. Default 0. - /// </summary> - public int SkipLinesEnd { get; set; } - /// <summary> - /// Only used when reading files from disk using a FileInfo object. Default AscII - /// </summary> - public Encoding Encoding { get; set; } - } +using System.Globalization; +using System.Text; + +namespace OfficeOpenXml; + +/// <summary> +/// Discribes a column when reading a text using the ExcelRangeBase.LoadFromText method +/// </summary> +public enum eDataTypes { + /// <summary> + /// Let the the import decide. + /// </summary> + Unknown, + + /// <summary> + /// Always a string. + /// </summary> + String, + + /// <summary> + /// Try to convert it to a number. If it fails then add it as a string. + /// </summary> + Number, + + /// <summary> + /// Try to convert it to a date. If it fails then add it as a string. + /// </summary> + DateTime, + + /// <summary> + /// Try to convert it to a number and divide with 100. + /// Removes any tailing percent sign (%). If it fails then add it as a string. + /// </summary> + Percent, +} + +/// <summary> +/// Describes how to split a CSV text. Used by the ExcelRange.LoadFromText method +/// </summary> +public class ExcelTextFormat { + /// <summary> + /// Describes how to split a CSV text + /// + /// Default values + /// <list> + /// <listheader><term>Property</term><description>Value</description></listheader> + /// <item><term>Delimiter</term><description>,</description></item> + /// <item><term>TextQualifier</term><description>None (\0)</description></item> + /// <item><term>EOL</term><description>CRLF</description></item> + /// <item><term>Culture</term><description>CultureInfo.InvariantCulture</description></item> + /// <item><term>DataTypes</term><description>End of line default CRLF</description></item> + /// <item><term>SkipLinesBeginning</term><description>0</description></item> + /// <item><term>SkipLinesEnd</term><description>0</description></item> + /// <item><term>Encoding</term><description>Encoding.ASCII</description></item> + /// </list> + /// </summary> + public ExcelTextFormat() { + Delimiter = ','; + TextQualifier = '\0'; + EOL = "\r\n"; + Culture = CultureInfo.InvariantCulture; + DataTypes = null; + SkipLinesBeginning = 0; + SkipLinesEnd = 0; + Encoding = Encoding.ASCII; + } + + /// <summary> + /// Delimiter character + /// </summary> + public char Delimiter { get; set; } + + /// <summary> + /// Text qualifier character + /// </summary> + public char TextQualifier { get; set; } + + /// <summary> + /// End of line characters. Default CRLF + /// </summary> + public string EOL { get; set; } + + /// <summary> + /// Datatypes list for each column (if column is not present Unknown is assumed) + /// </summary> + public eDataTypes[] DataTypes { get; set; } + + /// <summary> + /// Culture used when parsing. Default CultureInfo.InvariantCulture + /// </summary> + public CultureInfo Culture { get; set; } + + /// <summary> + /// Number of lines skiped in the begining of the file. Default 0. + /// </summary> + public int SkipLinesBeginning { get; set; } + + /// <summary> + /// Number of lines skiped at the end of the file. Default 0. + /// </summary> + public int SkipLinesEnd { get; set; } + + /// <summary> + /// Only used when reading files from disk using a FileInfo object. Default AscII + /// </summary> + public Encoding Encoding { get; set; } }
diff --git a/EPPlus/ExcelWorkbook.cs b/EPPlus/ExcelWorkbook.cs index f529826..ada35ea 100644 --- a/EPPlus/ExcelWorkbook.cs +++ b/EPPlus/ExcelWorkbook.cs
@@ -13,936 +13,876 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 * Richard Tallent Fix escaping of quotes 2012-10-31 *******************************************************************************/ + using System; -using System.Xml; -using System.IO; using System.Collections.Generic; -using System.Text; using System.Globalization; -using OfficeOpenXml.Utils; +using System.IO; +using System.Text; +using System.Xml; using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -using System.Drawing; +using OfficeOpenXml.Packaging; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml -{ - #region Public Enum ExcelCalcMode - /// <summary> - /// How the application should calculate formulas in the workbook - /// </summary> - public enum ExcelCalcMode - { - /// <summary> - /// Indicates that calculations in the workbook are performed automatically when cell values change. - /// The application recalculates those cells that are dependent on other cells that contain changed values. - /// This mode of calculation helps to avoid unnecessary calculations. - /// </summary> - Automatic, - /// <summary> - /// Indicates tables be excluded during automatic calculation - /// </summary> - AutomaticNoTable, - /// <summary> - /// Indicates that calculations in the workbook be triggered manually by the user. - /// </summary> - Manual - } - #endregion +namespace OfficeOpenXml; - /// <summary> - /// Represents the Excel workbook and provides access to all the - /// document properties and worksheets within the workbook. - /// </summary> - public sealed class ExcelWorkbook : XmlHelper - { - internal class SharedStringItem - { - internal int pos; - internal string Text; - internal bool isRichText = false; - } - #region Private Properties - internal ExcelPackage _package; - private ExcelWorksheets _worksheets; - private OfficeProperties _properties; +/// <summary> +/// How the application should calculate formulas in the workbook +/// </summary> +public enum ExcelCalcMode { + /// <summary> + /// Indicates that calculations in the workbook are performed automatically when cell values change. + /// The application recalculates those cells that are dependent on other cells that contain changed values. + /// This mode of calculation helps to avoid unnecessary calculations. + /// </summary> + Automatic, - private ExcelStyles _styles; - #endregion + /// <summary> + /// Indicates tables be excluded during automatic calculation + /// </summary> + AutomaticNoTable, - #region ExcelWorkbook Constructor - /// <summary> - /// Creates a new instance of the ExcelWorkbook class. - /// </summary> - /// <param name="package">The parent package</param> - /// <param name="namespaceManager">NamespaceManager</param> - internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManager) : - base(namespaceManager) - { - _package = package; - WorkbookUri = new Uri("/xl/workbook.xml", UriKind.Relative); - SharedStringsUri = new Uri("/xl/sharedStrings.xml", UriKind.Relative); - StylesUri = new Uri("/xl/styles.xml", UriKind.Relative); + /// <summary> + /// Indicates that calculations in the workbook be triggered manually by the user. + /// </summary> + Manual, +} - _names = new ExcelNamedRangeCollection(this); - _namespaceManager = namespaceManager; - TopNode = WorkbookXml.DocumentElement; - SchemaNodeOrder = new string[] { "fileVersion", "fileSharing", "workbookPr", "workbookProtection", "bookViews", "sheets", "functionGroups", "functionPrototypes", "externalReferences", "definedNames", "calcPr", "oleSize", "customWorkbookViews", "pivotCaches", "smartTagPr", "smartTagTypes", "webPublishing", "fileRecoveryPr", }; - FullCalcOnLoad = true; //Full calculation on load by default, for both new workbooks and templates. - GetSharedStrings(); - } - #endregion +/// <summary> +/// Represents the Excel workbook and provides access to all the +/// document properties and worksheets within the workbook. +/// </summary> +public sealed class ExcelWorkbook : XmlHelper { + internal class SharedStringItem { + internal int pos; + internal string Text; + internal bool isRichText; + } - internal Dictionary<string, SharedStringItem> _sharedStrings = new Dictionary<string, SharedStringItem>(); //Used when reading cells. - internal List<SharedStringItem> _sharedStringsList = new List<SharedStringItem>(); //Used when reading cells. - internal ExcelNamedRangeCollection _names; - internal int _nextDrawingID = 0; - internal int _nextTableID = int.MinValue; - internal int _nextPivotTableID = int.MinValue; - internal XmlNamespaceManager _namespaceManager; - internal FormulaParser _formulaParser = null; - internal FormulaParserManager _parserManager; - internal CellStore<List<Token>> _formulaTokens; - /// <summary> - /// Read shared strings to list - /// </summary> - private void GetSharedStrings() - { - if (_package.Package.PartExists(SharedStringsUri)) - { - var xml = _package.GetXmlFromUri(SharedStringsUri); - XmlNodeList nl = xml.SelectNodes("//d:sst/d:si", NameSpaceManager); - _sharedStringsList = new List<SharedStringItem>(); - if (nl != null) - { - foreach (XmlNode node in nl) - { - XmlNode n = node.SelectSingleNode("d:t", NameSpaceManager); - if (n != null) - { - _sharedStringsList.Add(new SharedStringItem() { Text = ConvertUtil.ExcelDecodeString(n.InnerText) }); - } - else - { - _sharedStringsList.Add(new SharedStringItem() { Text = node.InnerXml, isRichText = true }); - } - } - } - //Delete the shared string part, it will be recreated when the package is saved. - foreach (var rel in Part.GetRelationships()) - { - if (rel.TargetUri.OriginalString.EndsWith("sharedstrings.xml", StringComparison.InvariantCultureIgnoreCase)) - { - Part.DeleteRelationship(rel.Id); - break; - } - } - _package.Package.DeletePart(SharedStringsUri); //Remove the part, it is recreated when saved. - } - } - internal void GetDefinedNames() - { - XmlNodeList nl = WorkbookXml.SelectNodes("//d:definedNames/d:definedName", NameSpaceManager); - if (nl != null) - { - foreach (XmlElement elem in nl) - { - string fullAddress = elem.InnerText; + internal ExcelPackage _package; + private ExcelWorksheets _worksheets; + private OfficeProperties _properties; - int localSheetID; - ExcelWorksheet nameWorksheet; - if(!int.TryParse(elem.GetAttribute("localSheetId"), out localSheetID)) - { - localSheetID = -1; - nameWorksheet=null; - } - else - { - nameWorksheet=Worksheets[localSheetID + 1]; - } - var addressType = ExcelAddressBase.IsValid(fullAddress); - ExcelRangeBase range; - ExcelNamedRange namedRange; + private ExcelStyles _styles; - if (fullAddress.IndexOf("[") == 0) - { - int start = fullAddress.IndexOf("["); - int end = fullAddress.IndexOf("]", start); - if (start >= 0 && end >= 0) - { + /// <summary> + /// Creates a new instance of the ExcelWorkbook class. + /// </summary> + /// <param name="package">The parent package</param> + /// <param name="namespaceManager">NamespaceManager</param> + internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManager) + : base(namespaceManager) { + _package = package; + WorkbookUri = new("/xl/workbook.xml", UriKind.Relative); + SharedStringsUri = new("/xl/sharedStrings.xml", UriKind.Relative); + StylesUri = new("/xl/styles.xml", UriKind.Relative); - string externalIndex = fullAddress.Substring(start + 1, end - start - 1); - int index; - if (int.TryParse(externalIndex, out index)) - { - if (index > 0 && index <= _externalReferences.Count) - { - fullAddress = fullAddress.Substring(0, start) + "[" + _externalReferences[index - 1] + "]" + fullAddress.Substring(end + 1); - } - } - } - } + _names = new(this); + _namespaceManager = namespaceManager; + TopNode = WorkbookXml.DocumentElement; + SchemaNodeOrder = new[] { + "fileVersion", + "fileSharing", + "workbookPr", + "workbookProtection", + "bookViews", + "sheets", + "functionGroups", + "functionPrototypes", + "externalReferences", + "definedNames", + "calcPr", + "oleSize", + "customWorkbookViews", + "pivotCaches", + "smartTagPr", + "smartTagTypes", + "webPublishing", + "fileRecoveryPr", + }; + FullCalcOnLoad = true; //Full calculation on load by default, for both new workbooks and templates. + GetSharedStrings(); + } - if (addressType == ExcelAddressBase.AddressType.Invalid || addressType == ExcelAddressBase.AddressType.InternalName || addressType == ExcelAddressBase.AddressType.ExternalName || addressType==ExcelAddressBase.AddressType.Formula || addressType==ExcelAddressBase.AddressType.ExternalAddress) //A value or a formula - { - double value; - range = new ExcelRangeBase(this, nameWorksheet, elem.GetAttribute("name"), true); - if (nameWorksheet == null) - { - namedRange = _names.Add(elem.GetAttribute("name"), range); - } - else - { - namedRange = nameWorksheet.Names.Add(elem.GetAttribute("name"), range); - } - - if (fullAddress.StartsWith("\"")) //String value - { - namedRange.NameValue = fullAddress.Substring(1,fullAddress.Length-2); - } - else if (double.TryParse(fullAddress, NumberStyles.Any, CultureInfo.InvariantCulture, out value)) - { - namedRange.NameValue = value; - } - else - { - //if (addressType == ExcelAddressBase.AddressType.ExternalAddress || addressType == ExcelAddressBase.AddressType.ExternalName) - //{ - // var r = new ExcelAddress(fullAddress); - // namedRange.NameFormula = '\'[' + r._wb - //} - //else - //{ - namedRange.NameFormula = fullAddress; - //} - } - } - else - { - ExcelAddress addr = new ExcelAddress(fullAddress, _package, null); - if (localSheetID > -1) - { - if (string.IsNullOrEmpty(addr._ws)) - { - namedRange = Worksheets[localSheetID + 1].Names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, Worksheets[localSheetID + 1], fullAddress, false)); - } - else - { - namedRange = Worksheets[localSheetID + 1].Names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, Worksheets[addr._ws], fullAddress, false)); - } - } - else - { - var ws = Worksheets[addr._ws]; - namedRange = _names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, ws, fullAddress, false)); - } - } - if (elem.GetAttribute("hidden") == "1" && namedRange != null) namedRange.IsNameHidden = true; - if(!string.IsNullOrEmpty(elem.GetAttribute("comment"))) namedRange.NameComment=elem.GetAttribute("comment"); - } - } - } - #region Worksheets - /// <summary> - /// Provides access to all the worksheets in the workbook. - /// </summary> - public ExcelWorksheets Worksheets - { - get - { - if (_worksheets == null) - { - var sheetsNode = _workbookXml.DocumentElement.SelectSingleNode("d:sheets", _namespaceManager); - if (sheetsNode == null) - { - sheetsNode = CreateNode("d:sheets"); - } - - _worksheets = new ExcelWorksheets(_package, _namespaceManager, sheetsNode); - } - return (_worksheets); - } - } - #endregion + internal Dictionary<string, SharedStringItem> _sharedStrings = new(); //Used when reading cells. + internal List<SharedStringItem> _sharedStringsList = new(); //Used when reading cells. + internal ExcelNamedRangeCollection _names; + internal int _nextDrawingID = 0; + internal int _nextTableID = int.MinValue; + internal int _nextPivotTableID = int.MinValue; + internal XmlNamespaceManager _namespaceManager; + internal FormulaParser _formulaParser; + internal FormulaParserManager _parserManager; + internal CellStore<List<Token>> _formulaTokens; - /// <summary> - /// Provides access to named ranges - /// </summary> - public ExcelNamedRangeCollection Names - { - get - { - return _names; - } - } - #region Workbook Properties - internal FormulaParser FormulaParser - { - get - { - if (_formulaParser == null) - { - _formulaParser = new FormulaParser(new EpplusExcelDataProvider(_package)); - } - return _formulaParser; + /// <summary> + /// Read shared strings to list + /// </summary> + private void GetSharedStrings() { + if (_package.Package.PartExists(SharedStringsUri)) { + var xml = _package.GetXmlFromUri(SharedStringsUri); + XmlNodeList nl = xml.SelectNodes("//d:sst/d:si", NameSpaceManager); + _sharedStringsList = new(); + if (nl != null) { + foreach (XmlNode node in nl) { + XmlNode n = node.SelectSingleNode("d:t", NameSpaceManager); + if (n != null) { + _sharedStringsList.Add( + new() { + Text = ConvertUtil.ExcelDecodeString(n.InnerText), + }); + } else { + _sharedStringsList.Add( + new() { + Text = node.InnerXml, + isRichText = true, + }); + } + } + } + //Delete the shared string part, it will be recreated when the package is saved. + foreach (var rel in Part.GetRelationships()) { + if (rel.TargetUri.OriginalString.EndsWith( + "sharedstrings.xml", + StringComparison.InvariantCultureIgnoreCase)) { + Part.DeleteRelationship(rel.Id); + break; + } + } + _package.Package.DeletePart(SharedStringsUri); //Remove the part, it is recreated when saved. + } + } + + internal void GetDefinedNames() { + XmlNodeList nl = WorkbookXml.SelectNodes("//d:definedNames/d:definedName", NameSpaceManager); + if (nl != null) { + foreach (XmlElement elem in nl) { + string fullAddress = elem.InnerText; + + int localSheetId; + ExcelWorksheet nameWorksheet; + if (!int.TryParse(elem.GetAttribute("localSheetId"), out localSheetId)) { + localSheetId = -1; + nameWorksheet = null; + } else { + nameWorksheet = Worksheets[localSheetId + 1]; + } + var addressType = ExcelAddressBase.IsValid(fullAddress); + ExcelRangeBase range; + ExcelNamedRange namedRange; + + if (fullAddress.IndexOf("[") == 0) { + int start = fullAddress.IndexOf("["); + int end = fullAddress.IndexOf("]", start); + if (start >= 0 && end >= 0) { + string externalIndex = fullAddress.Substring(start + 1, end - start - 1); + int index; + if (int.TryParse(externalIndex, out index)) { + if (index > 0 && index <= _externalReferences.Count) { + fullAddress = + fullAddress.Substring(0, start) + + "[" + + _externalReferences[index - 1] + + "]" + + fullAddress.Substring(end + 1); + } } + } } - public FormulaParserManager FormulaParserManager - { - get - { - if (_parserManager == null) - { - _parserManager = new FormulaParserManager(FormulaParser); - } - return _parserManager; - } - } + if (addressType == ExcelAddressBase.AddressType.Invalid + || addressType == ExcelAddressBase.AddressType.InternalName + || addressType == ExcelAddressBase.AddressType.ExternalName + || addressType == ExcelAddressBase.AddressType.Formula + || addressType + == ExcelAddressBase + .AddressType + .ExternalAddress) //A value or a formula + { + double value; + range = new(this, nameWorksheet, elem.GetAttribute("name"), true); + if (nameWorksheet == null) { + namedRange = _names.Add(elem.GetAttribute("name"), range); + } else { + namedRange = nameWorksheet.Names.Add(elem.GetAttribute("name"), range); + } - ExcelProtection _protection = null; - /// <summary> - /// Access properties to protect or unprotect a workbook - /// </summary> - public ExcelProtection Protection - { - get - { - if (_protection == null) - { - _protection = new ExcelProtection(NameSpaceManager, TopNode, this); - _protection.SchemaNodeOrder = SchemaNodeOrder; - } - return _protection; - } - } - ExcelWorkbookView _view = null; - /// <summary> - /// Access to workbook view properties - /// </summary> - public ExcelWorkbookView View - { - get - { - if (_view == null) - { - _view = new ExcelWorkbookView(NameSpaceManager, TopNode, this); - } - return _view; - } - } - - /// <summary> - /// URI to the workbook inside the package - /// </summary> - internal Uri WorkbookUri { get; private set; } - /// <summary> - /// URI to the styles inside the package - /// </summary> - internal Uri StylesUri { get; private set; } - /// <summary> - /// URI to the shared strings inside the package - /// </summary> - internal Uri SharedStringsUri { get; private set; } - /// <summary> - /// Returns a reference to the workbook's part within the package - /// </summary> - internal Packaging.ZipPackagePart Part { get { return (_package.Package.GetPart(WorkbookUri)); } } - - #region WorkbookXml - private XmlDocument _workbookXml; - /// <summary> - /// Provides access to the XML data representing the workbook in the package. - /// </summary> - public XmlDocument WorkbookXml - { - get - { - if (_workbookXml == null) - { - CreateWorkbookXml(_namespaceManager); - } - return (_workbookXml); - } - } - const string codeModuleNamePath = "d:workbookPr/@codeName"; - internal string CodeModuleName - { - get - { - return GetXmlNodeString(codeModuleNamePath); + if (fullAddress.StartsWith( + "\"")) //String value + { + namedRange.NameValue = fullAddress.Substring(1, fullAddress.Length - 2); + } else if (double.TryParse( + fullAddress, + NumberStyles.Any, + CultureInfo.InvariantCulture, + out value)) { + namedRange.NameValue = value; + } else { + //if (addressType == ExcelAddressBase.AddressType.ExternalAddress || addressType == ExcelAddressBase.AddressType.ExternalName) + //{ + // var r = new ExcelAddress(fullAddress); + // namedRange.NameFormula = '\'[' + r._wb + //} + //else + //{ + namedRange.NameFormula = fullAddress; + //} + } + } else { + ExcelAddress addr = new ExcelAddress(fullAddress, _package, null); + if (localSheetId > -1) { + if (string.IsNullOrEmpty(addr._ws)) { + namedRange = Worksheets[localSheetId + 1].Names.Add( + elem.GetAttribute("name"), + new(this, Worksheets[localSheetId + 1], fullAddress, false)); + } else { + namedRange = Worksheets[localSheetId + 1].Names.Add( + elem.GetAttribute("name"), + new(this, Worksheets[addr._ws], fullAddress, false)); } - set - { - SetXmlNodeString(codeModuleNamePath,value); - } + } else { + var ws = Worksheets[addr._ws]; + namedRange = _names.Add(elem.GetAttribute("name"), new(this, ws, fullAddress, false)); + } } - internal void CodeNameChange(string value) - { - CodeModuleName = value; + if (elem.GetAttribute("hidden") == "1" && namedRange != null) { + namedRange.IsNameHidden = true; + } + if (!string.IsNullOrEmpty(elem.GetAttribute("comment"))) { + namedRange.NameComment = elem.GetAttribute("comment"); + } + } + } + } + + /// <summary> + /// Provides access to all the worksheets in the workbook. + /// </summary> + public ExcelWorksheets Worksheets { + get { + if (_worksheets == null) { + var sheetsNode = _workbookXml.DocumentElement.SelectSingleNode( + "d:sheets", + _namespaceManager); + if (sheetsNode == null) { + sheetsNode = CreateNode("d:sheets"); } - const string date1904Path = "d:workbookPr/@date1904"; - internal const double date1904Offset = 365.5 * 4; // offset to fix 1900 and 1904 differences, 4 OLE years - /// <summary> - /// The date systems used by Microsoft Excel can be based on one of two different dates. By default, a serial number of 1 in Microsoft Excel represents January 1, 1900. - /// The default for the serial number 1 can be changed to represent January 2, 1904. - /// This option was included in Microsoft Excel for Windows to make it compatible with Excel for the Macintosh, which defaults to January 2, 1904. - /// </summary> - public bool Date1904 - { - get - { - return GetXmlNodeBool(date1904Path, false); - - } - set - { - if (Date1904 != value) - { - // Like Excel when the option it's changed update it all cells with Date format - foreach (var item in Worksheets) - { - item.UpdateCellsWithDate1904Setting(); - } - } + _worksheets = new(_package, _namespaceManager, sheetsNode); + } + return (_worksheets); + } + } - SetXmlNodeBool(date1904Path, value, false); - } + /// <summary> + /// Provides access to named ranges + /// </summary> + public ExcelNamedRangeCollection Names => _names; + + internal FormulaParser FormulaParser { + get { + if (_formulaParser == null) { + _formulaParser = new(new EpplusExcelDataProvider(_package)); + } + return _formulaParser; + } + } + + public FormulaParserManager FormulaParserManager { + get { + if (_parserManager == null) { + _parserManager = new(FormulaParser); + } + return _parserManager; + } + } + + private ExcelProtection _protection; + + /// <summary> + /// Access properties to protect or unprotect a workbook + /// </summary> + public ExcelProtection Protection { + get { + if (_protection == null) { + _protection = new(NameSpaceManager, TopNode, this); + _protection.SchemaNodeOrder = SchemaNodeOrder; + } + return _protection; + } + } + + private ExcelWorkbookView _view; + + /// <summary> + /// Access to workbook view properties + /// </summary> + public ExcelWorkbookView View { + get { + if (_view == null) { + _view = new(NameSpaceManager, TopNode, this); + } + return _view; + } + } + + /// <summary> + /// URI to the workbook inside the package + /// </summary> + internal Uri WorkbookUri { get; private set; } + + /// <summary> + /// URI to the styles inside the package + /// </summary> + internal Uri StylesUri { get; private set; } + + /// <summary> + /// URI to the shared strings inside the package + /// </summary> + internal Uri SharedStringsUri { get; private set; } + + /// <summary> + /// Returns a reference to the workbook's part within the package + /// </summary> + internal ZipPackagePart Part { + get { return (_package.Package.GetPart(WorkbookUri)); } + } + + private XmlDocument _workbookXml; + + /// <summary> + /// Provides access to the XML data representing the workbook in the package. + /// </summary> + public XmlDocument WorkbookXml { + get { + if (_workbookXml == null) { + CreateWorkbookXml(_namespaceManager); + } + return (_workbookXml); + } + } + + private const string _codeModuleNamePath = "d:workbookPr/@codeName"; + + internal string CodeModuleName { + get { return GetXmlNodeString(_codeModuleNamePath); } + set { SetXmlNodeString(_codeModuleNamePath, value); } + } + + internal void CodeNameChange(string value) { + CodeModuleName = value; + } + + private const string _date1904Path = "d:workbookPr/@date1904"; + internal const double _date1904Offset = 365.5 * 4; // offset to fix 1900 and 1904 differences, 4 OLE years + + /// <summary> + /// The date systems used by Microsoft Excel can be based on one of two different dates. By default, a serial number of 1 in Microsoft Excel represents January 1, 1900. + /// The default for the serial number 1 can be changed to represent January 2, 1904. + /// This option was included in Microsoft Excel for Windows to make it compatible with Excel for the Macintosh, which defaults to January 2, 1904. + /// </summary> + public bool Date1904 { + get { return GetXmlNodeBool(_date1904Path, false); } + set { + if (Date1904 != value) { + // Like Excel when the option it's changed update it all cells with Date format + foreach (var item in Worksheets) { + item.UpdateCellsWithDate1904Setting(); } - - - /// <summary> - /// Create or read the XML for the workbook. - /// </summary> - private void CreateWorkbookXml(XmlNamespaceManager namespaceManager) - { - if (_package.Package.PartExists(WorkbookUri)) - _workbookXml = _package.GetXmlFromUri(WorkbookUri); - else - { - // create a new workbook part and add to the package - Packaging.ZipPackagePart partWorkbook = _package.Package.CreatePart(WorkbookUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", _package.Compression); + } - // create the workbook - _workbookXml = new XmlDocument(namespaceManager.NameTable); - - _workbookXml.PreserveWhitespace = ExcelPackage.preserveWhitespace; - // create the workbook element - XmlElement wbElem = _workbookXml.CreateElement("workbook", ExcelPackage.schemaMain); + SetXmlNodeBool(_date1904Path, value, false); + } + } - // Add the relationships namespace - wbElem.SetAttribute("xmlns:r", ExcelPackage.schemaRelationships); + /// <summary> + /// Create or read the XML for the workbook. + /// </summary> + private void CreateWorkbookXml(XmlNamespaceManager namespaceManager) { + if (_package.Package.PartExists(WorkbookUri)) { + _workbookXml = _package.GetXmlFromUri(WorkbookUri); + } else { + // create a new workbook part and add to the package + ZipPackagePart partWorkbook = _package.Package.CreatePart( + WorkbookUri, + "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", + _package.Compression); - _workbookXml.AppendChild(wbElem); + // create the workbook + _workbookXml = new(namespaceManager.NameTable); - // create the bookViews and workbooks element - XmlElement bookViews = _workbookXml.CreateElement("bookViews", ExcelPackage.schemaMain); - wbElem.AppendChild(bookViews); - XmlElement workbookView = _workbookXml.CreateElement("workbookView", ExcelPackage.schemaMain); - bookViews.AppendChild(workbookView); + _workbookXml.PreserveWhitespace = ExcelPackage._preserveWhitespace; + // create the workbook element + XmlElement wbElem = _workbookXml.CreateElement("workbook", ExcelPackage._schemaMain); - // save it to the package - StreamWriter stream = new StreamWriter(partWorkbook.GetStream(FileMode.Create, FileAccess.Write)); - _workbookXml.Save(stream); - //stream.Close(); - } - } - #endregion - #region StylesXml - private XmlDocument _stylesXml; - /// <summary> - /// Provides access to the XML data representing the styles in the package. - /// </summary> - public XmlDocument StylesXml - { - get - { - if (_stylesXml == null) - { - if (_package.Package.PartExists(StylesUri)) - _stylesXml = _package.GetXmlFromUri(StylesUri); - else - { - // create a new styles part and add to the package - Packaging.ZipPackagePart part = _package.Package.CreatePart(StylesUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", _package.Compression); - // create the style sheet + // Add the relationships namespace + wbElem.SetAttribute("xmlns:r", ExcelPackage._schemaRelationships); - StringBuilder xml = new StringBuilder("<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"); - xml.Append("<numFmts />"); - xml.Append("<fonts count=\"1\"><font><sz val=\"11\" /><name val=\"Calibri\" /></font></fonts>"); - xml.Append("<fills><fill><patternFill patternType=\"none\" /></fill><fill><patternFill patternType=\"gray125\" /></fill></fills>"); - xml.Append("<borders><border><left /><right /><top /><bottom /><diagonal /></border></borders>"); - xml.Append("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" /></cellStyleXfs>"); - xml.Append("<cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" xfId=\"0\" /></cellXfs>"); - xml.Append("<cellStyles><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" /></cellStyles>"); - xml.Append("<dxfs count=\"0\" />"); - xml.Append("</styleSheet>"); - - _stylesXml = new XmlDocument(); - _stylesXml.LoadXml(xml.ToString()); - - //Save it to the package - StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write)); + _workbookXml.AppendChild(wbElem); - _stylesXml.Save(stream); - //stream.Close(); + // create the bookViews and workbooks element + XmlElement bookViews = _workbookXml.CreateElement("bookViews", ExcelPackage._schemaMain); + wbElem.AppendChild(bookViews); + XmlElement workbookView = _workbookXml.CreateElement( + "workbookView", + ExcelPackage._schemaMain); + bookViews.AppendChild(workbookView); - // create the relationship between the workbook and the new shared strings part - _package.Workbook.Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, StylesUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/styles"); - } - } - return (_stylesXml); - } - set - { - _stylesXml = value; - } - } - /// <summary> - /// Package styles collection. Used internally to access style data. - /// </summary> - public ExcelStyles Styles - { - get - { - if (_styles == null) - { - _styles = new ExcelStyles(NameSpaceManager, StylesXml, this); - } - return _styles; - } - } - #endregion + // save it to the package + StreamWriter stream = new StreamWriter( + partWorkbook.GetStream(FileMode.Create, FileAccess.Write)); + _workbookXml.Save(stream); + //stream.Close(); + } + } - #region Office Document Properties - /// <summary> - /// The office document properties - /// </summary> - public OfficeProperties Properties - { - get - { - if (_properties == null) - { - // Create a NamespaceManager to handle the default namespace, - // and create a prefix for the default namespace: - _properties = new OfficeProperties(_package, NameSpaceManager); - } - return _properties; - } - } - #endregion + private XmlDocument _stylesXml; - #region CalcMode - private string CALC_MODE_PATH = "d:calcPr/@calcMode"; - /// <summary> - /// Calculation mode for the workbook. - /// </summary> - public ExcelCalcMode CalcMode - { - get - { - string calcMode = GetXmlNodeString(CALC_MODE_PATH); - switch (calcMode) - { - case "autoNoTable": - return ExcelCalcMode.AutomaticNoTable; - case "manual": - return ExcelCalcMode.Manual; - default: - return ExcelCalcMode.Automatic; - - } - } - set - { - switch (value) - { - case ExcelCalcMode.AutomaticNoTable: - SetXmlNodeString(CALC_MODE_PATH, "autoNoTable") ; - break; - case ExcelCalcMode.Manual: - SetXmlNodeString(CALC_MODE_PATH, "manual"); - break; - default: - SetXmlNodeString(CALC_MODE_PATH, "auto"); - break; + /// <summary> + /// Provides access to the XML data representing the styles in the package. + /// </summary> + public XmlDocument StylesXml { + get { + if (_stylesXml == null) { + if (_package.Package.PartExists(StylesUri)) { + _stylesXml = _package.GetXmlFromUri(StylesUri); + } else { + // create a new styles part and add to the package + ZipPackagePart part = _package.Package.CreatePart( + StylesUri, + "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", + _package.Compression); + // create the style sheet - } - } - #endregion - } + StringBuilder xml = new StringBuilder( + "<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">"); + xml.Append("<numFmts />"); + xml.Append( + "<fonts count=\"1\"><font><sz val=\"11\" /><name val=\"Calibri\" /></font></fonts>"); + xml.Append( + "<fills><fill><patternFill patternType=\"none\" /></fill><fill><patternFill patternType=\"gray125\" /></fill></fills>"); + xml.Append( + "<borders><border><left /><right /><top /><bottom /><diagonal /></border></borders>"); + xml.Append("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" /></cellStyleXfs>"); + xml.Append( + "<cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" xfId=\"0\" /></cellXfs>"); + xml.Append( + "<cellStyles><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" /></cellStyles>"); + xml.Append("<dxfs count=\"0\" />"); + xml.Append("</styleSheet>"); - private const string FULL_CALC_ON_LOAD_PATH = "d:calcPr/@fullCalcOnLoad"; - /// <summary> - /// Should Excel do a full calculation after the workbook has been loaded? - /// <remarks>This property is always true for both new workbooks and loaded templates(on load). If this is not the wanted behavior set this property to false.</remarks> - /// </summary> - public bool FullCalcOnLoad - { - get - { - return GetXmlNodeBool(FULL_CALC_ON_LOAD_PATH); - } - set - { - SetXmlNodeBool(FULL_CALC_ON_LOAD_PATH, value); - } - } - #endregion - #region Workbook Private Methods - - #region Save // Workbook Save - /// <summary> - /// Saves the workbook and all its components to the package. - /// For internal use only! - /// </summary> - internal void Save() // Workbook Save - { - if (Worksheets.Count == 0) - throw new InvalidOperationException("The workbook must contain at least one worksheet"); + _stylesXml = new(); + _stylesXml.LoadXml(xml.ToString()); - DeleteCalcChain(); + //Save it to the package + StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write)); - const string vbaPartUri = "/xl/vbaProject.bin"; - if (!_package.Package.PartExists(new Uri(vbaPartUri, UriKind.Relative))) - { - if (Part.ContentType != ExcelPackage.contentTypeWorkbookDefault) - { - Part.ContentType = ExcelPackage.contentTypeWorkbookDefault; - } - } - else - { - if (Part.ContentType != ExcelPackage.contentTypeWorkbookMacroEnabled) - { - Part.ContentType = ExcelPackage.contentTypeWorkbookMacroEnabled; - } - } - - UpdateDefinedNamesXml(); + _stylesXml.Save(stream); + //stream.Close(); - // save the workbook - if (_workbookXml != null) - { - _package.SavePart(WorkbookUri, _workbookXml); - } - - // save the properties of the workbook - if (_properties != null) - { - _properties.Save(); - } - - // save the style sheet - Styles.UpdateXml(); - _package.SavePart(StylesUri, _stylesXml); - - // save all the open worksheets - var isProtected = Protection.LockWindows || Protection.LockStructure; - foreach (ExcelWorksheet worksheet in Worksheets) - { - if (isProtected && Protection.LockWindows) - { - worksheet.View.WindowProtection = true; - } - worksheet.Save(); - worksheet.Part.SaveHandler = worksheet.SaveHandler; - } - - var part = _package.Package.CreatePart(SharedStringsUri, ExcelPackage.contentTypeSharedString, _package.Compression); - part.SaveHandler = SaveSharedStringHandler; - Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/sharedStrings"); - //UpdateSharedStringsXml(); - - // Data validation - ValidateDataValidations(); - } - private void DeleteCalcChain() - { - //Remove the calc chain if it exists. - Uri uriCalcChain = new Uri("/xl/calcChain.xml", UriKind.Relative); - if (_package.Package.PartExists(uriCalcChain)) - { - Uri calcChain = new Uri("calcChain.xml", UriKind.Relative); - foreach (var relationship in _package.Workbook.Part.GetRelationships()) - { - if (relationship.TargetUri == calcChain) - { - _package.Workbook.Part.DeleteRelationship(relationship.Id); - break; - } - } - // delete the calcChain part - _package.Package.DeletePart(uriCalcChain); - } - } - - private void ValidateDataValidations() - { - foreach (var sheet in _package.Workbook.Worksheets) - { - if (!(sheet is ExcelChartsheet)) - { - sheet.DataValidations.ValidateAll(); - } - } - } - - private void SaveSharedStringHandler(StreamWriter sw) - { - var cache = new StringBuilder(); - cache.AppendFormat("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"{0}\" uniqueCount=\"{0}\">", _sharedStrings.Count); - foreach (string t in _sharedStrings.Keys) - { - - SharedStringItem ssi = _sharedStrings[t]; - if (ssi.isRichText) - { - cache.Append("<si>"); - ConvertUtil.ExcelEncodeString(cache, t); - cache.Append("</si>"); - } - else - { - if (t.Length > 0 && (t[0] == ' ' || t[t.Length - 1] == ' ' || t.Contains(" ") || t.Contains("\t") || t.Contains("\n") || t.Contains("\n"))) //Fixes issue 14849 - { - cache.Append("<si><t xml:space=\"preserve\">"); - } - else - { - cache.Append("<si><t>"); - } - ConvertUtil.ExcelEncodeString(cache, ConvertUtil.ExcelEscapeString(t)); - cache.Append("</t></si>"); - } - if (cache.Length > 0x600000) - { - sw.Write(cache.ToString()); - cache = new StringBuilder(); - } - } - cache.Append("</sst>"); - sw.Write(cache.ToString()); - sw.Flush(); - Part.CreateRelationship(UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/sharedStrings"); - } - private void UpdateDefinedNamesXml() - { - try - { - XmlNode top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager); - if (!ExistsNames()) - { - if (top != null) TopNode.RemoveChild(top); - return; - } - else - { - if (top == null) - { - CreateNode("d:definedNames"); - top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager); - } - else - { - top.RemoveAll(); - } - foreach (ExcelNamedRange name in _names) - { - - XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage.schemaMain); - top.AppendChild(elem); - elem.SetAttribute("name", name.Name); - if (name.IsNameHidden) elem.SetAttribute("hidden", "1"); - if (!string.IsNullOrEmpty(name.NameComment)) elem.SetAttribute("comment", name.NameComment); - SetNameElement(name, elem); - } - } - foreach (ExcelWorksheet ws in _worksheets) - { - if (!(ws is ExcelChartsheet)) - { - foreach (ExcelNamedRange name in ws.Names) - { - XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage.schemaMain); - top.AppendChild(elem); - elem.SetAttribute("name", name.Name); - elem.SetAttribute("localSheetId", name.LocalSheetId.ToString()); - if (name.IsNameHidden) elem.SetAttribute("hidden", "1"); - if (!string.IsNullOrEmpty(name.NameComment)) elem.SetAttribute("comment", name.NameComment); - SetNameElement(name, elem); - } - } - } - } - catch (Exception ex) - { - throw new Exception("Internal error updating named ranges ",ex); - } - } - - private void SetNameElement(ExcelNamedRange name, XmlElement elem) - { - if (name.IsName) - { - if (string.IsNullOrEmpty(name.NameFormula)) - { - if ((name.NameValue.GetType().IsPrimitive || name.NameValue is double || name.NameValue is decimal)) - { - elem.InnerText = Convert.ToDouble(name.NameValue, CultureInfo.InvariantCulture).ToString("R15", CultureInfo.InvariantCulture); - } - else if (name.NameValue is DateTime) - { - elem.InnerText = ((DateTime)name.NameValue).ToOADate().ToString(CultureInfo.InvariantCulture); - } - else - { - elem.InnerText = "\"" + name.NameValue.ToString() + "\""; - } - } - else - { - elem.InnerText = name.NameFormula; - } - } - else - { - elem.InnerText = name.FullAddressAbsolute; - } - } - /// <summary> - /// Is their any names in the workbook or in the sheets. - /// </summary> - /// <returns>?</returns> - private bool ExistsNames() - { - if (_names.Count == 0) - { - foreach (ExcelWorksheet ws in Worksheets) - { - if (ws is ExcelChartsheet) continue; - if(ws.Names.Count>0) - { - return true; - } - } - } - else - { - return true; - } - return false; - } - #endregion - - #endregion - internal bool ExistsTableName(string Name) - { - foreach (var ws in Worksheets) - { - if(ws.Tables._tableNames.ContainsKey(Name)) - { - return true; - } - } - return false; - } - internal bool ExistsPivotTableName(string Name) - { - foreach (var ws in Worksheets) - { - if (ws.PivotTables._pivotTableNames.ContainsKey(Name)) - { - return true; - } - } - return false; - } - internal void AddPivotTable(string cacheID, Uri defUri) - { - CreateNode("d:pivotCaches"); - - XmlElement item = WorkbookXml.CreateElement("pivotCache", ExcelPackage.schemaMain); - item.SetAttribute("cacheId", cacheID); - var rel = Part.CreateRelationship(UriHelper.ResolvePartUri(WorkbookUri, defUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotCacheDefinition"); - item.SetAttribute("id", ExcelPackage.schemaRelationships, rel.Id); - - var pivotCaches = WorkbookXml.SelectSingleNode("//d:pivotCaches", NameSpaceManager); - pivotCaches.AppendChild(item); - } - internal List<string> _externalReferences = new List<string>(); - //internal bool _isCalculated=false; - internal void GetExternalReferences() - { - XmlNodeList nl = WorkbookXml.SelectNodes("//d:externalReferences/d:externalReference", NameSpaceManager); - if (nl != null) - { - foreach (XmlElement elem in nl) - { - string rID = elem.GetAttribute("r:id"); - var rel = Part.GetRelationship(rID); - var part = _package.Package.GetPart(UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri)); - XmlDocument xmlExtRef = new XmlDocument(); - LoadXmlSafe(xmlExtRef, part.GetStream()); - - XmlElement book=xmlExtRef.SelectSingleNode("//d:externalBook", NameSpaceManager) as XmlElement; - if(book!=null) - { - string rId_ExtRef = book.GetAttribute("r:id"); - var rel_extRef = part.GetRelationship(rId_ExtRef); - if (rel_extRef != null) - { - _externalReferences.Add(rel_extRef.TargetUri.OriginalString); - } - - } - } - } - } - - internal void ReadAllTables() - { - if (_nextTableID > 0) return; - _nextTableID = 1; - _nextPivotTableID = 1; - foreach (var ws in Worksheets) - { - if (!(ws is ExcelChartsheet)) //Fixes 15273. Chartsheets should be ignored. - { - foreach (var tbl in ws.Tables) - { - if (tbl.Id >= _nextTableID) - { - _nextTableID = tbl.Id + 1; - } - } - foreach (var pt in ws.PivotTables) - { - if (pt.CacheID >= _nextPivotTableID) - { - _nextPivotTableID = pt.CacheID + 1; - } - } - } - } + // create the relationship between the workbook and the new shared strings part + _package.Workbook.Part.CreateRelationship( + UriHelper.GetRelativeUri(WorkbookUri, StylesUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/styles"); } - } // end Workbook + } + return (_stylesXml); + } + set { _stylesXml = value; } + } + + /// <summary> + /// Package styles collection. Used internally to access style data. + /// </summary> + public ExcelStyles Styles { + get { + if (_styles == null) { + _styles = new(NameSpaceManager, StylesXml, this); + } + return _styles; + } + } + + /// <summary> + /// The office document properties + /// </summary> + public OfficeProperties Properties { + get { + if (_properties == null) { + // Create a NamespaceManager to handle the default namespace, + // and create a prefix for the default namespace: + _properties = new(_package, NameSpaceManager); + } + return _properties; + } + } + + private string CALC_MODE_PATH = "d:calcPr/@calcMode"; + + /// <summary> + /// Calculation mode for the workbook. + /// </summary> + public ExcelCalcMode CalcMode { + get { + string calcMode = GetXmlNodeString(CALC_MODE_PATH); + switch (calcMode) { + case "autoNoTable": + return ExcelCalcMode.AutomaticNoTable; + case "manual": + return ExcelCalcMode.Manual; + default: + return ExcelCalcMode.Automatic; + } + } + set { + switch (value) { + case ExcelCalcMode.AutomaticNoTable: + SetXmlNodeString(CALC_MODE_PATH, "autoNoTable"); + break; + case ExcelCalcMode.Manual: + SetXmlNodeString(CALC_MODE_PATH, "manual"); + break; + default: + SetXmlNodeString(CALC_MODE_PATH, "auto"); + break; + } + } + } + + private const string _fullCalcOnLoadPath = "d:calcPr/@fullCalcOnLoad"; + + /// <summary> + /// Should Excel do a full calculation after the workbook has been loaded? + /// <remarks>This property is always true for both new workbooks and loaded templates(on load). If this is not the wanted behavior set this property to false.</remarks> + /// </summary> + public bool FullCalcOnLoad { + get { return GetXmlNodeBool(_fullCalcOnLoadPath); } + set { SetXmlNodeBool(_fullCalcOnLoadPath, value); } + } + + /// <summary> + /// Saves the workbook and all its components to the package. + /// For internal use only! + /// </summary> + internal void Save() // Workbook Save + { + if (Worksheets.Count == 0) { + throw new InvalidOperationException("The workbook must contain at least one worksheet"); + } + + DeleteCalcChain(); + + const string vbaPartUri = "/xl/vbaProject.bin"; + if (!_package.Package.PartExists(new(vbaPartUri, UriKind.Relative))) { + if (Part.ContentType != ExcelPackage._contentTypeWorkbookDefault) { + Part.ContentType = ExcelPackage._contentTypeWorkbookDefault; + } + } else { + if (Part.ContentType != ExcelPackage._contentTypeWorkbookMacroEnabled) { + Part.ContentType = ExcelPackage._contentTypeWorkbookMacroEnabled; + } + } + + UpdateDefinedNamesXml(); + + // save the workbook + if (_workbookXml != null) { + _package.SavePart(WorkbookUri, _workbookXml); + } + + // save the properties of the workbook + if (_properties != null) { + _properties.Save(); + } + + // save the style sheet + Styles.UpdateXml(); + _package.SavePart(StylesUri, _stylesXml); + + // save all the open worksheets + var isProtected = Protection.LockWindows || Protection.LockStructure; + foreach (ExcelWorksheet worksheet in Worksheets) { + if (isProtected && Protection.LockWindows) { + worksheet.View.WindowProtection = true; + } + worksheet.Save(); + worksheet.Part.SaveHandler = worksheet.SaveHandler; + } + + var part = _package.Package.CreatePart( + SharedStringsUri, + ExcelPackage._contentTypeSharedString, + _package.Compression); + part.SaveHandler = SaveSharedStringHandler; + Part.CreateRelationship( + UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/sharedStrings"); + //UpdateSharedStringsXml(); + + // Data validation + ValidateDataValidations(); + } + + private void DeleteCalcChain() { + //Remove the calc chain if it exists. + Uri uriCalcChain = new Uri("/xl/calcChain.xml", UriKind.Relative); + if (_package.Package.PartExists(uriCalcChain)) { + Uri calcChain = new Uri("calcChain.xml", UriKind.Relative); + foreach (var relationship in _package.Workbook.Part.GetRelationships()) { + if (relationship.TargetUri == calcChain) { + _package.Workbook.Part.DeleteRelationship(relationship.Id); + break; + } + } + // delete the calcChain part + _package.Package.DeletePart(uriCalcChain); + } + } + + private void ValidateDataValidations() { + foreach (var sheet in _package.Workbook.Worksheets) { + if (!(sheet is ExcelChartsheet)) { + sheet.DataValidations.ValidateAll(); + } + } + } + + private void SaveSharedStringHandler(StreamWriter sw) { + var cache = new StringBuilder(); + cache.AppendFormat( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"{0}\" uniqueCount=\"{0}\">", + _sharedStrings.Count); + foreach (string t in _sharedStrings.Keys) { + SharedStringItem ssi = _sharedStrings[t]; + if (ssi.isRichText) { + cache.Append("<si>"); + ConvertUtil.ExcelEncodeString(cache, t); + cache.Append("</si>"); + } else { + if (t.Length > 0 + && (t[0] == ' ' + || t[t.Length - 1] == ' ' + || t.Contains(" ") + || t.Contains("\t") + || t.Contains("\n") + || t.Contains( + "\n"))) //Fixes issue 14849 + { + cache.Append("<si><t xml:space=\"preserve\">"); + } else { + cache.Append("<si><t>"); + } + ConvertUtil.ExcelEncodeString(cache, ConvertUtil.ExcelEscapeString(t)); + cache.Append("</t></si>"); + } + if (cache.Length > 0x600000) { + sw.Write(cache.ToString()); + cache = new(); + } + } + cache.Append("</sst>"); + sw.Write(cache.ToString()); + sw.Flush(); + Part.CreateRelationship( + UriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/sharedStrings"); + } + + private void UpdateDefinedNamesXml() { + try { + XmlNode top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager); + if (!ExistsNames()) { + if (top != null) { + TopNode.RemoveChild(top); + } + return; + } + if (top == null) { + CreateNode("d:definedNames"); + top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager); + } else { + top.RemoveAll(); + } + foreach (ExcelNamedRange name in _names) { + XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage._schemaMain); + top.AppendChild(elem); + elem.SetAttribute("name", name.Name); + if (name.IsNameHidden) { + elem.SetAttribute("hidden", "1"); + } + if (!string.IsNullOrEmpty(name.NameComment)) { + elem.SetAttribute("comment", name.NameComment); + } + SetNameElement(name, elem); + } + foreach (ExcelWorksheet ws in _worksheets) { + if (!(ws is ExcelChartsheet)) { + foreach (ExcelNamedRange name in ws.Names) { + XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage._schemaMain); + top.AppendChild(elem); + elem.SetAttribute("name", name.Name); + elem.SetAttribute("localSheetId", name.LocalSheetId.ToString()); + if (name.IsNameHidden) { + elem.SetAttribute("hidden", "1"); + } + if (!string.IsNullOrEmpty(name.NameComment)) { + elem.SetAttribute("comment", name.NameComment); + } + SetNameElement(name, elem); + } + } + } + } catch (Exception ex) { + throw new("Internal error updating named ranges ", ex); + } + } + + private void SetNameElement(ExcelNamedRange name, XmlElement elem) { + if (name.IsName) { + if (string.IsNullOrEmpty(name.NameFormula)) { + if ((name.NameValue.GetType().IsPrimitive + || name.NameValue is double + || name.NameValue is decimal)) { + elem.InnerText = Convert + .ToDouble(name.NameValue, CultureInfo.InvariantCulture) + .ToString("R15", CultureInfo.InvariantCulture); + } else if (name.NameValue is DateTime) { + elem.InnerText = + ((DateTime)name.NameValue).ToOADate().ToString(CultureInfo.InvariantCulture); + } else { + elem.InnerText = "\"" + name.NameValue + "\""; + } + } else { + elem.InnerText = name.NameFormula; + } + } else { + elem.InnerText = name.FullAddressAbsolute; + } + } + + /// <summary> + /// Is their any names in the workbook or in the sheets. + /// </summary> + /// <returns>?</returns> + private bool ExistsNames() { + if (_names.Count == 0) { + foreach (ExcelWorksheet ws in Worksheets) { + if (ws is ExcelChartsheet) { + continue; + } + if (ws.Names.Count > 0) { + return true; + } + } + } else { + return true; + } + return false; + } + + internal bool ExistsTableName(string name) { + foreach (var ws in Worksheets) { + if (ws.Tables._tableNames.ContainsKey(name)) { + return true; + } + } + return false; + } + + internal bool ExistsPivotTableName(string name) { + foreach (var ws in Worksheets) { + if (ws.PivotTables._pivotTableNames.ContainsKey(name)) { + return true; + } + } + return false; + } + + internal void AddPivotTable(string cacheId, Uri defUri) { + CreateNode("d:pivotCaches"); + + XmlElement item = WorkbookXml.CreateElement("pivotCache", ExcelPackage._schemaMain); + item.SetAttribute("cacheId", cacheId); + var rel = Part.CreateRelationship( + UriHelper.ResolvePartUri(WorkbookUri, defUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/pivotCacheDefinition"); + item.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id); + + var pivotCaches = WorkbookXml.SelectSingleNode("//d:pivotCaches", NameSpaceManager); + pivotCaches.AppendChild(item); + } + + internal List<string> _externalReferences = new(); + + //internal bool _isCalculated=false; + internal void GetExternalReferences() { + XmlNodeList nl = WorkbookXml.SelectNodes( + "//d:externalReferences/d:externalReference", + NameSpaceManager); + if (nl != null) { + foreach (XmlElement elem in nl) { + string rId = elem.GetAttribute("r:id"); + var rel = Part.GetRelationship(rId); + var part = _package.Package.GetPart(UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri)); + XmlDocument xmlExtRef = new XmlDocument(); + LoadXmlSafe(xmlExtRef, part.GetStream()); + + XmlElement book = + xmlExtRef.SelectSingleNode("//d:externalBook", NameSpaceManager) as XmlElement; + if (book != null) { + string rIdExtRef = book.GetAttribute("r:id"); + var relExtRef = part.GetRelationship(rIdExtRef); + if (relExtRef != null) { + _externalReferences.Add(relExtRef.TargetUri.OriginalString); + } + } + } + } + } + + internal void ReadAllTables() { + if (_nextTableID > 0) { + return; + } + _nextTableID = 1; + _nextPivotTableID = 1; + foreach (var ws in Worksheets) { + if (!(ws + is ExcelChartsheet)) //Fixes 15273. Chartsheets should be ignored. + { + foreach (var tbl in ws.Tables) { + if (tbl.Id >= _nextTableID) { + _nextTableID = tbl.Id + 1; + } + } + foreach (var pt in ws.PivotTables) { + if (pt.CacheID >= _nextPivotTableID) { + _nextPivotTableID = pt.CacheID + 1; + } + } + } + } + } }
diff --git a/EPPlus/ExcelWorkbookView.cs b/EPPlus/ExcelWorkbookView.cs index 69a1749..6772936 100644 --- a/EPPlus/ExcelWorkbookView.cs +++ b/EPPlus/ExcelWorkbookView.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,200 +13,148 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2011-11-02 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; + using System.Globalization; -using System.Text; using System.Xml; -namespace OfficeOpenXml -{ - /// <summary> - /// Access to workbook view properties - /// </summary> - public class ExcelWorkbookView : XmlHelper - { - #region ExcelWorksheetView Constructor - /// <summary> - /// Creates a new ExcelWorkbookView which provides access to all the - /// view states of the worksheet. - /// </summary> - /// <param name="ns"></param> - /// <param name="node"></param> - /// <param name="wb"></param> - internal ExcelWorkbookView(XmlNamespaceManager ns, XmlNode node, ExcelWorkbook wb) : - base(ns, node) - { - SchemaNodeOrder = wb.SchemaNodeOrder; - } - #endregion - const string LEFT_PATH="d:bookViews/d:workbookView/@xWindow"; - /// <summary> - /// Position of the upper left corner of the workbook window. In twips. - /// </summary> - public int Left - { - get - { - return GetXmlNodeInt(LEFT_PATH); - } - internal set - { - SetXmlNodeString(LEFT_PATH,value.ToString()); - } - } - const string TOP_PATH="d:bookViews/d:workbookView/@yWindow"; - /// <summary> - /// Position of the upper left corner of the workbook window. In twips. - /// </summary> - public int Top - { - get - { - return GetXmlNodeInt(TOP_PATH); - } - internal set - { - SetXmlNodeString(TOP_PATH, value.ToString()); - } - } - const string WIDTH_PATH="d:bookViews/d:workbookView/@windowWidth"; - /// <summary> - /// Width of the workbook window. In twips. - /// </summary> - public int Width - { - get - { - return GetXmlNodeInt(WIDTH_PATH); - } - internal set - { - SetXmlNodeString(WIDTH_PATH, value.ToString()); - } - } - const string HEIGHT_PATH="d:bookViews/d:workbookView/@windowHeight"; - /// <summary> - /// Height of the workbook window. In twips. - /// </summary> - public int Height - { - get - { - return GetXmlNodeInt(HEIGHT_PATH); - } - internal set - { - SetXmlNodeString(HEIGHT_PATH, value.ToString()); - } - } - const string MINIMIZED_PATH="d:bookViews/d:workbookView/@minimized"; - /// <summary> - /// If true the the workbook window is minimized. - /// </summary> - public bool Minimized - { - get - { - return GetXmlNodeBool(MINIMIZED_PATH); - } - set - { - SetXmlNodeString(MINIMIZED_PATH, value.ToString()); - } - } - const string SHOWVERTICALSCROLL_PATH = "d:bookViews/d:workbookView/@showVerticalScroll"; - /// <summary> - /// Show the vertical scrollbar - /// </summary> - public bool ShowVerticalScrollBar - { - get - { - return GetXmlNodeBool(SHOWVERTICALSCROLL_PATH,true); - } - set - { - SetXmlNodeBool(SHOWVERTICALSCROLL_PATH, value, true); - } - } - const string SHOWHORIZONTALSCR_PATH = "d:bookViews/d:workbookView/@showHorizontalScroll"; - /// <summary> - /// Show the horizontal scrollbar - /// </summary> - public bool ShowHorizontalScrollBar - { - get - { - return GetXmlNodeBool(SHOWHORIZONTALSCR_PATH, true); - } - set - { - SetXmlNodeBool(SHOWHORIZONTALSCR_PATH, value, true); - } - } - const string SHOWSHEETTABS_PATH = "d:bookViews/d:workbookView/@showSheetTabs"; - /// <summary> - /// Show the sheet tabs - /// </summary> - public bool ShowSheetTabs - { - get - { - return GetXmlNodeBool(SHOWSHEETTABS_PATH, true); - } - set - { - SetXmlNodeBool(SHOWSHEETTABS_PATH, value, true); - } - } - /// <summary> - /// Set the window position in twips - /// </summary> - /// <param name="left"></param> - /// <param name="top"></param> - /// <param name="width"></param> - /// <param name="height"></param> - public void SetWindowSize(int left, int top, int width, int height) - { - Left = left; - Top = top; - Width = width; - Height = height; - } - const string ACTIVETAB_PATH = "d:bookViews/d:workbookView/@activeTab"; - public int ActiveTab - { - get - { - var v=GetXmlNodeInt(ACTIVETAB_PATH); - if (v < 0) - return 0; - else - return v; +namespace OfficeOpenXml; - } - set - { - SetXmlNodeString(ACTIVETAB_PATH, value.ToString(CultureInfo.InvariantCulture)); - } - } +/// <summary> +/// Access to workbook view properties +/// </summary> +public class ExcelWorkbookView : XmlHelper { + /// <summary> + /// Creates a new ExcelWorkbookView which provides access to all the + /// view states of the worksheet. + /// </summary> + /// <param name="ns"></param> + /// <param name="node"></param> + /// <param name="wb"></param> + internal ExcelWorkbookView(XmlNamespaceManager ns, XmlNode node, ExcelWorkbook wb) + : base(ns, node) { + SchemaNodeOrder = wb.SchemaNodeOrder; + } + + private const string _leftPath = "d:bookViews/d:workbookView/@xWindow"; + + /// <summary> + /// Position of the upper left corner of the workbook window. In twips. + /// </summary> + public int Left { + get => GetXmlNodeInt(_leftPath); + internal set => SetXmlNodeString(_leftPath, value.ToString()); + } + + private const string _topPath = "d:bookViews/d:workbookView/@yWindow"; + + /// <summary> + /// Position of the upper left corner of the workbook window. In twips. + /// </summary> + public int Top { + get => GetXmlNodeInt(_topPath); + internal set => SetXmlNodeString(_topPath, value.ToString()); + } + + private const string _widthPath = "d:bookViews/d:workbookView/@windowWidth"; + + /// <summary> + /// Width of the workbook window. In twips. + /// </summary> + public int Width { + get => GetXmlNodeInt(_widthPath); + internal set => SetXmlNodeString(_widthPath, value.ToString()); + } + + private const string _heightPath = "d:bookViews/d:workbookView/@windowHeight"; + + /// <summary> + /// Height of the workbook window. In twips. + /// </summary> + public int Height { + get => GetXmlNodeInt(_heightPath); + internal set => SetXmlNodeString(_heightPath, value.ToString()); + } + + private const string _minimizedPath = "d:bookViews/d:workbookView/@minimized"; + + /// <summary> + /// If true the the workbook window is minimized. + /// </summary> + public bool Minimized { + get => GetXmlNodeBool(_minimizedPath); + set => SetXmlNodeString(_minimizedPath, value.ToString()); + } + + private const string _showverticalscrollPath = "d:bookViews/d:workbookView/@showVerticalScroll"; + + /// <summary> + /// Show the vertical scrollbar + /// </summary> + public bool ShowVerticalScrollBar { + get => GetXmlNodeBool(_showverticalscrollPath, true); + set => SetXmlNodeBool(_showverticalscrollPath, value, true); + } + + private const string _showhorizontalscrPath = "d:bookViews/d:workbookView/@showHorizontalScroll"; + + /// <summary> + /// Show the horizontal scrollbar + /// </summary> + public bool ShowHorizontalScrollBar { + get => GetXmlNodeBool(_showhorizontalscrPath, true); + set => SetXmlNodeBool(_showhorizontalscrPath, value, true); + } + + private const string _showsheettabsPath = "d:bookViews/d:workbookView/@showSheetTabs"; + + /// <summary> + /// Show the sheet tabs + /// </summary> + public bool ShowSheetTabs { + get => GetXmlNodeBool(_showsheettabsPath, true); + set => SetXmlNodeBool(_showsheettabsPath, value, true); + } + + /// <summary> + /// Set the window position in twips + /// </summary> + /// <param name="left"></param> + /// <param name="top"></param> + /// <param name="width"></param> + /// <param name="height"></param> + public void SetWindowSize(int left, int top, int width, int height) { + Left = left; + Top = top; + Width = width; + Height = height; + } + + private const string _activetabPath = "d:bookViews/d:workbookView/@activeTab"; + + public int ActiveTab { + get { + var v = GetXmlNodeInt(_activetabPath); + if (v < 0) { + return 0; + } + return v; } + set => SetXmlNodeString(_activetabPath, value.ToString(CultureInfo.InvariantCulture)); + } } - \ No newline at end of file
diff --git a/EPPlus/ExcelWorksheet.cs b/EPPlus/ExcelWorksheet.cs index c2bf6e7..2579a7e 100644 --- a/EPPlus/ExcelWorksheet.cs +++ b/EPPlus/ExcelWorksheet.cs
@@ -1,4144 +1,3913 @@ - /******************************************************************************* - * You may amend and distribute as you like, but don't remove this header! - * - * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. - * See http://www.codeplex.com/EPPlus for details. - * - * Copyright (C) 2011 Jan Källman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. +/******************************************************************************* +* You may amend and distribute as you like, but don't remove this header! +* +* EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. +* See http://www.codeplex.com/EPPlus for details. +* +* Copyright (C) 2011 Jan Källman +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php - * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html - * - * All code and executables are provided "as is" with no warranty either express or implied. - * The author accepts no liability for any damage or loss of business that this product may cause. - * - * Code change notes: - * - * Author Change Date - * ****************************************************************************** - * Jan Källman Initial Release 2011-11-02 - * Jan Källman Total rewrite 2010-03-01 - * Jan Källman License changed GPL-->LGPL 2011-12-27 - *******************************************************************************/ +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php +* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html +* +* All code and executables are provided "as is" with no warranty either express or implied. +* The author accepts no liability for any damage or loss of business that this product may cause. +* +* Code change notes: +* +* Author Change Date +* ****************************************************************************** +* Jan Källman Initial Release 2011-11-02 +* Jan Källman Total rewrite 2010-03-01 +* Jan Källman License changed GPL-->LGPL 2011-12-27 +*******************************************************************************/ + using System; -using System.Xml; +using System.Collections; using System.Collections.Generic; -using System.IO; -using System.Globalization; -using System.Text; -using System.Security; -using OfficeOpenXml.Style.XmlAccess; -using System.Text.RegularExpressions; -using OfficeOpenXml.Drawing.Vml; -using OfficeOpenXml.Table; -using OfficeOpenXml.DataValidation; -using OfficeOpenXml.Table.PivotTable; using System.ComponentModel; -using System.IO.Compression; +using System.Globalization; +using System.IO; +using System.Security; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; using OfficeOpenXml.ConditionalFormatting; -using OfficeOpenXml.Utils; +using OfficeOpenXml.DataValidation; +using OfficeOpenXml.Drawing.Vml; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; - -namespace OfficeOpenXml -{ - /// <summary> - /// Worksheet hidden enumeration - /// </summary> - public enum eWorkSheetHidden - { - /// <summary> - /// The worksheet is visible - /// </summary> - Visible, - /// <summary> - /// The worksheet is hidden but can be shown by the user via the user interface - /// </summary> - Hidden, - /// <summary> - /// The worksheet is hidden and cannot be shown by the user via the user interface - /// </summary> - VeryHidden +using OfficeOpenXml.Packaging; +using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.Table; +using OfficeOpenXml.Table.PivotTable; +using OfficeOpenXml.Utils; + +namespace OfficeOpenXml; + +/// <summary> +/// Worksheet hidden enumeration +/// </summary> +public enum eWorkSheetHidden { + /// <summary> + /// The worksheet is visible + /// </summary> + Visible, + + /// <summary> + /// The worksheet is hidden but can be shown by the user via the user interface + /// </summary> + Hidden, + + /// <summary> + /// The worksheet is hidden and cannot be shown by the user via the user interface + /// </summary> + VeryHidden, +} + +[Flags] +internal enum CellFlags { + //Merged = 0x1, + RichText = 0x2, + SharedFormula = 0x4, + ArrayFormula = 0x8, +} + +/// <summary> +/// Represents an Excel Chartsheet and provides access to its properties and methods +/// </summary> +public class ExcelChartsheet : ExcelWorksheet { + public ExcelChartsheet( + XmlNamespaceManager ns, + ExcelPackage pck, + string relId, + Uri uriWorksheet, + string sheetName, + int sheetId, + int positionId, + eWorkSheetHidden hidden) + : base(ns, pck, relId, uriWorksheet, sheetName, sheetId, positionId, hidden) {} +} + +/// <summary> +/// Represents an Excel worksheet and provides access to its properties and methods +/// </summary> +public class ExcelWorksheet : XmlHelper, IEqualityComparer<ExcelWorksheet> { + internal class Formulas { + public Formulas(ISourceCodeTokenizer tokenizer) { + _tokenizer = tokenizer; } - [Flags] - internal enum CellFlags - { - //Merged = 0x1, - RichText = 0x2, - SharedFormula = 0x4, - ArrayFormula = 0x8 + + public static string RemoveDummyFunction(string formula) { + const string dummyFunctionConcatenate = "\"&\""; + const string dummyFunctionPrefix = "IFERROR(__xludf.DUMMYFUNCTION(\""; + const string dummyFunctionSuffix = "\"),"; + + if (string.IsNullOrEmpty(formula)) { + return formula; + } + + // Look for Prefix + if (!formula.StartsWith(dummyFunctionPrefix)) { + return formula; + } + + // Look for Suffix + int index = formula.LastIndexOf(dummyFunctionSuffix); + if (index < 0) { + return formula; + } + + // Trim Suffix + formula = formula.Substring(0, index); + + // Trim Prefix + formula = formula.Replace(dummyFunctionPrefix, ""); + + // Remove string concatentations from long formulas. + // Google break the quoted string into 254 character segments which are concatenated. + if (formula.Length >= 254) { + formula = formula.Replace(dummyFunctionConcatenate, ""); + } + + // Replace doubled quotes with single quote + formula = formula.Replace("\"\"", "\""); + + // Return formula + return formula; } - /// <summary> - /// Represents an Excel Chartsheet and provides access to its properties and methods - /// </summary> - public class ExcelChartsheet : ExcelWorksheet - { - public ExcelChartsheet(XmlNamespaceManager ns, ExcelPackage pck, string relID, Uri uriWorksheet, string sheetName, int sheetID, int positionID, eWorkSheetHidden hidden) : - base(ns, pck, relID, uriWorksheet, sheetName, sheetID, positionID, hidden) - { + + private ISourceCodeTokenizer _tokenizer; + + internal int Index { get; set; } + + internal string Address { get; set; } + + internal bool IsArray { get; set; } + + public string Formula { get; set; } + + public int StartRow { get; set; } + + public int StartCol { get; set; } + + private IEnumerable<Token> Tokens { get; set; } + + internal string GetFormula(int row, int column, string worksheet) { + if ((StartRow == row && StartCol == column) || IsArray) { + return RemoveDummyFunction(Formula); + } + + if (Tokens == null) { + Tokens = _tokenizer.Tokenize(RemoveDummyFunction(Formula), worksheet); + } + + string f = ""; + foreach (var token in Tokens) { + if (token.TokenType == TokenType.ExcelAddress) { + var a = new ExcelFormulaAddress(token.Value); + f += a.GetOffset(row - StartRow, column - StartCol); + } else { + f += token.Value; } + } + return f; } - /// <summary> - /// Represents an Excel worksheet and provides access to its properties and methods - /// </summary> - public class ExcelWorksheet : XmlHelper, IEqualityComparer<ExcelWorksheet> - { - internal class Formulas + } + + /// <summary> + /// Collection containing merged cell addresses + /// </summary> + public class MergeCellsCollection : IEnumerable<string> { + internal MergeCellsCollection() {} + + internal CellStore<int> _cells = new(); + private List<string> _list = new(); + + internal List<string> List => _list; + + public string this[int row, int column] { + get { + int ix = -1; + if (_cells.Exists(row, column, ref ix) + && ix >= 0 + && ix + < List.Count) //Fixes issue 15075 { - public Formulas(ISourceCodeTokenizer tokenizer) - { - _tokenizer = tokenizer; - } - - public static string RemoveDummyFunction(string formula) - { - const string DummyFunctionConcatenate = "\"&\""; - const string DummyFunctionPrefix = "IFERROR(__xludf.DUMMYFUNCTION(\""; - const string DummyFunctionSuffix = "\"),"; - - if (string.IsNullOrEmpty(formula)) - return formula; - - // Look for Prefix - if (!formula.StartsWith(DummyFunctionPrefix)) - return formula; - - // Look for Suffix - int index = formula.LastIndexOf(DummyFunctionSuffix); - if (index < 0) - return formula; - - // Trim Suffix - formula = formula.Substring(0, index); - - // Trim Prefix - formula = formula.Replace(DummyFunctionPrefix, ""); - - // Remove string concatentations from long formulas. - // Google break the quoted string into 254 character segments which are concatenated. - if (formula.Length >= 254) - { - formula = formula.Replace(DummyFunctionConcatenate, ""); - } - - // Replace doubled quotes with single quote - formula = formula.Replace("\"\"", "\""); - - // Return formula - return formula; - } - - private ISourceCodeTokenizer _tokenizer; - internal int Index { get; set; } - internal string Address { get; set; } - internal bool IsArray { get; set; } - public string Formula { get; set; } - public int StartRow { get; set; } - public int StartCol { get; set; } - - private IEnumerable<Token> Tokens {get; set;} - - - internal string GetFormula(int row, int column, string worksheet) - { - if ((StartRow == row && StartCol == column) || IsArray) - { - return RemoveDummyFunction(Formula); - } - - if (Tokens == null) - { - Tokens = _tokenizer.Tokenize(RemoveDummyFunction(Formula), worksheet); - } - - string f = ""; - foreach (var token in Tokens) - { - if (token.TokenType == TokenType.ExcelAddress) - { - var a = new ExcelFormulaAddress(token.Value); - f += a.GetOffset(row - StartRow, column - StartCol); - } - else - { - f += token.Value; - } - } - return f; - } + return List[ix]; } - /// <summary> - /// Collection containing merged cell addresses - /// </summary> - public class MergeCellsCollection : IEnumerable<string> - { - internal MergeCellsCollection() - { + return null; + } + } - } - internal CellStore<int> _cells = new CellStore<int>(); - List<string> _list = new List<string>(); - internal List<string> List { get {return _list;} } - public string this[int row, int column] - { - get - { - int ix=-1; - if (_cells.Exists(row, column, ref ix) && ix >= 0 && ix < List.Count) //Fixes issue 15075 - { - return List[ix]; - } - else - { - return null; - } - } - } - public string this[int index] - { - get - { - return _list[index]; - } - } - internal void Add(ExcelAddressBase address, bool doValidate) - { - int ix=0; + public string this[int index] => _list[index]; - //Validate - if (doValidate && Validate(address) == false) - { - throw(new ArgumentException("Can't merge and already merged range")); - } - lock(this) - { - ix = _list.Count; - _list.Add(address.Address); - SetIndex(address, ix); - } - } + internal void Add(ExcelAddressBase address, bool doValidate) { + int ix = 0; - private bool Validate(ExcelAddressBase address) - { - int ix=0; - if(_cells.Exists(address._fromRow, address._fromCol, ref ix)) - { - if (ix>=0 && ix < _list.Count && _list[ix]!=null && address.Address == _list[ix]) - { - return true; - } - else - { - return false; - } - } - - var cse = new CellsStoreEnumerator<int>(_cells, address._fromRow, address._fromCol, address._toRow, address._toCol); - //cells - while(cse.Next()) - { - return false; - } - //Entire column - cse = new CellsStoreEnumerator<int>(_cells, 0, address._fromCol, 0, address._toCol); - while (cse.Next()) - { - return false; - } - //Entire row - cse = new CellsStoreEnumerator<int>(_cells, address._fromRow, 0, address._toRow, 0); - while (cse.Next()) - { - return false; - } - return true; - } + //Validate + if (doValidate && Validate(address) == false) { + throw (new ArgumentException("Can't merge and already merged range")); + } + lock (this) { + ix = _list.Count; + _list.Add(address.Address); + SetIndex(address, ix); + } + } - internal void SetIndex(ExcelAddressBase address, int ix) - { - if (address._fromRow == 1 && address._toRow == ExcelPackage.MaxRows) //Entire row - { - for (int col = address._fromCol; col <= address._toCol; col++) - { - _cells.SetValue(0, col, ix); - } - } - else if (address._fromCol == 1 && address._toCol == ExcelPackage.MaxColumns) //Entire row - { - for (int row = address._fromRow; row <= address._toRow; row++) - { - _cells.SetValue(row, 0, ix); - } - } - else - { - for (int col = address._fromCol; col <= address._toCol; col++) - { - for (int row = address._fromRow; row <= address._toRow; row++) - { - _cells.SetValue(row, col, ix); - } - } - } - } - public int Count - { - get - { - return _list.Count; - } - } - internal void Remove(string Item) - { - _list.Remove(Item); - } - #region IEnumerable<string> Members - - public IEnumerator<string> GetEnumerator() - { - return _list.GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _list.GetEnumerator(); - } - - #endregion - internal void Clear(ExcelAddressBase Destination) - { - var cse = new CellsStoreEnumerator<int>(_cells, Destination._fromRow, Destination._fromCol, Destination._toRow, Destination._toCol); - var used=new HashSet<int>(); - while(cse.Next()) - { - var v=cse.Value; - if (!used.Contains(v) && _list[v]!=null) - { - var adr=new ExcelAddressBase(_list[v]); - if (!(Destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Inside || Destination.Collide(adr)==ExcelAddressBase.eAddressCollition.Equal)) - { - throw(new InvalidOperationException(string.Format("Can't delete merged cells. A range is partly merged with the deleted range. {0}", adr._address))); - } - used.Add(v); - } - } - - _cells.Clear(Destination._fromRow, Destination._fromCol, Destination._toRow - Destination._fromRow + 1, Destination._toCol - Destination._fromCol + 1); - foreach(var i in used) - { - _list[i] = null; - } - } + private bool Validate(ExcelAddressBase address) { + int ix = 0; + if (_cells.Exists(address._fromRow, address._fromCol, ref ix)) { + if (ix >= 0 && ix < _list.Count && _list[ix] != null && address.Address == _list[ix]) { + return true; } - internal CellStore<object> _values; - internal CellStore<string> _types; - internal CellStore<int> _styles; - internal CellStore<object> _formulas; - internal FlagCellStore _flags; - internal CellStore<List<Token>> _formulaTokens; + return false; + } - internal CellStore<Uri> _hyperLinks; - internal CellStore<ExcelComment> _commentsStore; + var cse = new CellsStoreEnumerator<int>( + _cells, + address._fromRow, + address._fromCol, + address._toRow, + address._toCol); + //cells + while (cse.Next()) { + return false; + } + //Entire column + cse = new(_cells, 0, address._fromCol, 0, address._toCol); + while (cse.Next()) { + return false; + } + //Entire row + cse = new(_cells, address._fromRow, 0, address._toRow, 0); + while (cse.Next()) { + return false; + } + return true; + } - internal Dictionary<int, Formulas> _sharedFormulas = new Dictionary<int, Formulas>(); - internal int _minCol = ExcelPackage.MaxColumns; - internal int _maxCol = 0; - #region Worksheet Private Properties - internal ExcelPackage _package; - private Uri _worksheetUri; - private string _name; - private int _sheetID; - private int _positionID; - private string _relationshipID; - private XmlDocument _worksheetXml; - internal ExcelWorksheetView _sheetView; - internal ExcelHeaderFooter _headerFooter; - #endregion - #region ExcelWorksheet Constructor - /// <summary> - /// A worksheet - /// </summary> - /// <param name="ns">Namespacemanager</param> - /// <param name="excelPackage">Package</param> - /// <param name="relID">Relationship ID</param> - /// <param name="uriWorksheet">URI</param> - /// <param name="sheetName">Name of the sheet</param> - /// <param name="sheetID">Sheet id</param> - /// <param name="positionID">Position</param> - /// <param name="hide">hide</param> - public ExcelWorksheet(XmlNamespaceManager ns, ExcelPackage excelPackage, string relID, - Uri uriWorksheet, string sheetName, int sheetID, int positionID, - eWorkSheetHidden hide) : - base(ns, null) - { - SchemaNodeOrder = new string[] { "sheetPr", "tabColor", "outlinePr", "pageSetUpPr", "dimension", "sheetViews", "sheetFormatPr", "cols", "sheetData", "sheetProtection", "protectedRanges","scenarios", "autoFilter", "sortState", "dataConsolidate", "customSheetViews", "customSheetViews", "mergeCells", "phoneticPr", "conditionalFormatting", "dataValidations", "hyperlinks", "printOptions", "pageMargins", "pageSetup", "headerFooter", "linePrint", "rowBreaks", "colBreaks", "customProperties", "cellWatches", "ignoredErrors", "smartTags", "drawing", "legacyDrawing", "legacyDrawingHF", "picture", "oleObjects", "activeXControls", "webPublishItems", "tableParts" , "extLst" }; - _package = excelPackage; - _relationshipID = relID; - _worksheetUri = uriWorksheet; - _name = sheetName; - _sheetID = sheetID; - _positionID = positionID; - Hidden = hide; - - /**** Cellstore ****/ - _values=new CellStore<object>(); - _types = new CellStore<string>(); - _styles = new CellStore<int>(); - _formulas = new CellStore<object>(); - _flags = new FlagCellStore(); - _commentsStore = new CellStore<ExcelComment>(); - _hyperLinks = new CellStore<Uri>(); - - _names = new ExcelNamedRangeCollection(Workbook,this); + internal void SetIndex(ExcelAddressBase address, int ix) { + if (address._fromRow == 1 + && address._toRow + == ExcelPackage.MaxRows) //Entire row + { + for (int col = address._fromCol; col <= address._toCol; col++) { + _cells.SetValue(0, col, ix); + } + } else if (address._fromCol == 1 + && address._toCol + == ExcelPackage.MaxColumns) //Entire row + { + for (int row = address._fromRow; row <= address._toRow; row++) { + _cells.SetValue(row, 0, ix); + } + } else { + for (int col = address._fromCol; col <= address._toCol; col++) { + for (int row = address._fromRow; row <= address._toRow; row++) { + _cells.SetValue(row, col, ix); + } + } + } + } - CreateXml(); - TopNode = _worksheetXml.DocumentElement; + public int Count => _list.Count; + + internal void Remove(string item) { + _list.Remove(item); + } + + public IEnumerator<string> GetEnumerator() { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _list.GetEnumerator(); + } + + internal void Clear(ExcelAddressBase destination) { + var cse = new CellsStoreEnumerator<int>( + _cells, + destination._fromRow, + destination._fromCol, + destination._toRow, + destination._toCol); + var used = new HashSet<int>(); + while (cse.Next()) { + var v = cse.Value; + if (!used.Contains(v) && _list[v] != null) { + var adr = new ExcelAddressBase(_list[v]); + if (!(destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Inside + || destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Equal)) { + throw (new InvalidOperationException( + string.Format( + "Can't delete merged cells. A range is partly merged with the deleted range. {0}", + adr._address))); + } + used.Add(v); + } + } + + _cells.Clear( + destination._fromRow, + destination._fromCol, + destination._toRow - destination._fromRow + 1, + destination._toCol - destination._fromCol + 1); + foreach (var i in used) { + _list[i] = null; + } + } + } + + internal CellStore<object> _values; + internal CellStore<string> _types; + internal CellStore<int> _styles; + internal CellStore<object> _formulas; + internal FlagCellStore _flags; + internal CellStore<List<Token>> _formulaTokens; + + internal CellStore<Uri> _hyperLinks; + internal CellStore<ExcelComment> _commentsStore; + + internal Dictionary<int, Formulas> _sharedFormulas = new(); + internal int _minCol = ExcelPackage.MaxColumns; + internal int _maxCol = 0; + + internal ExcelPackage _package; + private Uri _worksheetUri; + private string _name; + private int _sheetID; + private int _positionID; + private string _relationshipID; + private XmlDocument _worksheetXml; + internal ExcelWorksheetView _sheetView; + internal ExcelHeaderFooter _headerFooter; + + /// <summary> + /// A worksheet + /// </summary> + /// <param name="ns">Namespacemanager</param> + /// <param name="excelPackage">Package</param> + /// <param name="relId">Relationship ID</param> + /// <param name="uriWorksheet">URI</param> + /// <param name="sheetName">Name of the sheet</param> + /// <param name="sheetId">Sheet id</param> + /// <param name="positionId">Position</param> + /// <param name="hide">hide</param> + public ExcelWorksheet( + XmlNamespaceManager ns, + ExcelPackage excelPackage, + string relId, + Uri uriWorksheet, + string sheetName, + int sheetId, + int positionId, + eWorkSheetHidden hide) + : base(ns, null) { + SchemaNodeOrder = new[] { + "sheetPr", + "tabColor", + "outlinePr", + "pageSetUpPr", + "dimension", + "sheetViews", + "sheetFormatPr", + "cols", + "sheetData", + "sheetProtection", + "protectedRanges", + "scenarios", + "autoFilter", + "sortState", + "dataConsolidate", + "customSheetViews", + "customSheetViews", + "mergeCells", + "phoneticPr", + "conditionalFormatting", + "dataValidations", + "hyperlinks", + "printOptions", + "pageMargins", + "pageSetup", + "headerFooter", + "linePrint", + "rowBreaks", + "colBreaks", + "customProperties", + "cellWatches", + "ignoredErrors", + "smartTags", + "drawing", + "legacyDrawing", + "legacyDrawingHF", + "picture", + "oleObjects", + "activeXControls", + "webPublishItems", + "tableParts", + "extLst", + }; + _package = excelPackage; + _relationshipID = relId; + _worksheetUri = uriWorksheet; + _name = sheetName; + _sheetID = sheetId; + _positionID = positionId; + Hidden = hide; + + /**** Cellstore ****/ + _values = new(); + _types = new(); + _styles = new(); + _formulas = new(); + _flags = new(); + _commentsStore = new(); + _hyperLinks = new(); + + _names = new(Workbook, this); + + CreateXml(); + TopNode = _worksheetXml.DocumentElement; + } + + /// <summary> + /// The Uri to the worksheet within the package + /// </summary> + internal Uri WorksheetUri => (_worksheetUri); + + /// <summary> + /// The Zip.ZipPackagePart for the worksheet within the package + /// </summary> + internal ZipPackagePart Part => (_package.Package.GetPart(WorksheetUri)); + + /// <summary> + /// The ID for the worksheet's relationship with the workbook in the package + /// </summary> + internal string RelationshipID => (_relationshipID); + + /// <summary> + /// The unique identifier for the worksheet. + /// </summary> + internal int SheetID => (_sheetID); + + /// <summary> + /// The position of the worksheet. + /// </summary> + internal int PositionID { + get => (_positionID); + set => _positionID = value; + } + + /// <summary> + /// The index in the worksheets collection + /// </summary> + public int Index => (_positionID); + + /// <summary> + /// Address for autofilter + /// <seealso cref="ExcelRangeBase.AutoFilter" /> + /// </summary> + public ExcelAddressBase AutoFilterAddress { + get { + CheckSheetType(); + string address = GetXmlNodeString("d:autoFilter/@ref"); + if (address == "") { + return null; + } + return new(address); + } + internal set { + CheckSheetType(); + SetXmlNodeString("d:autoFilter/@ref", value.Address); + } + } + + internal void CheckSheetType() { + if (this is ExcelChartsheet) { + throw (new NotSupportedException( + "This property or method is not supported for a Chartsheet")); + } + } + + /// <summary> + /// Returns a ExcelWorksheetView object that allows you to set the view state properties of the worksheet + /// </summary> + public ExcelWorksheetView View { + get { + if (_sheetView == null) { + XmlNode node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager); + if (node == null) { + CreateNode("d:sheetViews/d:sheetView"); //this one shouls always exist. but check anyway + node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager); + } + _sheetView = new(NameSpaceManager, node, this); + } + return (_sheetView); + } + } + + /// <summary> + /// The worksheet's display name as it appears on the tab + /// </summary> + public string Name { + get => (_name); + set { + if (value == _name) { + return; + } + value = _package.Workbook.Worksheets.ValidateFixSheetName(value); + foreach (var ws in Workbook.Worksheets) { + if (ws.PositionID != PositionID + && ws.Name.Equals(value, StringComparison.InvariantCultureIgnoreCase)) { + throw (new ArgumentException("Worksheet name must be unique")); + } + } + _package.Workbook.SetXmlNodeString( + string.Format("d:sheets/d:sheet[@sheetId={0}]/@name", _sheetID), + value); + ChangeNames(value); + + _name = value; + } + } + + private void ChangeNames(string value) { + //Renames name in this Worksheet; + foreach (var n in Workbook.Names) { + if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue == null) { + n.ChangeWorksheet(_name, value); + } + } + foreach (var ws in Workbook.Worksheets) { + if (!(ws is ExcelChartsheet)) { + foreach (var n in ws.Names) { + if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue == null) { + n.ChangeWorksheet(_name, value); + } + } + } + } + } + + internal ExcelNamedRangeCollection _names; + + /// <summary> + /// Provides access to named ranges + /// </summary> + public ExcelNamedRangeCollection Names { + get { + CheckSheetType(); + return _names; + } + } + + /// <summary> + /// Indicates if the worksheet is hidden in the workbook + /// </summary> + public eWorkSheetHidden Hidden { + get { + string state = _package.Workbook.GetXmlNodeString( + string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID)); + if (state == "hidden") { + return eWorkSheetHidden.Hidden; + } + if (state == "veryHidden") { + return eWorkSheetHidden.VeryHidden; + } + return eWorkSheetHidden.Visible; + } + set { + if (value == eWorkSheetHidden.Visible) { + _package.Workbook.DeleteNode( + string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID)); + } else { + string v; + v = value.ToString(); + v = v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1); + _package.Workbook.SetXmlNodeString( + string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID), + v); + } + } + } + + private double _defaultRowHeight = double.NaN; + + /// <summary> + /// Get/set the default height of all rows in the worksheet + /// </summary> + public double DefaultRowHeight { + get { + CheckSheetType(); + if (double.IsNaN(_defaultRowHeight)) { + _defaultRowHeight = GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight"); + if (double.IsNaN(_defaultRowHeight)) { + _defaultRowHeight = 15; // Excel default height + } + } + return _defaultRowHeight; + } + set { + CheckSheetType(); + _defaultRowHeight = value; + SetXmlNodeString( + "d:sheetFormatPr/@defaultRowHeight", + value.ToString(CultureInfo.InvariantCulture)); + SetXmlNodeBool("d:sheetFormatPr/@customHeight", value != 15); + + if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth"))) { + DefaultColWidth = 9.140625; + } + } + } + + /// <summary> + /// Get/set the default width of all rows in the worksheet + /// </summary> + public double DefaultColWidth { + get { + CheckSheetType(); + double ret = GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth"); + if (double.IsNaN(ret)) { + ret = 9.140625; // Excel's default width + } + return ret; + } + set { + CheckSheetType(); + SetXmlNodeString( + "d:sheetFormatPr/@defaultColWidth", + value.ToString(CultureInfo.InvariantCulture)); + + if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight"))) { + DefaultRowHeight = 15; + } + } + } + + /** <outlinePr applyStyles="1" summaryBelow="0" summaryRight="0" /> **/ + private const string _outLineSummaryBelowPath = "d:sheetPr/d:outlinePr/@summaryBelow"; + + /// <summary> + /// Summary rows below details + /// </summary> + public bool OutLineSummaryBelow { + get { + CheckSheetType(); + return GetXmlNodeBool(_outLineSummaryBelowPath); + } + set { + CheckSheetType(); + SetXmlNodeString(_outLineSummaryBelowPath, value ? "1" : "0"); + } + } + + private const string _outLineSummaryRightPath = "d:sheetPr/d:outlinePr/@summaryRight"; + + /// <summary> + /// Summary rows to right of details + /// </summary> + public bool OutLineSummaryRight { + get { + CheckSheetType(); + return GetXmlNodeBool(_outLineSummaryRightPath); + } + set { + CheckSheetType(); + SetXmlNodeString(_outLineSummaryRightPath, value ? "1" : "0"); + } + } + + private const string _outLineApplyStylePath = "d:sheetPr/d:outlinePr/@applyStyles"; + + /// <summary> + /// Automatic styles + /// </summary> + public bool OutLineApplyStyle { + get { + CheckSheetType(); + return GetXmlNodeBool(_outLineApplyStylePath); + } + set { + CheckSheetType(); + SetXmlNodeString(_outLineApplyStylePath, value ? "1" : "0"); + } + } + + private const string _tabColorPath = "d:sheetPr/d:tabColor/@rgb"; + private const string _codeModuleNamePath = "d:sheetPr/@codeName"; + + internal string CodeModuleName { + get => GetXmlNodeString(_codeModuleNamePath); + set => SetXmlNodeString(_codeModuleNamePath, value); + } + + internal void CodeNameChange(string value) { + CodeModuleName = value; + } + + /// <summary> + /// The XML document holding the worksheet data. + /// All column, row, cell, pagebreak, merged cell and hyperlink-data are loaded into memory and removed from the document when loading the document. + /// </summary> + public XmlDocument WorksheetXml => (_worksheetXml); + + internal ExcelVmlDrawingCommentCollection _vmlDrawings; + + /// <summary> + /// Vml drawings. underlaying object for comments + /// </summary> + internal ExcelVmlDrawingCommentCollection VmlDrawingsComments { + get { + if (_vmlDrawings == null) { + CreateVmlCollection(); + } + return _vmlDrawings; + } + } + + internal ExcelCommentCollection _comments; + + /// <summary> + /// Collection of comments + /// </summary> + public ExcelCommentCollection Comments { + get { + CheckSheetType(); + if (_comments == null) { + CreateVmlCollection(); + _comments = new(_package, this, NameSpaceManager); + } + return _comments; + } + } + + private void CreateVmlCollection() { + var vmlNode = _worksheetXml.DocumentElement.SelectSingleNode( + "d:legacyDrawing/@r:id", + NameSpaceManager); + if (vmlNode == null) { + _vmlDrawings = new(_package, this, null); + } else { + if (Part.RelationshipExists(vmlNode.Value)) { + var rel = Part.GetRelationship(vmlNode.Value); + var vmlUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); + + _vmlDrawings = new(_package, this, vmlUri); + _vmlDrawings.RelId = rel.Id; + } + } + } + + private void CreateXml() { + _worksheetXml = new(); + _worksheetXml.PreserveWhitespace = ExcelPackage._preserveWhitespace; + ZipPackagePart packPart = _package.Package.GetPart(WorksheetUri); + string xml = ""; + + // First Columns, rows, cells, mergecells, hyperlinks and pagebreakes are loaded from a xmlstream to optimize speed... + Stream stream = packPart.GetStream(); + + XmlTextReader xr = new XmlTextReader(stream); + xr.ProhibitDtd = true; + xr.WhitespaceHandling = WhitespaceHandling.None; + LoadColumns(xr); //columnXml + long start = stream.Position; + LoadCells(xr); + var nextElementLength = GetAttributeLength(xr); + long end = stream.Position - nextElementLength; + LoadMergeCells(xr); + LoadHyperLinks(xr); + LoadRowPageBreakes(xr); + LoadColPageBreakes(xr); + //...then the rest of the Xml is extracted and loaded into the WorksheetXml document. + stream.Seek(0, SeekOrigin.Begin); + Encoding encoding; + xml = GetWorkSheetXml(stream, start, end, out encoding); + + //first char is invalid sometimes?? + if (xml[0] != '<') { + LoadXmlSafe(_worksheetXml, xml.Substring(1, xml.Length - 1), encoding); + } else { + LoadXmlSafe(_worksheetXml, xml, encoding); + } + + ClearNodes(); + } + + /// <summary> + /// Get the lenth of the attributes + /// Conditional formatting attributes can be extremly long som get length of the attributes to finetune position. + /// </summary> + /// <param name="xr"></param> + /// <returns></returns> + private int GetAttributeLength(XmlTextReader xr) { + if (xr.NodeType != XmlNodeType.Element) { + return 0; + } + var length = 0; + + for (int i = 0; i < xr.AttributeCount; i++) { + var a = xr.GetAttribute(i); + length += string.IsNullOrEmpty(a) ? 0 : a.Length; + } + return length; + } + + private void LoadRowPageBreakes(XmlTextReader xr) { + if (!ReadUntil(xr, "rowBreaks", "colBreaks")) { + return; + } + while (xr.Read()) { + if (xr.LocalName == "brk") { + if (xr.NodeType == XmlNodeType.Element) { + int id; + if (int.TryParse(xr.GetAttribute("id"), out id)) { + Row(id).PageBreak = true; + } + } + } else { + break; + } + } + } + + private void LoadColPageBreakes(XmlTextReader xr) { + if (!ReadUntil(xr, "colBreaks")) { + return; + } + while (xr.Read()) { + if (xr.LocalName == "brk") { + if (xr.NodeType == XmlNodeType.Element) { + int id; + if (int.TryParse(xr.GetAttribute("id"), out id)) { + Column(id).PageBreak = true; + } + } + } else { + break; + } + } + } + + private void ClearNodes() { + if (_worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager) != null) { + _worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager).RemoveAll(); + } + if (_worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager) != null) { + _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager).RemoveAll(); + } + if (_worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager) != null) { + _worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager).RemoveAll(); + } + if (_worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager) != null) { + _worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager).RemoveAll(); + } + if (_worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager) != null) { + _worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager).RemoveAll(); + } + } + + private const int _blocksize = 8192; + + private string GetWorkSheetXml(Stream stream, long start, long end, out Encoding encoding) { + StreamReader sr = new StreamReader(stream); + int length = 0; + char[] block; + int pos; + StringBuilder sb = new StringBuilder(); + Match startmMatch, + endMatch; + do { + int size = stream.Length < _blocksize ? (int)stream.Length : _blocksize; + block = new char[size]; + pos = sr.ReadBlock(block, 0, size); + sb.Append(block, 0, pos); + length += size; + } while (length < start + 20 && length < end); + startmMatch = Regex.Match(sb.ToString(), string.Format("(<[^>]*{0}[^>]*>)", "sheetData")); + if (!startmMatch.Success) //Not found + { + encoding = sr.CurrentEncoding; + return sb.ToString(); + } + string s = sb.ToString(); + string xml = s.Substring(0, startmMatch.Index); + if (startmMatch.Value.EndsWith("/>")) { + xml += s.Substring(startmMatch.Index, s.Length - startmMatch.Index); + } else { + if (sr.Peek() != -1) { + /**** Fixes issue 14788. Fix by Philip Garrett ****/ + long endSeekStart = end; + + while (endSeekStart >= 0) { + endSeekStart = Math.Max(endSeekStart - _blocksize, 0); + int size = (int)(end - endSeekStart); + stream.Seek(endSeekStart, SeekOrigin.Begin); + block = new char[size]; + sr = new(stream); + pos = sr.ReadBlock(block, 0, size); + sb = new(); + sb.Append(block, 0, pos); + s = sb.ToString(); + endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData")); + if (endMatch.Success) { + break; + } + } + } + endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData")); + xml += + "<sheetData/>" + + s.Substring( + endMatch.Index + endMatch.Length, + s.Length - (endMatch.Index + endMatch.Length)); + } + if (sr.Peek() > -1) { + xml += sr.ReadToEnd(); + } + + encoding = sr.CurrentEncoding; + return xml; + } + + private void GetBlockPos(string xml, string tag, ref int start, ref int end) { + Match startmMatch, + endMatch; + startmMatch = Regex.Match(xml.Substring(start), string.Format("(<[^>]*{0}[^>]*>)", tag)); //"<[a-zA-Z:]*" + tag + "[?]*>"); + + if (!startmMatch.Success) //Not found + { + start = -1; + end = -1; + return; + } + var startPos = startmMatch.Index + start; + if (startmMatch.Value.Substring(startmMatch.Value.Length - 2, 1) == "/") { + end = startPos + startmMatch.Length; + } else { + endMatch = Regex.Match(xml.Substring(start), string.Format("(</[^>]*{0}[^>]*>)", tag)); + if (endMatch.Success) { + end = endMatch.Index + endMatch.Length + start; + } + } + start = startPos; + } + + private bool ReadUntil(XmlTextReader xr, params string[] tagName) { + if (xr.EOF) { + return false; + } + while (!Array.Exists(tagName, tag => xr.LocalName.EndsWith(tag))) { + xr.Read(); + if (xr.EOF) { + return false; + } + } + return (xr.LocalName.EndsWith(tagName[0])); + } + + private void LoadColumns( + XmlTextReader xr) //(string xml) + { + var colList = new List<IRangeId>(); + if (ReadUntil(xr, "cols", "sheetData")) { + //if (xml != "") + //{ + //var xr=new XmlTextReader(new StringReader(xml)); + while (xr.Read()) { + if (xr.NodeType == XmlNodeType.Whitespace) { + continue; + } + if (xr.LocalName != "col") { + break; + } + if (xr.NodeType == XmlNodeType.Element) { + int min = int.Parse(xr.GetAttribute("min")); + + ExcelColumn col = new ExcelColumn(this, min); + + col.ColumnMax = int.Parse(xr.GetAttribute("max")); + col.Width = + xr.GetAttribute("width") == null + ? 0 + : double.Parse(xr.GetAttribute("width"), CultureInfo.InvariantCulture); + col.BestFit = + xr.GetAttribute("bestFit") != null && xr.GetAttribute("bestFit") == "1" + ? true + : false; + col.Collapsed = + xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1" + ? true + : false; + col.Phonetic = + xr.GetAttribute("phonetic") != null && xr.GetAttribute("phonetic") == "1" + ? true + : false; + col.OutlineLevel = (short)(xr.GetAttribute("outlineLevel") == null + ? 0 + : int.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture)); + col.Hidden = + xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false; + _values.SetValue(0, min, col); + + int style; + if (!(xr.GetAttribute("style") == null + || !int.TryParse(xr.GetAttribute("style"), out style))) { + _styles.SetValue(0, min, style); + } + } + } + } + } + + /// <summary> + /// Read until the node is found. If not found the xmlreader is reseted. + /// </summary> + /// <param name="xr">The reader</param> + /// <param name="nodeText">Text to search for</param> + /// <param name="altNode">Alternative text to search for</param> + /// <returns></returns> + private static bool ReadXmlReaderUntil(XmlTextReader xr, string nodeText, string altNode) { + do { + if (xr.LocalName == nodeText || xr.LocalName == altNode) { + return true; + } + } while (xr.Read()); + xr.Close(); + return false; + } + + /// <summary> + /// Load Hyperlinks + /// </summary> + /// <param name="xr">The reader</param> + private void LoadHyperLinks(XmlTextReader xr) { + if (!ReadUntil(xr, "hyperlinks", "rowBreaks", "colBreaks")) { + return; + } + while (xr.Read()) { + if (xr.LocalName == "hyperlink") { + int fromRow, + fromCol, + toRow, + toCol; + ExcelCellBase.GetRowColFromAddress( + xr.GetAttribute("ref"), + out fromRow, + out fromCol, + out toRow, + out toCol); + ExcelHyperLink hl = null; + if (xr.GetAttribute("id", ExcelPackage._schemaRelationships) != null) { + var rId = xr.GetAttribute("id", ExcelPackage._schemaRelationships); + var uri = Part.GetRelationship(rId).TargetUri; + + // Get Location, if any. EPPlus Bug 15517 + var location = xr.GetAttribute("location"); + location = (string.IsNullOrEmpty(location)) ? "" : "#" + location; + + if (uri.IsAbsoluteUri) { + try { + hl = new(uri.AbsoluteUri + location); + } catch { + hl = new(uri.OriginalString + location, UriKind.Absolute); + } + } else { + hl = new(uri.OriginalString + location, UriKind.Relative); + } + + hl.RId = rId; + Part.DeleteRelationship(rId); //Delete the relationship, it is recreated when we save the package. + } else if (xr.GetAttribute("location") != null) { + hl = new(xr.GetAttribute("location"), xr.GetAttribute("display")); + hl.RowSpann = toRow - fromRow; + hl.ColSpann = toCol - fromCol; } - #endregion - /// <summary> - /// The Uri to the worksheet within the package - /// </summary> - internal Uri WorksheetUri { get { return (_worksheetUri); } } - /// <summary> - /// The Zip.ZipPackagePart for the worksheet within the package - /// </summary> - internal Packaging.ZipPackagePart Part { get { return (_package.Package.GetPart(WorksheetUri)); } } - /// <summary> - /// The ID for the worksheet's relationship with the workbook in the package - /// </summary> - internal string RelationshipID { get { return (_relationshipID); } } - /// <summary> - /// The unique identifier for the worksheet. - /// </summary> - internal int SheetID { get { return (_sheetID); } } - /// <summary> - /// The position of the worksheet. - /// </summary> - internal int PositionID { get { return (_positionID); } set { _positionID = value; } } - #region Worksheet Public Properties - /// <summary> - /// The index in the worksheets collection - /// </summary> - public int Index { get { return (_positionID); } } - /// <summary> - /// Address for autofilter - /// <seealso cref="ExcelRangeBase.AutoFilter" /> - /// </summary> - public ExcelAddressBase AutoFilterAddress - { - get - { - CheckSheetType(); - string address = GetXmlNodeString("d:autoFilter/@ref"); - if (address == "") - { - return null; - } - else - { - return new ExcelAddressBase(address); - } - } - internal set - { - CheckSheetType(); - SetXmlNodeString("d:autoFilter/@ref", value.Address); - } + string tt = xr.GetAttribute("tooltip"); + if (!string.IsNullOrEmpty(tt)) { + hl.ToolTip = tt; + } + _hyperLinks.SetValue(fromRow, fromCol, hl); + } else { + break; + } + } + } + + /// <summary> + /// Load cells + /// </summary> + /// <param name="xr">The reader</param> + private void LoadCells(XmlTextReader xr) { + //var cellList=new List<IRangeID>(); + //var rowList = new List<IRangeID>(); + //var formulaList = new List<IRangeID>(); + ReadUntil(xr, "sheetData", "mergeCells", "hyperlinks", "rowBreaks", "colBreaks"); + ExcelAddressBase address = null; + string type = ""; + int style = 0; + int row = 0; + int col = 0; + xr.Read(); + + while (!xr.EOF) { + while (xr.NodeType == XmlNodeType.EndElement) { + xr.Read(); + } + if (xr.LocalName == "row") { + var r = xr.GetAttribute("r"); + if (r == null) { + row++; + } else { + row = Convert.ToInt32(r); } - internal void CheckSheetType() - { - if (this is ExcelChartsheet) - { - throw (new NotSupportedException("This property or method is not supported for a Chartsheet")); - } + if (DoAddRow(xr)) { + _values.SetValue(row, 0, AddRow(xr, row)); + if (xr.GetAttribute("s") != null) { + _styles.SetValue(row, 0, int.Parse(xr.GetAttribute("s"), CultureInfo.InvariantCulture)); + } + } + xr.Read(); + } else if (xr.LocalName == "c") { + //if (cell != null) cellList.Add(cell); + //cell = new ExcelCell(this, xr.GetAttribute("r")); + var r = xr.GetAttribute("r"); + if (r == null) { + //Handle cells with no reference + col++; + address = new(row, col, row, col); + } else { + address = new(r); + col = address._fromCol; } - /// <summary> - /// Returns a ExcelWorksheetView object that allows you to set the view state properties of the worksheet - /// </summary> - public ExcelWorksheetView View - { - get - { - if (_sheetView == null) - { - XmlNode node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager); - if (node == null) - { - CreateNode("d:sheetViews/d:sheetView"); //this one shouls always exist. but check anyway - node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager); - } - _sheetView = new ExcelWorksheetView(NameSpaceManager, node, this); - } - return (_sheetView); - } - } + //Datetype + if (xr.GetAttribute("t") != null) { + type = xr.GetAttribute("t"); + _types.SetValue(address._fromRow, address._fromCol, type); + } else { + type = ""; + } + //Style + if (xr.GetAttribute("s") != null) { + style = int.Parse(xr.GetAttribute("s")); + _styles.SetValue(address._fromRow, address._fromCol, style); + _values.SetValue(address._fromRow, address._fromCol, null); //TODO:Better Performance ?? + } else { + style = 0; + } + xr.Read(); + } else if (xr.LocalName == "v") { + SetValueFromXml(xr, type, style, address._fromRow, address._fromCol); - /// <summary> - /// The worksheet's display name as it appears on the tab - /// </summary> - public string Name - { - get { return (_name); } - set - { - if (value == _name) return; - value=_package.Workbook.Worksheets.ValidateFixSheetName(value); - foreach(var ws in Workbook.Worksheets) - { - if(ws.PositionID!=PositionID && ws.Name.Equals(value,StringComparison.InvariantCultureIgnoreCase)) - { - throw (new ArgumentException("Worksheet name must be unique")); - } - } - _package.Workbook.SetXmlNodeString(string.Format("d:sheets/d:sheet[@sheetId={0}]/@name", _sheetID), value); - ChangeNames(value); + xr.Read(); + } else if (xr.LocalName == "f") { + string t = xr.GetAttribute("t"); + if (t == null) { + _formulas.SetValue(address._fromRow, address._fromCol, xr.ReadElementContentAsString()); + _values.SetValue(address._fromRow, address._fromCol, null); + //formulaList.Add(cell); + } else if (t == "shared") { + string si = xr.GetAttribute("si"); + if (si != null) { + var sfIndex = int.Parse(si); + _formulas.SetValue(address._fromRow, address._fromCol, sfIndex); + _values.SetValue(address._fromRow, address._fromCol, null); + string fAddress = xr.GetAttribute("ref"); + string formula = ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString()); + if (formula != "") { + _sharedFormulas.Add( + sfIndex, + new(SourceCodeTokenizer.Default) { + Index = sfIndex, + Formula = formula, + Address = fAddress, + StartRow = address._fromRow, + StartCol = address._fromCol, + }); + } + } else { + xr.Read(); //Something is wrong in the sheet, read next + } + } else if (t + == "array") //TODO: Array functions are not support yet. Read the formula for the start cell only. + { + string aAddress = xr.GetAttribute("ref"); + ExcelRange addressRange = new ExcelRange(this, aAddress); + string formula = xr.ReadElementContentAsString(); + bool isIndexMatchFormula = + Regex.IsMatch(formula, @"INDEX\(", RegexOptions.IgnoreCase) + && Regex.IsMatch(formula, @"MATCH\(", RegexOptions.IgnoreCase) + && !aAddress.Contains(":"); + if (isIndexMatchFormula) { + addressRange.IsArrayFormula = false; + for (int colIndex = addressRange.Start.Column; + colIndex <= addressRange.End.Column; + colIndex++) { + for (int rowIndex = addressRange.Start.Row; + rowIndex <= addressRange.End.Row; + rowIndex++) { + var afIndex = GetMaxShareFunctionIndex(true); + _formulas.SetValue(rowIndex, colIndex, afIndex); + _values.SetValue(rowIndex, colIndex, null); + _sharedFormulas.Add( + afIndex, + new(SourceCodeTokenizer.Default) { + Index = afIndex, + Formula = formula, + Address = aAddress, + StartRow = address._fromRow, + StartCol = address._fromCol, + IsArray = false, + }); + } + } + } else { + addressRange.IsArrayFormula = true; + var afIndex = GetMaxShareFunctionIndex(true); + for (int colIndex = addressRange.Start.Column; + colIndex <= addressRange.End.Column; + colIndex++) { + for (int rowIndex = addressRange.Start.Row; + rowIndex <= addressRange.End.Row; + rowIndex++) { + _formulas.SetValue(rowIndex, colIndex, afIndex); + _values.SetValue(rowIndex, colIndex, null); + } + } + _sharedFormulas.Add( + afIndex, + new(SourceCodeTokenizer.Default) { + Index = afIndex, + Formula = formula, + Address = aAddress, + StartRow = address._fromRow, + StartCol = address._fromCol, + IsArray = true, + }); + } + } else // ??? some other type + { + xr.Read(); //Something is wrong in the sheet, read next + } + } else if (xr.LocalName + == "is") //Inline string + { + xr.Read(); + if (xr.LocalName == "t") { + _values.SetValue( + address._fromRow, + address._fromCol, + ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString())); + //cell._value = xr.ReadInnerXml(); + } else { + _values.SetValue(address._fromRow, address._fromCol, xr.ReadOuterXml()); + _types.SetValue(address._fromRow, address._fromCol, "rt"); + _flags.SetFlagValue(address._fromRow, address._fromCol, true, CellFlags.RichText); + //cell.IsRichText = true; + } + } else { + break; + } + } + //if (cell != null) cellList.Add(cell); - _name = value; - } - } + //_cells = new RangeCollection(cellList); + //_rows = new RangeCollection(rowList); + //_formulaCells = new RangeCollection(formulaList); + } - private void ChangeNames(string value) - { - //Renames name in this Worksheet; - foreach (var n in Workbook.Names) - { - if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue==null) - { - n.ChangeWorksheet(_name, value); - } - } - foreach (var ws in Workbook.Worksheets) - { - if (!(ws is ExcelChartsheet)) - { - foreach (var n in ws.Names) - { - if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue == null) - { - n.ChangeWorksheet(_name, value); - } - } - } - } - } - internal ExcelNamedRangeCollection _names; - /// <summary> - /// Provides access to named ranges - /// </summary> - public ExcelNamedRangeCollection Names - { - get - { - CheckSheetType(); - return _names; - } - } - /// <summary> - /// Indicates if the worksheet is hidden in the workbook - /// </summary> - public eWorkSheetHidden Hidden - { - get - { - string state=_package.Workbook.GetXmlNodeString(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID)); - if (state == "hidden") - { - return eWorkSheetHidden.Hidden; - } - else if (state == "veryHidden") - { - return eWorkSheetHidden.VeryHidden; - } - return eWorkSheetHidden.Visible; - } - set - { - if (value == eWorkSheetHidden.Visible) - { - _package.Workbook.DeleteNode(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID)); - } - else - { - string v; - v=value.ToString(); - v=v.Substring(0,1).ToLower(CultureInfo.InvariantCulture)+v.Substring(1); - _package.Workbook.SetXmlNodeString(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID),v ); - } - } - } - double _defaultRowHeight = double.NaN; - /// <summary> - /// Get/set the default height of all rows in the worksheet - /// </summary> - public double DefaultRowHeight - { - get - { - CheckSheetType(); - if (double.IsNaN(_defaultRowHeight)) - { - _defaultRowHeight = GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight"); - if(double.IsNaN(_defaultRowHeight)) - { - _defaultRowHeight = 15; // Excel default height - } - } - return _defaultRowHeight; - } - set - { - CheckSheetType(); - _defaultRowHeight = value; - SetXmlNodeString("d:sheetFormatPr/@defaultRowHeight", value.ToString(CultureInfo.InvariantCulture)); - SetXmlNodeBool("d:sheetFormatPr/@customHeight", value != 15); + private bool DoAddRow(XmlTextReader xr) { + var c = xr.GetAttribute("r") == null ? 0 : 1; + if (xr.GetAttribute("spans") != null) { + c++; + } + return xr.AttributeCount > c; + } - if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth"))) - { - DefaultColWidth = 9.140625; - } - } - } - /// <summary> - /// Get/set the default width of all rows in the worksheet - /// </summary> - public double DefaultColWidth - { - get - { - CheckSheetType(); - double ret = GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth"); - if (double.IsNaN(ret)) - { - ret = 9.140625; // Excel's default width - } - return ret; - } - set - { - CheckSheetType(); - SetXmlNodeString("d:sheetFormatPr/@defaultColWidth", value.ToString(CultureInfo.InvariantCulture)); + /// <summary> + /// Load merged cells + /// </summary> + /// <param name="xr"></param> + private void LoadMergeCells(XmlTextReader xr) { + if (ReadUntil(xr, "mergeCells", "hyperlinks", "rowBreaks", "colBreaks") && !xr.EOF) { + while (xr.Read()) { + if (xr.LocalName != "mergeCell") { + break; + } + if (xr.NodeType == XmlNodeType.Element) { + string address = xr.GetAttribute("ref"); + //int fromRow, fromCol, toRow, toCol; + //ExcelCellBase.GetRowColFromAddress(address, out fromRow, out fromCol, out toRow, out toCol); + //for (int row = fromRow; row <= toRow; row++) + //{ + // for (int col = fromCol; col <= toCol; col++) + // { + // _flags.SetFlagValue(row, col, true,CellFlags.Merged); + // } + //} + //_mergedCells.List.Add(address); + _mergedCells.Add(new ExcelAddress(address), false); + } + } + } + } - if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight"))) - { - DefaultRowHeight = 15; - } - } + /// <summary> + /// Update merged cells + /// </summary> + /// <param name="sw">The writer</param> + private void UpdateMergedCells(StreamWriter sw) { + sw.Write("<mergeCells>"); + foreach (string address in _mergedCells) { + sw.Write("<mergeCell ref=\"{0}\" />", address); + } + sw.Write("</mergeCells>"); + } + + /// <summary> + /// Reads a row from the XML reader + /// </summary> + /// <param name="xr">The reader</param> + /// <param name="row">The row number</param> + /// <returns></returns> + private RowInternal AddRow(XmlTextReader xr, int row) { + return new() { + Collapsed = + (xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1" + ? true + : false), + OutlineLevel = + (xr.GetAttribute("outlineLevel") == null + ? (short)0 + : short.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture)), + Height = + (xr.GetAttribute("ht") == null + ? -1 + : double.Parse(xr.GetAttribute("ht"), CultureInfo.InvariantCulture)), + Hidden = + (xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false), + Phonetic = xr.GetAttribute("ph") != null && xr.GetAttribute("ph") == "1" ? true : false, + CustomHeight = + xr.GetAttribute("customHeight") == null ? false : xr.GetAttribute("customHeight") == "1", + }; + } + + private static readonly DateTime _excelEpoch = new(1899, 12, 30); + + public static DateTime IncorrectDurationFromOaDate(double value) { + // This behavior is wrong. Real OADate values have a discontinuity on 30 December 1899. + // For real OADate values, the negative sign applies only to the integer portion of + // the float, *not* to the decimal portion. For example, -0.5 and 0.5 both refer to the + // same date, and -1.5 is actually 1899-12-29 12:00 (1 day before 1899-12-30 00:00 + // plus 0.5 days), *not* 1899-12-28 12:00 (1.5 days before 1899-12-30 00:00). + // + // Unfortunately, AppSheet's duration-handling code gets this very wrong, and treats the + // duration as the offset from 1899-12-30 00:00. This is correct for positive durations, + // but it's wrong for negative durations. This code tries to fix the bug that exists in + // AppSheet's duration-handling code here, and it succeeds in some cases and fails in + // others. + // + // This code also breaks date/time handling for dates before 1899-12-30 00:00 in some + // cases. Specifically, dates end up being offset by one day. + // + // Regardless, changing this behavior is risky, so this code simply replicates the + // existing behavior for + if (value >= 0) { + return DateTime.FromOADate(value); + } + // This looks like a very complicated way to call TimeSpan.FromDays(value), but + // TimeSpan.FromDays actually only guarantees millisecond precision, and critically + // rounding is different on .NET Core, resulting in values like (e.g.) 3:15:00 being + // incorrectly rounded. + var offset = DateTime.FromOADate(-value) - _excelEpoch; + return _excelEpoch - offset; + } + + private void SetValueFromXml(XmlTextReader xr, string type, int styleId, int row, int col) { + //XmlNode vnode = colNode.SelectSingleNode("d:v", NameSpaceManager); + //if (vnode == null) return null; + if (type == "s") { + int ix = xr.ReadElementContentAsInt(); + + // Temporary debugging code to locate intermittent 'Index was out of range' exception. + if (ix < 0) { + throw new( + string.Format( + "ReadElementContentAsInt returned value '{0}' which is less than zero.", + ix)); + } + if (ix >= _package.Workbook._sharedStringsList.Count) { + throw new( + string.Format( + "ReadElementContentAsInt returned index value '{0}' which is greater than _sharedStringsList count of {1}.", + ix, + _package.Workbook._sharedStringsList.Count)); + } + + _values.SetValue(row, col, _package.Workbook._sharedStringsList[ix].Text); + if (_package.Workbook._sharedStringsList[ix].isRichText) { + _flags.SetFlagValue(row, col, true, CellFlags.RichText); + } + } else if (type == "str") { + _values.SetValue(row, col, ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString())); + } else if (type == "b") { + _values.SetValue(row, col, (xr.ReadElementContentAsString() != "0")); + } else if (type == "e") { + _values.SetValue(row, col, GetErrorType(xr.ReadElementContentAsString())); + } else { + string v = xr.ReadElementContentAsString(); + var nf = Workbook.Styles.CellXfs[styleId].NumberFormatId; + if ((nf >= 20 && nf <= 21) + || (nf >= 45 + && nf + <= 47)) // Duration + { + double res; + if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out res)) { + if (Workbook.Date1904) { + res += ExcelWorkbook._date1904Offset; + } + if (res >= -657435.0 && res < 2958465.9999999) { + // Get the Duration value expressed as a DateTime. + _values.SetValue(row, col, IncorrectDurationFromOaDate(res)); + } else { + // Cope with Google Sheets export of cells having a formula. + // Rather than exporting the native value, they export the formatted value. + _values.SetValue(row, col, v); + } + } else { + // Cope with Google Sheets export of cells having a formula. + // Rather than exporting the native value, they export the formatted value. + _values.SetValue(row, col, v); } - /** <outlinePr applyStyles="1" summaryBelow="0" summaryRight="0" /> **/ - const string outLineSummaryBelowPath = "d:sheetPr/d:outlinePr/@summaryBelow"; - /// <summary> - /// Summary rows below details - /// </summary> - public bool OutLineSummaryBelow - { - get - { - CheckSheetType(); - return GetXmlNodeBool(outLineSummaryBelowPath); - } - set - { - CheckSheetType(); - SetXmlNodeString(outLineSummaryBelowPath, value ? "1" : "0"); - } + } else if ((nf >= 14 && nf <= 19) + || (nf + == 22)) // DateTime + { + double res; + if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out res)) { + if (Workbook.Date1904) { + res += ExcelWorkbook._date1904Offset; + } + if (res >= -657435.0 && res < 2958465.9999999) { + _values.SetValue(row, col, DateTime.FromOADate(res)); + } else { + // Cope with Google Sheets export of cells having a formula. + // Rather than exporting the native value, they export the formatted value. + _values.SetValue(row, col, v); + } + } else { + // Cope with Google Sheets export of cells having a formula. + // Rather than exporting the native value, they export the formatted value. + _values.SetValue(row, col, v); } - const string outLineSummaryRightPath = "d:sheetPr/d:outlinePr/@summaryRight"; - /// <summary> - /// Summary rows to right of details - /// </summary> - public bool OutLineSummaryRight - { - get - { - CheckSheetType(); - return GetXmlNodeBool(outLineSummaryRightPath); - } - set - { - CheckSheetType(); - SetXmlNodeString(outLineSummaryRightPath, value ? "1" : "0"); - } + } else { + double d; + if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) { + _values.SetValue(row, col, d); + } else { + // Cope with Google Sheets export of cells having a formula. + // Rather than exporting the native value, they export the formatted value. + _values.SetValue(row, col, v); + + //_values.SetValue(row, col, double.NaN); } - const string outLineApplyStylePath = "d:sheetPr/d:outlinePr/@applyStyles"; - /// <summary> - /// Automatic styles - /// </summary> - public bool OutLineApplyStyle - { - get - { - CheckSheetType(); - return GetXmlNodeBool(outLineApplyStylePath); - } - set - { - CheckSheetType(); - SetXmlNodeString(outLineApplyStylePath, value ? "1" : "0"); - } + } + } + } + + private object GetErrorType(string v) { + return ExcelErrorValue.Parse(v.ToUpper(CultureInfo.InvariantCulture)); + //switch(v.ToUpper()) + //{ + // case "#DIV/0!": + // return new ExcelErrorValue.cre(eErrorType.Div0); + // case "#REF!": + // return new ExcelErrorValue(eErrorType.Ref); + // case "#N/A": + // return new ExcelErrorValue(eErrorType.NA); + // case "#NAME?": + // return new ExcelErrorValue(eErrorType.Name); + // case "#NULL!": + // return new ExcelErrorValue(eErrorType.Null); + // case "#NUM!": + // return new ExcelErrorValue(eErrorType.Num); + // default: + // return new ExcelErrorValue(eErrorType.Value); + //} + } + + //private string GetSharedString(int stringID) + //{ + // string retValue = null; + // XmlNodeList stringNodes = xlPackage.Workbook.SharedStringsXml.SelectNodes(string.Format("//d:si", stringID), NameSpaceManager); + // XmlNode stringNode = stringNodes[stringID]; + // if (stringNode != null) + // retValue = stringNode.InnerText; + // return (retValue); + //} + + + + /// <summary> + /// A reference to the header and footer class which allows you to + /// set the header and footer for all odd, even and first pages of the worksheet + /// </summary> + /// <remarks> + /// To format the text you can use the following format + /// <list type="table"> + /// <listheader><term>Prefix</term><description>Description</description></listheader> + /// <item><term>&U</term><description>Underlined</description></item> + /// <item><term>&E</term><description>Double Underline</description></item> + /// <item><term>&K:xxxxxx</term><description>Color. ex &K:FF0000 for red</description></item> + /// <item><term>&"Font,Regular Bold Italic"</term><description>Changes the font. Regular or Bold or Italic or Bold Italic can be used. ex &"Arial,Bold Italic"</description></item> + /// <item><term>&nn</term><description>Change font size. nn is an integer. ex &24</description></item> + /// <item><term>&G</term><description>Placeholder for images. Images can not be added by the library, but its possible to use in a template.</description></item> + /// </list> + /// </remarks> + public ExcelHeaderFooter HeaderFooter { + get { + if (_headerFooter == null) { + XmlNode headerFooterNode = TopNode.SelectSingleNode("d:headerFooter", NameSpaceManager); + if (headerFooterNode == null) { + headerFooterNode = CreateNode("d:headerFooter"); } - const string tabColorPath = "d:sheetPr/d:tabColor/@rgb"; - const string codeModuleNamePath = "d:sheetPr/@codeName"; - internal string CodeModuleName - { - get - { - return GetXmlNodeString(codeModuleNamePath); - } - set - { - SetXmlNodeString(codeModuleNamePath, value); - } + _headerFooter = new(NameSpaceManager, headerFooterNode, this); + } + return (_headerFooter); + } + } + + /// <summary> + /// Printer settings + /// </summary> + public ExcelPrinterSettings PrinterSettings { + get { + var ps = new ExcelPrinterSettings(NameSpaceManager, TopNode, this); + ps.SchemaNodeOrder = SchemaNodeOrder; + return ps; + } + } + + ///// <summary> + ///// Provides access to an individual cell within the worksheet. + ///// </summary> + ///// <param name="row">The row number in the worksheet</param> + ///// <param name="col">The column number in the worksheet</param> + ///// <returns></returns> + //internal ExcelCell Cell(int row, int col) + //{ + // return new ExcelCell(_values, row, col); + //} + /// <summary> + /// Provides access to a range of cells + /// </summary> + public ExcelRange Cells { + get { + CheckSheetType(); + return new(this, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); + } + } + + /// <summary> + /// Provides access to the selected range of cells + /// </summary> + public ExcelRange SelectedRange { + get { + CheckSheetType(); + return new(this, View.SelectedRange); + } + } + + private MergeCellsCollection _mergedCells = new(); + + /// <summary> + /// Addresses to merged ranges + /// </summary> + public MergeCellsCollection MergedCells { + get { + CheckSheetType(); + return _mergedCells; + } + } + + /// <summary> + /// Provides access to an individual row within the worksheet so you can set its properties. + /// </summary> + /// <param name="row">The row number in the worksheet</param> + /// <returns></returns> + public ExcelRow Row(int row) { + //ExcelRow r; + //ulong id = ExcelRow.GetRowID(_sheetID, row); + //TODO: Fixa. + //var v = _values.GetValue(row, 0); + //if (v!=null) + //{ + // var ri=(RowInternal)v; + // r = new ExcelRow(this, row) + //} + //else + //{ + //r = new ExcelRow(this, row); + //_values.SetValue(row, 0, r); + //_rows.Add(r); + //} + CheckSheetType(); + if (row < 1 || row > ExcelPackage.MaxRows) { + throw (new ArgumentException("Row number out of bounds")); + } + return new(this, row); + //return r; + } + + /// <summary> + /// Provides access to an individual column within the worksheet so you can set its properties. + /// </summary> + /// <param name="col">The column number in the worksheet</param> + /// <returns></returns> + public ExcelColumn Column(int col) { + CheckSheetType(); + if (col < 1 || col > ExcelPackage.MaxColumns) { + throw (new ArgumentException("Column number out of bounds")); + } + var column = _values.GetValue(0, col) as ExcelColumn; + if (column != null) { + if (column.ColumnMin != column.ColumnMax) { + int maxCol = column.ColumnMax; + column.ColumnMax = col; + ExcelColumn copy = CopyColumn(column, col + 1, maxCol); + } + } else { + int r = 0, + c = col; + if (_values.PrevCell(ref r, ref c)) { + column = _values.GetValue(0, c) as ExcelColumn; + int maxCol = column.ColumnMax; + if (maxCol >= col) { + column.ColumnMax = col - 1; + if (maxCol > col) { + ExcelColumn newC = CopyColumn(column, col + 1, maxCol); + } + return CopyColumn(column, col, col); } - internal void CodeNameChange(string value) - { - CodeModuleName = value; + } + //foreach (ExcelColumn checkColumn in _columns) + //{ + // if (col > checkColumn.ColumnMin && col <= checkColumn.ColumnMax) + // { + // int maxCol = checkColumn.ColumnMax; + // checkColumn.ColumnMax = col - 1; + // if (maxCol > col) + // { + // ExcelColumn newC = CopyColumn(checkColumn, col + 1, maxCol); + // } + // return CopyColumn(checkColumn, col,col); + // } + //} + column = new(this, col); + _values.SetValue(0, col, column); + //_columns.Add(column); + } + return column; + } + + /// <summary> + /// Returns the name of the worksheet + /// </summary> + /// <returns>The name of the worksheet</returns> + public override string ToString() { + return Name; + } + + internal ExcelColumn CopyColumn(ExcelColumn c, int col, int maxCol) { + ExcelColumn newC = new ExcelColumn(this, col); + newC.ColumnMax = maxCol < ExcelPackage.MaxColumns ? maxCol : ExcelPackage.MaxColumns; + if (c.StyleName != "") { + newC.StyleName = c.StyleName; + } else { + newC.StyleID = c.StyleID; + } + + newC.OutlineLevel = c.OutlineLevel; + newC.Phonetic = c.Phonetic; + newC.BestFit = c.BestFit; + //_columns.Add(newC); + _values.SetValue(0, col, newC); + newC._width = c._width; + newC._hidden = c._hidden; + return newC; + } + + /// <summary> + /// Make the current worksheet active. + /// </summary> + public void Select() { + View.TabSelected = true; + //Select(Address, true); + } + + /// <summary> + /// Selects a range in the worksheet. The active cell is the topmost cell. + /// Make the current worksheet active. + /// </summary> + /// <param name="address">An address range</param> + public void Select(string address) { + Select(address, true); + } + + /// <summary> + /// Selects a range in the worksheet. The actice cell is the topmost cell. + /// </summary> + /// <param name="address">A range of cells</param> + /// <param name="selectSheet">Make the sheet active</param> + public void Select(string address, bool selectSheet) { + CheckSheetType(); + int fromCol, + fromRow, + toCol, + toRow; + //Get rows and columns and validate as well + ExcelCellBase.GetRowColFromAddress(address, out fromRow, out fromCol, out toRow, out toCol); + + if (selectSheet) { + View.TabSelected = true; + } + View.SelectedRange = address; + View.ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol); + } + + /// <summary> + /// Selects a range in the worksheet. The active cell is the topmost cell of the first address. + /// Make the current worksheet active. + /// </summary> + /// <param name="address">An address range</param> + public void Select(ExcelAddress address) { + CheckSheetType(); + Select(address, true); + } + + /// <summary> + /// Selects a range in the worksheet. The active cell is the topmost cell of the first address. + /// </summary> + /// <param name="address">A range of cells</param> + /// <param name="selectSheet">Make the sheet active</param> + public void Select(ExcelAddress address, bool selectSheet) { + CheckSheetType(); + if (selectSheet) { + View.TabSelected = true; + } + string selAddress = + ExcelCellBase.GetAddress(address.Start.Row, address.Start.Column) + + ":" + + ExcelCellBase.GetAddress(address.End.Row, address.End.Column); + if (address.Addresses != null) { + foreach (var a in address.Addresses) { + selAddress += + " " + + ExcelCellBase.GetAddress(a.Start.Row, a.Start.Column) + + ":" + + ExcelCellBase.GetAddress(a.End.Row, a.End.Column); + } + } + View.SelectedRange = selAddress; + View.ActiveCell = ExcelCellBase.GetAddress(address.Start.Row, address.Start.Column); + } + + /// <summary> + /// Inserts a new row into the spreadsheet. Existing rows below the position are + /// shifted down. All formula are updated to take account of the new row. + /// </summary> + /// <param name="rowFrom">The position of the new row</param> + /// <param name="rows">Number of rows to insert</param> + public void InsertRow(int rowFrom, int rows) { + InsertRow(rowFrom, rows, 0); + } + + /// <summary> + /// Inserts a new row into the spreadsheet. Existing rows below the position are + /// shifted down. All formula are updated to take account of the new row. + /// </summary> + /// <param name="rowFrom">The position of the new row</param> + /// <param name="rows">Number of rows to insert.</param> + /// <param name="copyStylesFromRow">Copy Styles from this row. Applied to all inserted rows</param> + public void InsertRow(int rowFrom, int rows, int copyStylesFromRow) { + CheckSheetType(); + var d = Dimension; + + if (rowFrom < 1) { + throw (new ArgumentOutOfRangeException("rowFrom can't be lesser that 1")); + } + + //Check that cells aren't shifted outside the boundries + if (d != null && d.End.Row > rowFrom && d.End.Row + rows > ExcelPackage.MaxRows) { + throw (new ArgumentOutOfRangeException( + "Can't insert. Rows will be shifted outside the boundries of the worksheet.")); + } + + lock (this) { + _values.Insert(rowFrom, 0, rows, 0); + _formulas.Insert(rowFrom, 0, rows, 0); + _styles.Insert(rowFrom, 0, rows, 0); + _types.Insert(rowFrom, 0, rows, 0); + _commentsStore.Insert(rowFrom, 0, rows, 0); + _hyperLinks.Insert(rowFrom, 0, rows, 0); + _flags.Insert(rowFrom, 0, rows, 0); + + foreach (var f in _sharedFormulas.Values) { + if (f.StartRow >= rowFrom) { + f.StartRow += rows; + } + var a = new ExcelAddressBase(f.Address); + if (a._fromRow >= rowFrom) { + a._fromRow += rows; + a._toRow += rows; + } else if (a._toRow >= rowFrom) { + a._toRow += rows; + } + f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol); + f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, rows, 0, rowFrom, 0); + } + var cse = new CellsStoreEnumerator<object>(_formulas); + while (cse.Next()) { + if (cse.Value is string) { + cse.Value = ExcelCellBase.UpdateFormulaReferences( + cse.Value.ToString(), + rows, + 0, + rowFrom, + 0); + } + } + + FixMergedCellsRow(rowFrom, rows, false); + if (copyStylesFromRow > 0) { + var cseS = new CellsStoreEnumerator<int>( + _styles, + copyStylesFromRow, + 0, + copyStylesFromRow, + ExcelPackage.MaxColumns); //Fixes issue 15068 , 15090 + while (cseS.Next()) { + for (var r = 0; r < rows; r++) { + _styles.SetValue(rowFrom + r, cseS.Column, cseS.Value); + } + } + } + foreach (var tbl in Tables) { + tbl.Address = tbl.Address.AddRow(rowFrom, rows); + } + } + } + + /// <summary> + /// Inserts a new column into the spreadsheet. Existing columns below the position are + /// shifted down. All formula are updated to take account of the new column. + /// </summary> + /// <param name="columnFrom">The position of the new column</param> + /// <param name="columns">Number of columns to insert</param> + public void InsertColumn(int columnFrom, int columns) { + InsertColumn(columnFrom, columns, 0); + } + + ///<summary> + /// Inserts a new column into the spreadsheet. Existing column to the left are + /// shifted. All formula are updated to take account of the new column. + /// </summary> + /// <param name="columnFrom">The position of the new column</param> + /// <param name="columns">Number of columns to insert.</param> + /// <param name="copyStylesFromColumn">Copy Styles from this column. Applied to all inserted columns</param> + public void InsertColumn(int columnFrom, int columns, int copyStylesFromColumn) { + CheckSheetType(); + var d = Dimension; + + if (columnFrom < 1) { + throw (new ArgumentOutOfRangeException("columnFrom can't be lesser that 1")); + } + //Check that cells aren't shifted outside the boundries + if (d != null + && d.End.Column > columnFrom + && d.End.Column + columns > ExcelPackage.MaxColumns) { + throw (new ArgumentOutOfRangeException( + "Can't insert. Columns will be shifted outside the boundries of the worksheet.")); + } + + lock (this) { + _values.Insert(0, columnFrom, 0, columns); + _formulas.Insert(0, columnFrom, 0, columns); + _styles.Insert(0, columnFrom, 0, columns); + _types.Insert(0, columnFrom, 0, columns); + _commentsStore.Insert(0, columnFrom, 0, columns); + _hyperLinks.Insert(0, columnFrom, 0, columns); + _flags.Insert(0, columnFrom, 0, columns); + + foreach (var f in _sharedFormulas.Values) { + if (f.StartCol >= columnFrom) { + f.StartCol += columns; + } + var a = new ExcelAddressBase(f.Address); + if (a._fromCol >= columnFrom) { + a._fromCol += columns; + a._toCol += columns; + } else if (a._toCol >= columnFrom) { + a._toCol += columns; + } + f.Address = ExcelCellBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol); + f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, 0, columns, 0, columnFrom); + } + + var cse = new CellsStoreEnumerator<object>(_formulas); + while (cse.Next()) { + if (cse.Value is string) { + cse.Value = ExcelCellBase.UpdateFormulaReferences( + cse.Value.ToString(), + 0, + columns, + 0, + columnFrom); + } + } + + FixMergedCellsColumn(columnFrom, columns, false); + + var csec = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns); + var lst = new List<ExcelColumn>(); + foreach (var col in csec) { + if (col is ExcelColumn) { + lst.Add((ExcelColumn)col); + } + } + + for (int i = lst.Count - 1; i >= 0; i--) { + var c = lst[i]; + if (c._columnMin >= columnFrom) { + if (c._columnMin + columns <= ExcelPackage.MaxColumns) { + c._columnMin += columns; + } else { + c._columnMin = ExcelPackage.MaxColumns; + } + + if (c._columnMax + columns <= ExcelPackage.MaxColumns) { + c._columnMax += columns; + } else { + c._columnMax = ExcelPackage.MaxColumns; + } + } else if (c._columnMax >= columnFrom) { + var cc = c._columnMax - columnFrom; + c._columnMax = columnFrom - 1; + CopyColumn(c, columnFrom + columns, columnFrom + columns + cc); + } + } + + if (copyStylesFromColumn > 0) { + for (var c = 0; c < columns; c++) { + var col = Column(columnFrom + c); + col.StyleID = Column(copyStylesFromColumn).StyleID; + } + } + //Adjust tables + foreach (var tbl in Tables) { + if (columnFrom > tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) { + InsertTableColumns(columnFrom, columns, tbl); } - #region WorksheetXml - /// <summary> - /// The XML document holding the worksheet data. - /// All column, row, cell, pagebreak, merged cell and hyperlink-data are loaded into memory and removed from the document when loading the document. - /// </summary> - public XmlDocument WorksheetXml - { - get - { - return (_worksheetXml); - } - } - internal ExcelVmlDrawingCommentCollection _vmlDrawings = null; - /// <summary> - /// Vml drawings. underlaying object for comments - /// </summary> - internal ExcelVmlDrawingCommentCollection VmlDrawingsComments - { - get - { - if (_vmlDrawings == null) - { - CreateVmlCollection(); - } - return _vmlDrawings; - } - } - internal ExcelCommentCollection _comments = null; - /// <summary> - /// Collection of comments - /// </summary> - public ExcelCommentCollection Comments - { - get - { - CheckSheetType(); - if (_comments == null) - { - CreateVmlCollection(); - _comments = new ExcelCommentCollection(_package, this, NameSpaceManager); - } - return _comments; - } - } - private void CreateVmlCollection() - { - var vmlNode = _worksheetXml.DocumentElement.SelectSingleNode("d:legacyDrawing/@r:id", NameSpaceManager); - if (vmlNode == null) - { - _vmlDrawings = new ExcelVmlDrawingCommentCollection(_package, this, null); - } - else - { - if (Part.RelationshipExists(vmlNode.Value)) - { - var rel = Part.GetRelationship(vmlNode.Value); - var vmlUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); + tbl.Address = tbl.Address.AddColumn(columnFrom, columns); + } + } + } - _vmlDrawings = new ExcelVmlDrawingCommentCollection(_package, this, vmlUri); - _vmlDrawings.RelId = rel.Id; - } - } + private static void InsertTableColumns(int columnFrom, int columns, ExcelTable tbl) { + var node = tbl.Columns[0].TopNode.ParentNode; + var ix = columnFrom - tbl.Address.Start.Column - 1; + var insPos = node.ChildNodes[ix]; + ix += 2; + for (int i = 0; i < columns; i++) { + var name = tbl.Columns.GetUniqueName( + string.Format("Column{0}", (ix++).ToString(CultureInfo.InvariantCulture))); + XmlElement tableColumn = (XmlElement) + tbl.TableXml.CreateNode(XmlNodeType.Element, "tableColumn", ExcelPackage._schemaMain); + tableColumn.SetAttribute( + "id", + (tbl.Columns.Count + i + 1).ToString(CultureInfo.InvariantCulture)); + tableColumn.SetAttribute("name", name); + insPos = node.InsertAfter(tableColumn, insPos); + } //Create tbl Column + tbl._cols = new(tbl); + } + + /// <summary> + /// Adds a value to the row of merged cells to fix for inserts or deletes + /// </summary> + /// <param name="row"></param> + /// <param name="rows"></param> + /// <param name="delete"></param> + private void FixMergedCellsRow(int row, int rows, bool delete) { + if (delete) { + _mergedCells._cells.Delete(row, 0, rows, 0); + } else { + _mergedCells._cells.Insert(row, 0, rows, 0); + } + + List<int> removeIndex = new List<int>(); + for (int i = 0; i < _mergedCells.Count; i++) { + if (!string.IsNullOrEmpty(_mergedCells[i])) { + ExcelAddressBase addr = new(_mergedCells[i]), + newAddr; + if (delete) { + newAddr = addr.DeleteRow(row, rows); + if (newAddr == null) { + removeIndex.Add(i); + continue; + } + } else { + newAddr = addr.AddRow(row, rows); + if (newAddr.Address != addr.Address) { + // _mergedCells._cells.Insert(row, 0, rows, 0); + _mergedCells.SetIndex(newAddr, i); + } } - private void CreateXml() - { - _worksheetXml = new XmlDocument(); - _worksheetXml.PreserveWhitespace = ExcelPackage.preserveWhitespace; - Packaging.ZipPackagePart packPart = _package.Package.GetPart(WorksheetUri); - string xml = ""; - - // First Columns, rows, cells, mergecells, hyperlinks and pagebreakes are loaded from a xmlstream to optimize speed... - Stream stream = packPart.GetStream(); - - XmlTextReader xr = new XmlTextReader(stream); - xr.ProhibitDtd = true; - xr.WhitespaceHandling = WhitespaceHandling.None; - LoadColumns(xr); //columnXml - long start = stream.Position; - LoadCells(xr); - var nextElementLength = GetAttributeLength(xr); - long end = stream.Position - nextElementLength; - LoadMergeCells(xr); - LoadHyperLinks(xr); - LoadRowPageBreakes(xr); - LoadColPageBreakes(xr); - //...then the rest of the Xml is extracted and loaded into the WorksheetXml document. - stream.Seek(0, SeekOrigin.Begin); - Encoding encoding; - xml = GetWorkSheetXml(stream, start, end, out encoding); - - //first char is invalid sometimes?? - if (xml[0] != '<') - LoadXmlSafe(_worksheetXml, xml.Substring(1, xml.Length - 1), encoding); - else - LoadXmlSafe(_worksheetXml, xml, encoding); - - ClearNodes(); + if (newAddr.Address != addr.Address) { + _mergedCells.List[i] = newAddr._address; } - /// <summary> - /// Get the lenth of the attributes - /// Conditional formatting attributes can be extremly long som get length of the attributes to finetune position. - /// </summary> - /// <param name="xr"></param> - /// <returns></returns> - private int GetAttributeLength(XmlTextReader xr) - { - if (xr.NodeType != XmlNodeType.Element) return 0; - var length = 0; - - for (int i = 0; i < xr.AttributeCount; i++) - { - var a=xr.GetAttribute(i); - length += string.IsNullOrEmpty(a) ? 0 : a.Length; - } - return length; - } - private void LoadRowPageBreakes(XmlTextReader xr) - { - if(!ReadUntil(xr, "rowBreaks","colBreaks")) return; - while (xr.Read()) - { - if (xr.LocalName == "brk") - { - if (xr.NodeType == XmlNodeType.Element) - { - int id; - if (int.TryParse(xr.GetAttribute("id"), out id)) - { - Row(id).PageBreak = true; - } - } - } - else - { - break; - } - } - } - private void LoadColPageBreakes(XmlTextReader xr) - { - if (!ReadUntil(xr, "colBreaks")) return; - while (xr.Read()) - { - if (xr.LocalName == "brk") - { - if (xr.NodeType == XmlNodeType.Element) - { - int id; - if (int.TryParse(xr.GetAttribute("id"), out id)) - { - Column(id).PageBreak = true; - } - } - } - else - { - break; - } - } + } + } + for (int i = removeIndex.Count - 1; i >= 0; i--) { + _mergedCells.List.RemoveAt(removeIndex[i]); + } + } + + /// <summary> + /// Adds a value to the row of merged cells to fix for inserts or deletes + /// </summary> + /// <param name="column"></param> + /// <param name="columns"></param> + /// <param name="delete"></param> + private void FixMergedCellsColumn(int column, int columns, bool delete) { + if (delete) { + _mergedCells._cells.Delete(0, column, 0, columns); + } else { + _mergedCells._cells.Insert(0, column, 0, columns); + } + List<int> removeIndex = new List<int>(); + for (int i = 0; i < _mergedCells.Count; i++) { + if (!string.IsNullOrEmpty(_mergedCells[i])) { + ExcelAddressBase addr = new(_mergedCells[i]), + newAddr; + if (delete) { + newAddr = addr.DeleteColumn(column, columns); + if (newAddr == null) { + removeIndex.Add(i); + continue; + } + } else { + newAddr = addr.AddColumn(column, columns); + if (newAddr.Address != addr.Address) { + _mergedCells.SetIndex(newAddr, i); + } } - private void ClearNodes() - { - if (_worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager)!=null) - { - _worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager).RemoveAll(); - } - if (_worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager) != null) - { - _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager).RemoveAll(); - } - if (_worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager) != null) - { - _worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager).RemoveAll(); - } - if (_worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager) != null) - { - _worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager).RemoveAll(); - } - if (_worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager) != null) - { - _worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager).RemoveAll(); - } + if (newAddr.Address != addr.Address) { + _mergedCells.List[i] = newAddr._address; } - const int BLOCKSIZE=8192; - private string GetWorkSheetXml(Stream stream, long start, long end, out Encoding encoding) - { - StreamReader sr = new StreamReader(stream); - int length = 0; - char[] block; - int pos; - StringBuilder sb = new StringBuilder(); - Match startmMatch, endMatch; - do - { - int size = stream.Length < BLOCKSIZE ? (int)stream.Length : BLOCKSIZE; - block = new char[size]; - pos = sr.ReadBlock(block, 0, size); - sb.Append(block,0,pos); - length += size; - } - while (length < start + 20 && length < end); - startmMatch = Regex.Match(sb.ToString(), string.Format("(<[^>]*{0}[^>]*>)", "sheetData")); - if (!startmMatch.Success) //Not found - { - encoding = sr.CurrentEncoding; - return sb.ToString(); - } - else - { - string s = sb.ToString(); - string xml = s.Substring(0, startmMatch.Index); - if(startmMatch.Value.EndsWith("/>")) - { - xml += s.Substring(startmMatch.Index, s.Length - startmMatch.Index); - } - else - { - if (sr.Peek() != -1) - { - /**** Fixes issue 14788. Fix by Philip Garrett ****/ - long endSeekStart = end; + } + } + for (int i = removeIndex.Count - 1; i >= 0; i--) { + _mergedCells.List.RemoveAt(removeIndex[i]); + } + } - while (endSeekStart >= 0) - { - endSeekStart = Math.Max(endSeekStart - BLOCKSIZE, 0); - int size = (int)(end - endSeekStart); - stream.Seek(endSeekStart, SeekOrigin.Begin); - block = new char[size]; - sr = new StreamReader(stream); - pos = sr.ReadBlock(block, 0, size); - sb = new StringBuilder(); - sb.Append(block, 0, pos); - s = sb.ToString(); - endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData")); - if (endMatch.Success) - { - break; - } - } - } - endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData")); - xml += "<sheetData/>" + s.Substring(endMatch.Index + endMatch.Length, s.Length - (endMatch.Index + endMatch.Length)); - } - if (sr.Peek() > -1) - { - xml += sr.ReadToEnd(); - } - - encoding = sr.CurrentEncoding; - return xml; - } + private void FixSharedFormulasRows(int position, int rows) { + List<Formulas> added = new List<Formulas>(); + List<Formulas> deleted = new List<Formulas>(); + + foreach (int id in _sharedFormulas.Keys) { + var f = _sharedFormulas[id]; + int fromCol, + fromRow, + toCol, + toRow; + + ExcelCellBase.GetRowColFromAddress(f.Address, out fromRow, out fromCol, out toRow, out toCol); + if (position >= fromRow + && position + (Math.Abs(rows)) + <= toRow) //Insert/delete is whithin the share formula address + { + if (rows + > 0) //Insert + { + f.Address = + ExcelCellBase.GetAddress(fromRow, fromCol) + + ":" + + ExcelCellBase.GetAddress(position - 1, toCol); + if (toRow != fromRow) { + Formulas newF = new Formulas(SourceCodeTokenizer.Default); + newF.StartCol = f.StartCol; + newF.StartRow = position + rows; + newF.Address = + ExcelCellBase.GetAddress(position + rows, fromCol) + + ":" + + ExcelCellBase.GetAddress(toRow + rows, toCol); + newF.Formula = ExcelCellBase.TranslateFromR1C1( + ExcelCellBase.TranslateToR1C1(f.Formula, f.StartRow, f.StartCol), + position, + f.StartCol); + added.Add(newF); + } + } else { + if (fromRow - rows < toRow) { + f.Address = ExcelCellBase.GetAddress(fromRow, fromCol, toRow + rows, toCol); + } else { + f.Address = + ExcelCellBase.GetAddress(fromRow, fromCol) + + ":" + + ExcelCellBase.GetAddress(toRow + rows, toCol); + } } - private void GetBlockPos(string xml, string tag, ref int start, ref int end) + } else if (position <= toRow) { + if (rows + > 0) //Insert before shift down { - Match startmMatch, endMatch; - startmMatch = Regex.Match(xml.Substring(start), string.Format("(<[^>]*{0}[^>]*>)", tag)); //"<[a-zA-Z:]*" + tag + "[?]*>"); + f.StartRow += rows; + //f.Formula = ExcelCell.UpdateFormulaReferences(f.Formula, rows, 0, position, 0); //Recalc the cells positions + f.Address = + ExcelCellBase.GetAddress(fromRow + rows, fromCol) + + ":" + + ExcelCellBase.GetAddress(toRow + rows, toCol); + } else { + //Cells[f.Address].SetSharedFormulaID(int.MinValue); + if (position <= fromRow + && position + Math.Abs(rows) + > toRow) //Delete the formula + { + deleted.Add(f); + } else { + toRow = toRow + rows < position - 1 ? position - 1 : toRow + rows; + if (position <= fromRow) { + fromRow = fromRow + rows < position ? position : fromRow + rows; + } - if (!startmMatch.Success) //Not found - { - start = -1; - end = -1; - return; - } - var startPos=startmMatch.Index+start; - if(startmMatch.Value.Substring(startmMatch.Value.Length-2,1)=="/") - { - end = startPos + startmMatch.Length; - } - else - { - endMatch = Regex.Match(xml.Substring(start), string.Format("(</[^>]*{0}[^>]*>)", tag)); - if (endMatch.Success) - { - end = endMatch.Index + endMatch.Length + start; - } - } - start = startPos; + f.Address = ExcelCellBase.GetAddress(fromRow, fromCol, toRow, toCol); + Cells[f.Address].SetSharedFormulaId(f.Index); + //f.StartRow = fromRow; + + //f.Formula = ExcelCell.UpdateFormulaReferences(f.Formula, rows, 0, position, 0); + } } - private bool ReadUntil(XmlTextReader xr,params string[] tagName) - { - if (xr.EOF) return false; - while (!Array.Exists(tagName, tag => xr.LocalName.EndsWith(tag))) - { - xr.Read(); - if (xr.EOF) return false; - } - return (xr.LocalName.EndsWith(tagName[0])); + } + } + + AddFormulas(added, position, rows); + + //Remove formulas + foreach (Formulas f in deleted) { + _sharedFormulas.Remove(f.Index); + } + + //Fix Formulas + added = new(); + foreach (int id in _sharedFormulas.Keys) { + var f = _sharedFormulas[id]; + UpdateSharedFormulaRow(ref f, position, rows, ref added); + } + AddFormulas(added, position, rows); + } + + private void AddFormulas(List<Formulas> added, int position, int rows) { + //Add new formulas + foreach (Formulas f in added) { + f.Index = GetMaxShareFunctionIndex(false); + _sharedFormulas.Add(f.Index, f); + Cells[f.Address].SetSharedFormulaId(f.Index); + } + } + + private void UpdateSharedFormulaRow( + ref Formulas formula, + int startRow, + int rows, + ref List<Formulas> newFormulas) { + int fromRow, + fromCol, + toRow, + toCol; + int newFormulasCount = newFormulas.Count; + ExcelCellBase.GetRowColFromAddress( + formula.Address, + out fromRow, + out fromCol, + out toRow, + out toCol); + //int refSplits = Regex.Split(formula.Formula, "#REF!").GetUpperBound(0); + string formualR1C1; + if (rows > 0 || fromRow <= startRow) { + formualR1C1 = ExcelCellBase.TranslateToR1C1( + formula.Formula, + formula.StartRow, + formula.StartCol); + formula.Formula = ExcelCellBase.TranslateFromR1C1(formualR1C1, fromRow, formula.StartCol); + } else { + formualR1C1 = ExcelCellBase.TranslateToR1C1( + formula.Formula, + formula.StartRow - rows, + formula.StartCol); + formula.Formula = ExcelCellBase.TranslateFromR1C1( + formualR1C1, + formula.StartRow, + formula.StartCol); + } + //bool isRef = false; + //Formulas restFormula=formula; + string prevFormualR1C1 = formualR1C1; + for (int row = fromRow; row <= toRow; row++) { + for (int col = fromCol; col <= toCol; col++) { + string newFormula; + string currentFormulaR1C1; + if (rows > 0 || row < startRow) { + newFormula = ExcelCellBase.UpdateFormulaReferences( + ExcelCellBase.TranslateFromR1C1(formualR1C1, row, col), + rows, + 0, + startRow, + 0); + currentFormulaR1C1 = ExcelCellBase.TranslateToR1C1(newFormula, row, col); + } else { + newFormula = ExcelCellBase.UpdateFormulaReferences( + ExcelCellBase.TranslateFromR1C1(formualR1C1, row - rows, col), + rows, + 0, + startRow, + 0); + currentFormulaR1C1 = ExcelCellBase.TranslateToR1C1(newFormula, row, col); } - private void LoadColumns (XmlTextReader xr)//(string xml) + if (currentFormulaR1C1 + != prevFormualR1C1) //newFormula.Contains("#REF!")) { - var colList = new List<IRangeID>(); - if (ReadUntil(xr, "cols", "sheetData")) - { - //if (xml != "") - //{ - //var xr=new XmlTextReader(new StringReader(xml)); - while(xr.Read()) - { - if (xr.NodeType == XmlNodeType.Whitespace) continue; - if (xr.LocalName != "col") break; - if (xr.NodeType == XmlNodeType.Element) - { - int min = int.Parse(xr.GetAttribute("min")); - - ExcelColumn col = new ExcelColumn(this, min); - - col.ColumnMax = int.Parse(xr.GetAttribute("max")); - col.Width = xr.GetAttribute("width") == null ? 0 : double.Parse(xr.GetAttribute("width"), CultureInfo.InvariantCulture); - col.BestFit = xr.GetAttribute("bestFit") != null && xr.GetAttribute("bestFit") == "1" ? true : false; - col.Collapsed = xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1" ? true : false; - col.Phonetic = xr.GetAttribute("phonetic") != null && xr.GetAttribute("phonetic") == "1" ? true : false; - col.OutlineLevel = (short)(xr.GetAttribute("outlineLevel") == null ? 0 : int.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture)); - col.Hidden = xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false; - _values.SetValue(0, min, col); - - int style; - if (!(xr.GetAttribute("style") == null || !int.TryParse(xr.GetAttribute("style"), out style))) - { - _styles.SetValue(0, min, style); - } - } - } + //if (refSplits == 0 || Regex.Split(newFormula, "#REF!").GetUpperBound(0) != refSplits) + //{ + //isRef = true; + if (row == fromRow && col == fromCol) { + formula.Formula = newFormula; + } else { + if (newFormulas.Count == newFormulasCount) { + formula.Address = ExcelCellBase.GetAddress( + formula.StartRow, + formula.StartCol, + row - 1, + col); + } else { + newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress( + newFormulas[newFormulas.Count - 1].StartRow, + newFormulas[newFormulas.Count - 1].StartCol, + row - 1, + col); } + var refFormula = new Formulas(SourceCodeTokenizer.Default); + refFormula.Formula = newFormula; + refFormula.StartRow = row; + refFormula.StartCol = col; + newFormulas.Add(refFormula); + + //restFormula = null; + prevFormualR1C1 = currentFormulaR1C1; + } } - /// <summary> - /// Read until the node is found. If not found the xmlreader is reseted. - /// </summary> - /// <param name="xr">The reader</param> - /// <param name="nodeText">Text to search for</param> - /// <param name="altNode">Alternative text to search for</param> - /// <returns></returns> - private static bool ReadXmlReaderUntil(XmlTextReader xr, string nodeText, string altNode) - { - do - { - if (xr.LocalName == nodeText || xr.LocalName == altNode) return true; - } - while(xr.Read()); - xr.Close(); - return false; - } - /// <summary> - /// Load Hyperlinks - /// </summary> - /// <param name="xr">The reader</param> - private void LoadHyperLinks(XmlTextReader xr) - { - if (!ReadUntil(xr, "hyperlinks", "rowBreaks", "colBreaks")) return; - while (xr.Read()) - { - if (xr.LocalName == "hyperlink") - { - int fromRow, fromCol, toRow, toCol; - ExcelCellBase.GetRowColFromAddress(xr.GetAttribute("ref"), out fromRow, out fromCol, out toRow, out toCol); - ExcelHyperLink hl = null; - if (xr.GetAttribute("id", ExcelPackage.schemaRelationships) != null) - { - var rId = xr.GetAttribute("id", ExcelPackage.schemaRelationships); - var uri = Part.GetRelationship(rId).TargetUri; - - // Get Location, if any. EPPlus Bug 15517 - var location = xr.GetAttribute("location"); - location = (string.IsNullOrEmpty(location)) ? "" : "#" + location; - - if (uri.IsAbsoluteUri) - { - try - { - hl = new ExcelHyperLink(uri.AbsoluteUri + location); - } - catch - { - hl = new ExcelHyperLink(uri.OriginalString + location, UriKind.Absolute); - } - } - else - { - hl = new ExcelHyperLink(uri.OriginalString + location, UriKind.Relative); - } - - hl.RId = rId; - Part.DeleteRelationship(rId); //Delete the relationship, it is recreated when we save the package. - } - else if (xr.GetAttribute("location") != null) - { - hl = new ExcelHyperLink(xr.GetAttribute("location"), xr.GetAttribute("display")); - hl.RowSpann = toRow - fromRow; - hl.ColSpann = toCol - fromCol; - } - - string tt = xr.GetAttribute("tooltip"); - if (!string.IsNullOrEmpty(tt)) - { - hl.ToolTip = tt; - } - _hyperLinks.SetValue(fromRow, fromCol, hl); - } - else - { - break; - } - } - } - /// <summary> - /// Load cells - /// </summary> - /// <param name="xr">The reader</param> - private void LoadCells(XmlTextReader xr) - { - //var cellList=new List<IRangeID>(); - //var rowList = new List<IRangeID>(); - //var formulaList = new List<IRangeID>(); - ReadUntil(xr, "sheetData", "mergeCells", "hyperlinks", "rowBreaks", "colBreaks"); - ExcelAddressBase address=null; - string type=""; - int style=0; - int row = 0; - int col = 0; - xr.Read(); - - while (!xr.EOF) - { - while (xr.NodeType == XmlNodeType.EndElement) - { - xr.Read(); - continue; - } - if (xr.LocalName == "row") - { - var r = xr.GetAttribute("r"); - if (r == null) - { - row++; - } - else - { - row = Convert.ToInt32(r); - } - - if (DoAddRow(xr)) - { - _values.SetValue(row, 0, AddRow(xr, row)); - if(xr.GetAttribute("s") != null) - { - _styles.SetValue(row, 0, int.Parse(xr.GetAttribute("s"), CultureInfo.InvariantCulture)); - } - } - xr.Read(); - } - else if (xr.LocalName == "c") - { - //if (cell != null) cellList.Add(cell); - //cell = new ExcelCell(this, xr.GetAttribute("r")); - var r = xr.GetAttribute("r"); - if (r == null) - { - //Handle cells with no reference - col++; - address = new ExcelAddressBase(row, col, row, col); - } - else - { - address = new ExcelAddressBase(r); - col = address._fromCol; - } - - - //Datetype - if (xr.GetAttribute("t") != null) - { - type=xr.GetAttribute("t"); - _types.SetValue(address._fromRow, address._fromCol, type); - } - else - { - type=""; - } - //Style - if(xr.GetAttribute("s") != null) - { - style=int.Parse(xr.GetAttribute("s")); - _styles.SetValue(address._fromRow, address._fromCol, style); - _values.SetValue(address._fromRow, address._fromCol, null); //TODO:Better Performance ?? - } - else - { - style = 0; - } - xr.Read(); - } - else if (xr.LocalName == "v") - { - SetValueFromXml(xr, type, style, address._fromRow, address._fromCol); - - xr.Read(); - } - else if (xr.LocalName == "f") - { - string t = xr.GetAttribute("t"); - if (t == null) - { - _formulas.SetValue(address._fromRow, address._fromCol, xr.ReadElementContentAsString()); - _values.SetValue(address._fromRow, address._fromCol, null); - //formulaList.Add(cell); - } - else if (t == "shared") - { - - string si = xr.GetAttribute("si"); - if (si != null) - { - var sfIndex = int.Parse(si); - _formulas.SetValue(address._fromRow, address._fromCol, sfIndex); - _values.SetValue(address._fromRow, address._fromCol, null); - string fAddress = xr.GetAttribute("ref"); - string formula = ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString()); - if (formula != "") - { - _sharedFormulas.Add(sfIndex, new Formulas(SourceCodeTokenizer.Default) { Index = sfIndex, Formula = formula, Address = fAddress, StartRow = address._fromRow, StartCol = address._fromCol }); - } - } - else - { - xr.Read(); //Something is wrong in the sheet, read next - } - } - else if (t == "array") //TODO: Array functions are not support yet. Read the formula for the start cell only. - { - string aAddress = xr.GetAttribute("ref"); - ExcelRange addressRange = new ExcelRange(this, aAddress); - string formula = xr.ReadElementContentAsString(); - bool isIndexMatchFormula = Regex.IsMatch(formula, @"INDEX\(", RegexOptions.IgnoreCase) && Regex.IsMatch(formula, @"MATCH\(", RegexOptions.IgnoreCase) && !aAddress.Contains(":"); - if (isIndexMatchFormula) - { - addressRange.IsArrayFormula = false; - for (int colIndex = addressRange.Start.Column; colIndex <= addressRange.End.Column; colIndex++) - { - for (int rowIndex = addressRange.Start.Row; rowIndex <= addressRange.End.Row; rowIndex++) - { - var afIndex = GetMaxShareFunctionIndex(true); - _formulas.SetValue(rowIndex, colIndex, afIndex); - _values.SetValue(rowIndex, colIndex, null); - _sharedFormulas.Add(afIndex, new Formulas(SourceCodeTokenizer.Default) { Index = afIndex, Formula = formula, Address = aAddress, StartRow = address._fromRow, StartCol = address._fromCol, IsArray = false }); - } - } - } - else - { - addressRange.IsArrayFormula = true; - var afIndex = GetMaxShareFunctionIndex(true); - for (int colIndex = addressRange.Start.Column; colIndex <= addressRange.End.Column; colIndex++) - { - for (int rowIndex = addressRange.Start.Row; rowIndex <= addressRange.End.Row; rowIndex++) - { - _formulas.SetValue(rowIndex, colIndex, afIndex); - _values.SetValue(rowIndex, colIndex, null); - } - } - _sharedFormulas.Add(afIndex, new Formulas(SourceCodeTokenizer.Default) { Index = afIndex, Formula = formula, Address = aAddress, StartRow = address._fromRow, StartCol = address._fromCol, IsArray = true }); - } - } - else // ??? some other type - { - xr.Read(); //Something is wrong in the sheet, read next - } - - } - else if (xr.LocalName == "is") //Inline string - { - xr.Read(); - if (xr.LocalName == "t") - { - _values.SetValue(address._fromRow, address._fromCol, ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString())); - //cell._value = xr.ReadInnerXml(); - } - else - { - _values.SetValue(address._fromRow, address._fromCol, xr.ReadOuterXml()); - _types.SetValue(address._fromRow, address._fromCol, "rt"); - _flags.SetFlagValue(address._fromRow, address._fromCol, true, CellFlags.RichText); - //cell.IsRichText = true; - } - } - else - { - break; - } - } - //if (cell != null) cellList.Add(cell); - - //_cells = new RangeCollection(cellList); - //_rows = new RangeCollection(rowList); - //_formulaCells = new RangeCollection(formulaList); - } - - private bool DoAddRow(XmlTextReader xr) - { - var c = xr.GetAttribute("r")==null ? 0:1; - if (xr.GetAttribute("spans") != null) - { - c++; - } - return xr.AttributeCount > c; - } - /// <summary> - /// Load merged cells - /// </summary> - /// <param name="xr"></param> - private void LoadMergeCells(XmlTextReader xr) - { - if(ReadUntil(xr, "mergeCells", "hyperlinks", "rowBreaks", "colBreaks") && !xr.EOF) - { - while (xr.Read()) - { - if (xr.LocalName != "mergeCell") break; - if (xr.NodeType == XmlNodeType.Element) - { - string address = xr.GetAttribute("ref"); - //int fromRow, fromCol, toRow, toCol; - //ExcelCellBase.GetRowColFromAddress(address, out fromRow, out fromCol, out toRow, out toCol); - //for (int row = fromRow; row <= toRow; row++) - //{ - // for (int col = fromCol; col <= toCol; col++) - // { - // _flags.SetFlagValue(row, col, true,CellFlags.Merged); - // } - //} - //_mergedCells.List.Add(address); - _mergedCells.Add(new ExcelAddress(address), false); - } - } - } - } - /// <summary> - /// Update merged cells - /// </summary> - /// <param name="sw">The writer</param> - private void UpdateMergedCells(StreamWriter sw) - { - sw.Write("<mergeCells>"); - foreach (string address in _mergedCells) - { - sw.Write("<mergeCell ref=\"{0}\" />", address); - } - sw.Write("</mergeCells>"); - } - /// <summary> - /// Reads a row from the XML reader - /// </summary> - /// <param name="xr">The reader</param> - /// <param name="row">The row number</param> - /// <returns></returns> - private RowInternal AddRow(XmlTextReader xr, int row) - { - return new RowInternal() - { - Collapsed=(xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed")== "1" ? true : false), - OutlineLevel = (xr.GetAttribute("outlineLevel") == null ? (short)0 : short.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture)), - Height = (xr.GetAttribute("ht") == null ? -1 : double.Parse(xr.GetAttribute("ht"), CultureInfo.InvariantCulture)), - Hidden = (xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false), - Phonetic = xr.GetAttribute("ph") != null && xr.GetAttribute("ph") == "1" ? true : false, - CustomHeight = xr.GetAttribute("customHeight") == null ? false : xr.GetAttribute("customHeight")=="1" - }; - } - - private static readonly DateTime _excelEpoch = new DateTime(1899, 12, 30); - - public static DateTime IncorrectDurationFromOADate(double value) - { - // This behavior is wrong. Real OADate values have a discontinuity on 30 December 1899. - // For real OADate values, the negative sign applies only to the integer portion of - // the float, *not* to the decimal portion. For example, -0.5 and 0.5 both refer to the - // same date, and -1.5 is actually 1899-12-29 12:00 (1 day before 1899-12-30 00:00 - // plus 0.5 days), *not* 1899-12-28 12:00 (1.5 days before 1899-12-30 00:00). - // - // Unfortunately, AppSheet's duration-handling code gets this very wrong, and treats the - // duration as the offset from 1899-12-30 00:00. This is correct for positive durations, - // but it's wrong for negative durations. This code tries to fix the bug that exists in - // AppSheet's duration-handling code here, and it succeeds in some cases and fails in - // others. - // - // This code also breaks date/time handling for dates before 1899-12-30 00:00 in some - // cases. Specifically, dates end up being offset by one day. - // - // Regardless, changing this behavior is risky, so this code simply replicates the - // existing behavior for - if (value >= 0) - { - return DateTime.FromOADate(value); - } - else - { - // This looks like a very complicated way to call TimeSpan.FromDays(value), but - // TimeSpan.FromDays actually only guarantees millisecond precision, and critically - // rounding is different on .NET Core, resulting in values like (e.g.) 3:15:00 being - // incorrectly rounded. - var offset = DateTime.FromOADate(-value) - _excelEpoch; - return _excelEpoch - offset; - } - } - - private void SetValueFromXml(XmlTextReader xr, string type, int styleID, int row, int col) - { - //XmlNode vnode = colNode.SelectSingleNode("d:v", NameSpaceManager); - //if (vnode == null) return null; - if (type == "s") - { - int ix = xr.ReadElementContentAsInt(); - - // Temporary debugging code to locate intermittent 'Index was out of range' exception. - if (ix < 0) - { - throw new Exception(string.Format("ReadElementContentAsInt returned value '{0}' which is less than zero.", ix)); - } - if (ix >= _package.Workbook._sharedStringsList.Count) - { - throw new Exception(string.Format("ReadElementContentAsInt returned index value '{0}' which is greater than _sharedStringsList count of {1}.", ix, _package.Workbook._sharedStringsList.Count)); - } - - _values.SetValue(row, col, _package.Workbook._sharedStringsList[ix].Text); - if (_package.Workbook._sharedStringsList[ix].isRichText) - { - _flags.SetFlagValue(row, col, true, CellFlags.RichText); - } - } - else if (type == "str") - { - _values.SetValue(row, col, ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString())); - } - else if (type == "b") - { - _values.SetValue(row, col, (xr.ReadElementContentAsString()!="0")); - } - else if (type == "e") - { - _values.SetValue(row, col, GetErrorType(xr.ReadElementContentAsString())); - } - else - { - string v = xr.ReadElementContentAsString(); - var nf = Workbook.Styles.CellXfs[styleID].NumberFormatId; - if ((nf >= 20 && nf <= 21) || (nf >= 45 && nf <= 47)) // Duration - { - double res; - if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out res)) - { - if (Workbook.Date1904) - { - res += ExcelWorkbook.date1904Offset; - } - if (res >= -657435.0 && res < 2958465.9999999) - { - // Get the Duration value expressed as a DateTime. - _values.SetValue(row, col, IncorrectDurationFromOADate(res)); - } - else - { - // Cope with Google Sheets export of cells having a formula. - // Rather than exporting the native value, they export the formatted value. - _values.SetValue(row, col, v); - } - } - else - { - // Cope with Google Sheets export of cells having a formula. - // Rather than exporting the native value, they export the formatted value. - _values.SetValue(row, col, v); - } - } - else if ((nf >= 14 && nf <= 19) || (nf == 22)) // DateTime - { - double res; - if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out res)) - { - if (Workbook.Date1904) - { - res += ExcelWorkbook.date1904Offset; - } - if (res >= -657435.0 && res < 2958465.9999999) - { - _values.SetValue(row, col, DateTime.FromOADate(res)); - } - else - { - // Cope with Google Sheets export of cells having a formula. - // Rather than exporting the native value, they export the formatted value. - _values.SetValue(row, col, v); - } - } - else - { - // Cope with Google Sheets export of cells having a formula. - // Rather than exporting the native value, they export the formatted value. - _values.SetValue(row, col, v); - } - } - else - { - double d; - if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) - { - _values.SetValue(row, col, d); - } - else - { - // Cope with Google Sheets export of cells having a formula. - // Rather than exporting the native value, they export the formatted value. - _values.SetValue(row, col, v); - - //_values.SetValue(row, col, double.NaN); - } - } - } - } - - private object GetErrorType(string v) - { - return ExcelErrorValue.Parse(v.ToUpper(CultureInfo.InvariantCulture)); - //switch(v.ToUpper()) - //{ - // case "#DIV/0!": - // return new ExcelErrorValue.cre(eErrorType.Div0); - // case "#REF!": - // return new ExcelErrorValue(eErrorType.Ref); - // case "#N/A": - // return new ExcelErrorValue(eErrorType.NA); - // case "#NAME?": - // return new ExcelErrorValue(eErrorType.Name); - // case "#NULL!": - // return new ExcelErrorValue(eErrorType.Null); - // case "#NUM!": - // return new ExcelErrorValue(eErrorType.Num); - // default: - // return new ExcelErrorValue(eErrorType.Value); - //} - } - //private string GetSharedString(int stringID) - //{ - // string retValue = null; - // XmlNodeList stringNodes = xlPackage.Workbook.SharedStringsXml.SelectNodes(string.Format("//d:si", stringID), NameSpaceManager); - // XmlNode stringNode = stringNodes[stringID]; - // if (stringNode != null) - // retValue = stringNode.InnerText; - // return (retValue); + // } + // else + // { + // isRef = false; + // } //} - #endregion - #region HeaderFooter - /// <summary> - /// A reference to the header and footer class which allows you to - /// set the header and footer for all odd, even and first pages of the worksheet - /// </summary> - /// <remarks> - /// To format the text you can use the following format - /// <list type="table"> - /// <listheader><term>Prefix</term><description>Description</description></listheader> - /// <item><term>&U</term><description>Underlined</description></item> - /// <item><term>&E</term><description>Double Underline</description></item> - /// <item><term>&K:xxxxxx</term><description>Color. ex &K:FF0000 for red</description></item> - /// <item><term>&"Font,Regular Bold Italic"</term><description>Changes the font. Regular or Bold or Italic or Bold Italic can be used. ex &"Arial,Bold Italic"</description></item> - /// <item><term>&nn</term><description>Change font size. nn is an integer. ex &24</description></item> - /// <item><term>&G</term><description>Placeholder for images. Images can not be added by the library, but its possible to use in a template.</description></item> - /// </list> - /// </remarks> - public ExcelHeaderFooter HeaderFooter - { - get - { - if (_headerFooter == null) - { - XmlNode headerFooterNode = TopNode.SelectSingleNode("d:headerFooter", NameSpaceManager); - if (headerFooterNode == null) - headerFooterNode= CreateNode("d:headerFooter"); - _headerFooter = new ExcelHeaderFooter(NameSpaceManager, headerFooterNode, this); - } - return (_headerFooter); - } - } - #endregion - - #region "PrinterSettings" - /// <summary> - /// Printer settings - /// </summary> - public ExcelPrinterSettings PrinterSettings - { - get - { - var ps = new ExcelPrinterSettings(NameSpaceManager, TopNode, this); - ps.SchemaNodeOrder = SchemaNodeOrder; - return ps; - } - } - #endregion - - #endregion // END Worksheet Public Properties - - #region Worksheet Public Methods - - ///// <summary> - ///// Provides access to an individual cell within the worksheet. - ///// </summary> - ///// <param name="row">The row number in the worksheet</param> - ///// <param name="col">The column number in the worksheet</param> - ///// <returns></returns> - //internal ExcelCell Cell(int row, int col) + //else //{ - // return new ExcelCell(_values, row, col); + // isRef = false; //} - /// <summary> - /// Provides access to a range of cells - /// </summary> - public ExcelRange Cells - { - get - { - CheckSheetType(); - return new ExcelRange(this, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - } - } - /// <summary> - /// Provides access to the selected range of cells - /// </summary> - public ExcelRange SelectedRange - { - get - { - CheckSheetType(); - return new ExcelRange(this, View.SelectedRange); - } - } - MergeCellsCollection _mergedCells = new MergeCellsCollection(); - /// <summary> - /// Addresses to merged ranges - /// </summary> - public MergeCellsCollection MergedCells - { - get - { - CheckSheetType(); - return _mergedCells; - } - } - /// <summary> - /// Provides access to an individual row within the worksheet so you can set its properties. - /// </summary> - /// <param name="row">The row number in the worksheet</param> - /// <returns></returns> - public ExcelRow Row(int row) - { - //ExcelRow r; - //ulong id = ExcelRow.GetRowID(_sheetID, row); - //TODO: Fixa. - //var v = _values.GetValue(row, 0); - //if (v!=null) - //{ - // var ri=(RowInternal)v; - // r = new ExcelRow(this, row) - //} - //else - //{ - //r = new ExcelRow(this, row); - //_values.SetValue(row, 0, r); - //_rows.Add(r); - //} - CheckSheetType(); - if (row < 1 || row > ExcelPackage.MaxRows) - { - throw (new ArgumentException("Row number out of bounds")); - } - return new ExcelRow(this, row); - //return r; - } - /// <summary> - /// Provides access to an individual column within the worksheet so you can set its properties. - /// </summary> - /// <param name="col">The column number in the worksheet</param> - /// <returns></returns> - public ExcelColumn Column(int col) - { - CheckSheetType(); - if (col < 1 || col > ExcelPackage.MaxColumns) - { - throw (new ArgumentException("Column number out of bounds")); - } - var column = _values.GetValue(0, col) as ExcelColumn; - if (column!=null) - { - - if (column.ColumnMin != column.ColumnMax) - { - int maxCol = column.ColumnMax; - column.ColumnMax = col; - ExcelColumn copy = CopyColumn(column, col + 1, maxCol); - } - } - else - { - int r=0, c=col; - if (_values.PrevCell(ref r, ref c)) - { - column = _values.GetValue(0, c) as ExcelColumn; - int maxCol = column.ColumnMax; - if (maxCol >= col) - { - column.ColumnMax = col-1; - if (maxCol > col) - { - ExcelColumn newC = CopyColumn(column, col + 1, maxCol); - } - return CopyColumn(column, col, col); - } - } - //foreach (ExcelColumn checkColumn in _columns) - //{ - // if (col > checkColumn.ColumnMin && col <= checkColumn.ColumnMax) - // { - // int maxCol = checkColumn.ColumnMax; - // checkColumn.ColumnMax = col - 1; - // if (maxCol > col) - // { - // ExcelColumn newC = CopyColumn(checkColumn, col + 1, maxCol); - // } - // return CopyColumn(checkColumn, col,col); - // } - //} - column = new ExcelColumn(this, col); - _values.SetValue(0, col, column); - //_columns.Add(column); - } - return column; - } + //if (restFormula==null) + //{ + //if (newFormulas.Count == newFormulasCount) + //{ + // formula.Address = ExcelCellBase.GetAddress(formula.StartRow, formula.StartCol, row - 1, col); + //} + //else + //{ + // newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress(newFormulas[newFormulas.Count - 1].StartRow, newFormulas[0].StartCol, row - 1, col); + //} - /// <summary> - /// Returns the name of the worksheet - /// </summary> - /// <returns>The name of the worksheet</returns> - public override string ToString() - { - return Name; - } - internal ExcelColumn CopyColumn(ExcelColumn c, int col, int maxCol) - { - ExcelColumn newC = new ExcelColumn(this, col); - newC.ColumnMax = maxCol < ExcelPackage.MaxColumns ? maxCol : ExcelPackage.MaxColumns; - if (c.StyleName != "") - newC.StyleName = c.StyleName; - else - newC.StyleID = c.StyleID; + //restFormula = new Formulas(); + //restFormula.Formula = newFormula; + //restFormula.StartRow = row; + //restFormula.StartCol = col; + //newFormulas.Add(restFormula); + //} + } + } + if (rows < 0 && formula.StartRow > startRow) { + if (formula.StartRow + rows < startRow) { + formula.StartRow = startRow; + } else { + formula.StartRow += rows; + } + } + if (newFormulas.Count > newFormulasCount) { + newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress( + newFormulas[newFormulas.Count - 1].StartRow, + newFormulas[newFormulas.Count - 1].StartCol, + toRow, + toCol); + } + } - newC.OutlineLevel = c.OutlineLevel; - newC.Phonetic = c.Phonetic; - newC.BestFit = c.BestFit; - //_columns.Add(newC); - _values.SetValue(0, col, newC); - newC._width = c._width; - newC._hidden = c._hidden; - return newC; - } - /// <summary> - /// Make the current worksheet active. - /// </summary> - public void Select() - { - View.TabSelected = true; - //Select(Address, true); - } - /// <summary> - /// Selects a range in the worksheet. The active cell is the topmost cell. - /// Make the current worksheet active. - /// </summary> - /// <param name="Address">An address range</param> - public void Select(string Address) - { - Select(Address, true); - } - /// <summary> - /// Selects a range in the worksheet. The actice cell is the topmost cell. - /// </summary> - /// <param name="Address">A range of cells</param> - /// <param name="SelectSheet">Make the sheet active</param> - public void Select(string Address, bool SelectSheet) - { - CheckSheetType(); - int fromCol, fromRow, toCol, toRow; - //Get rows and columns and validate as well - ExcelCellBase.GetRowColFromAddress(Address, out fromRow, out fromCol, out toRow, out toCol); + /// <summary> + /// Delete the specified row from the worksheet. + /// </summary> + /// <param name="row">A row to be deleted</param> + public void DeleteRow(int row) { + DeleteRow(row, 1); + } - if (SelectSheet) - { - View.TabSelected = true; - } - View.SelectedRange = Address; - View.ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol); - } - /// <summary> - /// Selects a range in the worksheet. The active cell is the topmost cell of the first address. - /// Make the current worksheet active. - /// </summary> - /// <param name="Address">An address range</param> - public void Select(ExcelAddress Address) - { - CheckSheetType(); - Select(Address, true); - } - /// <summary> - /// Selects a range in the worksheet. The active cell is the topmost cell of the first address. - /// </summary> - /// <param name="Address">A range of cells</param> - /// <param name="SelectSheet">Make the sheet active</param> - public void Select(ExcelAddress Address, bool SelectSheet) - { + /// <summary> + /// Delete the specified row from the worksheet. + /// </summary> + /// <param name="rowFrom">The start row</param> + /// <param name="rows">Number of rows to delete</param> + public void DeleteRow(int rowFrom, int rows) { + CheckSheetType(); + if (rowFrom < 1 || rowFrom + rows > ExcelPackage.MaxRows) { + throw (new ArgumentException( + "Row out of range. Spans from 1 to " + + ExcelPackage.MaxRows.ToString(CultureInfo.InvariantCulture))); + } + lock (this) { + _values.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); + _types.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); + _formulas.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); + _styles.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); + _flags.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); + _commentsStore.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); + _hyperLinks.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); - CheckSheetType(); - if (SelectSheet) - { - View.TabSelected = true; - } - string selAddress = ExcelCellBase.GetAddress(Address.Start.Row, Address.Start.Column) + ":" + ExcelCellBase.GetAddress(Address.End.Row, Address.End.Column); - if (Address.Addresses != null) - { - foreach (var a in Address.Addresses) - { - selAddress += " " + ExcelCellBase.GetAddress(a.Start.Row, a.Start.Column) + ":" + ExcelCellBase.GetAddress(a.End.Row, a.End.Column); - } - } - View.SelectedRange = selAddress; - View.ActiveCell = ExcelCellBase.GetAddress(Address.Start.Row, Address.Start.Column); - } + AdjustFormulasRow(rowFrom, rows); + FixMergedCellsRow(rowFrom, rows, true); - #region InsertRow - /// <summary> - /// Inserts a new row into the spreadsheet. Existing rows below the position are - /// shifted down. All formula are updated to take account of the new row. - /// </summary> - /// <param name="rowFrom">The position of the new row</param> - /// <param name="rows">Number of rows to insert</param> - public void InsertRow(int rowFrom, int rows) - { - InsertRow(rowFrom, rows, 0); - } - /// <summary> - /// Inserts a new row into the spreadsheet. Existing rows below the position are - /// shifted down. All formula are updated to take account of the new row. - /// </summary> - /// <param name="rowFrom">The position of the new row</param> - /// <param name="rows">Number of rows to insert.</param> - /// <param name="copyStylesFromRow">Copy Styles from this row. Applied to all inserted rows</param> - public void InsertRow(int rowFrom, int rows, int copyStylesFromRow) - { - CheckSheetType(); - var d = Dimension; + foreach (var tbl in Tables) { + tbl.Address = tbl.Address.DeleteRow(rowFrom, rows); + } + } + } - if (rowFrom < 1) - { - throw (new ArgumentOutOfRangeException("rowFrom can't be lesser that 1")); - } + /// <summary> + /// Delete the specified column from the worksheet. + /// </summary> + /// <param name="column">The column to be deleted</param> + public void DeleteColumn(int column) { + DeleteColumn(column, 1); + } - //Check that cells aren't shifted outside the boundries - if (d != null && d.End.Row > rowFrom && d.End.Row + rows > ExcelPackage.MaxRows) - { - throw (new ArgumentOutOfRangeException("Can't insert. Rows will be shifted outside the boundries of the worksheet.")); - } + /// <summary> + /// Delete the specified column from the worksheet. + /// </summary> + /// <param name="columnFrom">The start column</param> + /// <param name="columns">Number of columns to delete</param> + public void DeleteColumn(int columnFrom, int columns) { + if (columnFrom < 1 || columnFrom + columns > ExcelPackage.MaxColumns) { + throw (new ArgumentException( + "Column out of range. Spans from 1 to " + + ExcelPackage.MaxColumns.ToString(CultureInfo.InvariantCulture))); + } + lock (this) { + var col = _values.GetValue(0, columnFrom) as ExcelColumn; + if (col == null) { + var r = 0; + var c = columnFrom; + if (_values.PrevCell(ref r, ref c)) { + col = _values.GetValue(0, c) as ExcelColumn; + if (col._columnMax >= columnFrom) { + col.ColumnMax = columnFrom - 1; + } + } + } - lock (this) - { - _values.Insert(rowFrom, 0, rows, 0); - _formulas.Insert(rowFrom, 0, rows, 0); - _styles.Insert(rowFrom, 0, rows, 0); - _types.Insert(rowFrom, 0, rows, 0); - _commentsStore.Insert(rowFrom, 0, rows, 0); - _hyperLinks.Insert(rowFrom, 0, rows, 0); - _flags.Insert(rowFrom, 0, rows, 0); + _values.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); + _types.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); + _formulas.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); + _styles.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); + _flags.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); + _commentsStore.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); + _hyperLinks.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); - foreach (var f in _sharedFormulas.Values) - { - if (f.StartRow >= rowFrom) f.StartRow += rows; - var a = new ExcelAddressBase(f.Address); - if (a._fromRow >= rowFrom) - { - a._fromRow += rows; - a._toRow += rows; - } - else if (a._toRow >= rowFrom) - { - a._toRow += rows; - } - f.Address = ExcelAddressBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol); - f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, rows, 0, rowFrom, 0); - } - var cse = new CellsStoreEnumerator<object>(_formulas); - while (cse.Next()) - { - if (cse.Value is string) - { - cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), rows, 0, rowFrom, 0); - } - } + AdjustFormulasColumn(columnFrom, columns); + FixMergedCellsColumn(columnFrom, columns, true); - FixMergedCellsRow(rowFrom, rows, false); - if (copyStylesFromRow > 0) - { - var cseS = new CellsStoreEnumerator<int>(_styles, copyStylesFromRow, 0, copyStylesFromRow, ExcelPackage.MaxColumns); //Fixes issue 15068 , 15090 - while(cseS.Next()) - { - for (var r = 0; r < rows; r++) - { - _styles.SetValue(rowFrom + r, cseS.Column, cseS.Value); - } - } - } - foreach (var tbl in Tables) - { - tbl.Address = tbl.Address.AddRow(rowFrom, rows); - } - } - } - /// <summary> - /// Inserts a new column into the spreadsheet. Existing columns below the position are - /// shifted down. All formula are updated to take account of the new column. - /// </summary> - /// <param name="columnFrom">The position of the new column</param> - /// <param name="columns">Number of columns to insert</param> - public void InsertColumn(int columnFrom, int columns) - { - InsertColumn(columnFrom, columns, 0); + var csec = new CellsStoreEnumerator<object>( + _values, + 0, + columnFrom, + 0, + ExcelPackage.MaxColumns); + foreach (var column in csec) { + if (column is ExcelColumn) { + var c = (ExcelColumn)column; + if (c._columnMin >= columnFrom) { + c._columnMin -= columns; + c._columnMax -= columns; + } } - ///<summary> - /// Inserts a new column into the spreadsheet. Existing column to the left are - /// shifted. All formula are updated to take account of the new column. - /// </summary> - /// <param name="columnFrom">The position of the new column</param> - /// <param name="columns">Number of columns to insert.</param> - /// <param name="copyStylesFromColumn">Copy Styles from this column. Applied to all inserted columns</param> - public void InsertColumn(int columnFrom, int columns, int copyStylesFromColumn) - { - CheckSheetType(); - var d = Dimension; + } - if (columnFrom < 1) - { - throw (new ArgumentOutOfRangeException("columnFrom can't be lesser that 1")); - } - //Check that cells aren't shifted outside the boundries - if (d != null && d.End.Column > columnFrom && d.End.Column + columns > ExcelPackage.MaxColumns) - { - throw (new ArgumentOutOfRangeException("Can't insert. Columns will be shifted outside the boundries of the worksheet.")); + foreach (var tbl in Tables) { + if (columnFrom >= tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) { + var node = tbl.Columns[0].TopNode.ParentNode; + var ix = columnFrom - tbl.Address.Start.Column; + for (int i = 0; i < columns; i++) { + if (node.ChildNodes.Count > ix) { + node.RemoveChild(node.ChildNodes[ix]); } + } + tbl._cols = new(tbl); + } - lock (this) - { - _values.Insert(0, columnFrom, 0, columns); - _formulas.Insert(0, columnFrom, 0, columns); - _styles.Insert(0, columnFrom, 0, columns); - _types.Insert(0, columnFrom, 0, columns); - _commentsStore.Insert(0, columnFrom, 0, columns); - _hyperLinks.Insert(0, columnFrom, 0, columns); - _flags.Insert(0, columnFrom, 0, columns); + tbl.Address = tbl.Address.DeleteColumn(columnFrom, columns); + } + } + } - foreach (var f in _sharedFormulas.Values) - { - if (f.StartCol >= columnFrom) f.StartCol += columns; - var a = new ExcelAddressBase(f.Address); - if (a._fromCol >= columnFrom) - { - a._fromCol += columns; - a._toCol += columns; - } - else if (a._toCol >= columnFrom) - { - a._toCol += columns; - } - f.Address = ExcelAddressBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol); - f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, 0, columns, 0, columnFrom); - } + internal void AdjustFormulasRow(int rowFrom, int rows) { + var delSf = new List<int>(); + foreach (var sf in _sharedFormulas.Values) { + var a = new ExcelAddress(sf.Address).DeleteRow(rowFrom, rows); + if (a == null) { + delSf.Add(sf.Index); + } else { + sf.Address = a.Address; + if (sf.StartRow > rowFrom) { + var r = Math.Min(sf.StartRow - rowFrom, rows); + sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, -r, 0, rowFrom, 0); + sf.StartRow -= r; + } + } + } + foreach (var ix in delSf) { + _sharedFormulas.Remove(ix); + } + delSf = null; + var cse = new CellsStoreEnumerator<object>( + _formulas, + 1, + 1, + ExcelPackage.MaxRows, + ExcelPackage.MaxColumns); + while (cse.Next()) { + if (cse.Value is string) { + cse.Value = ExcelCellBase.UpdateFormulaReferences( + cse.Value.ToString(), + -rows, + 0, + rowFrom, + 0); + } + } + } - var cse = new CellsStoreEnumerator<object>(_formulas); - while (cse.Next()) - { - if (cse.Value is string) - { - cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), 0, columns, 0, columnFrom); - } - } + internal void AdjustFormulasColumn(int columnFrom, int columns) { + var delSf = new List<int>(); + foreach (var sf in _sharedFormulas.Values) { + var a = new ExcelAddress(sf.Address).DeleteColumn(columnFrom, columns); + if (a == null) { + delSf.Add(sf.Index); + } else { + sf.Address = a.Address; + //sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -columns, 0, columnFrom); + if (sf.StartCol > columnFrom) { + var c = Math.Min(sf.StartCol - columnFrom, columns); + sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -c, 0, 1); + sf.StartCol -= c; + } - FixMergedCellsColumn(columnFrom, columns, false); + //sf.Address = a.Address; + //sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0,-columns,0, columnFrom); + //if (sf.StartCol >= columnFrom) + //{ + // sf.StartCol -= sf.StartCol; + //} + } + } + foreach (var ix in delSf) { + _sharedFormulas.Remove(ix); + } + delSf = null; + var cse = new CellsStoreEnumerator<object>( + _formulas, + 1, + 1, + ExcelPackage.MaxRows, + ExcelPackage.MaxColumns); + while (cse.Next()) { + if (cse.Value is string) { + cse.Value = ExcelCellBase.UpdateFormulaReferences( + cse.Value.ToString(), + 0, + -columns, + 0, + columnFrom); + } + } + } - var csec = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns); - var lst = new List<ExcelColumn>(); - foreach (var col in csec) - { - if (col is ExcelColumn) - { - lst.Add((ExcelColumn)col); - } - } + /// <summary> + /// Deletes the specified row from the worksheet. + /// </summary> + /// <param name="rowFrom">The number of the start row to be deleted</param> + /// <param name="rows">Number of rows to delete</param> + /// <param name="shiftOtherRowsUp">Not used. Rows are always shifted</param> + public void DeleteRow(int rowFrom, int rows, bool shiftOtherRowsUp) { + DeleteRow(rowFrom, rows); + } - for (int i = lst.Count-1; i >= 0; i--) - { - var c = lst[i]; - if (c._columnMin >= columnFrom) - { - if (c._columnMin + columns <= ExcelPackage.MaxColumns) - { - c._columnMin += columns; - } - else - { - c._columnMin = ExcelPackage.MaxColumns; - } - - if (c._columnMax + columns <= ExcelPackage.MaxColumns) - { - c._columnMax += columns; - } - else - { - c._columnMax = ExcelPackage.MaxColumns; - } - } - else if (c._columnMax >= columnFrom) - { - var cc = c._columnMax - columnFrom; - c._columnMax = columnFrom - 1; - CopyColumn(c, columnFrom + columns, columnFrom + columns + cc); - } - } + /// <summary> + /// Get the cell value from thw worksheet + /// </summary> + /// <param name="row">The row number</param> + /// <param name="column">The row number</param> + /// <returns>The value</returns> + public object GetValue(int row, int column) { + CheckSheetType(); + //ulong cellID = ExcelCellBase.GetCellID(SheetID, Row, Column); + var v = _values.GetValue(row, column); + if (v != null) { + //var cell = ((ExcelCell)_cells[cellID]); + if (_flags.GetFlagValue(row, column, CellFlags.RichText)) { + return Cells[row, column].RichText.Text; + } + return v; + } + return null; + } + /// <summary> + /// Get a strongly typed cell value from the worksheet + /// </summary> + /// <typeparam name="T">The type</typeparam> + /// <param name="row">The row number</param> + /// <param name="column">The row number</param> + /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns> + public T GetValue<T>(int row, int column) { + CheckSheetType(); + //ulong cellID=ExcelCellBase.GetCellID(SheetID, Row, Column); + var v = _values.GetValue(row, column); + if (v == null) { + return default(T); + } - if (copyStylesFromColumn > 0) - { - for (var c = 0; c < columns; c++) - { - var col = this.Column(columnFrom + c); - col.StyleID = this.Column(copyStylesFromColumn).StyleID; - } - } - //Adjust tables - foreach (var tbl in Tables) - { - if (columnFrom > tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) - { - InsertTableColumns(columnFrom, columns, tbl); - } + //var cell=((ExcelCell)_cells[cellID]); + if (_flags.GetFlagValue(row, column, CellFlags.RichText)) { + return (T)(object)Cells[row, column].RichText.Text; + } + return GetTypedValue<T>(v); + } - tbl.Address=tbl.Address.AddColumn(columnFrom, columns); - } - } + //Thanks to Michael Tran for parts of this method + internal T GetTypedValue<T>(object v) { + if (v == null) { + return default(T); + } + Type fromType = v.GetType(); + Type toType = typeof(T); + if (fromType == toType) { + return (T)v; + } + var cnv = TypeDescriptor.GetConverter(fromType); + if (toType + == typeof(DateTime)) //Handle dates + { + if (fromType == typeof(TimeSpan)) { + return ((T)(object)(new DateTime(((TimeSpan)v).Ticks))); + } + if (fromType == typeof(string)) { + DateTime dt; + if (DateTime.TryParse(v.ToString(), out dt)) { + return (T)(object)(dt); + } + return default(T); + } + if (cnv.CanConvertTo(typeof(double))) { + return (T)(object)(DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double)))); + } + return default(T); + } + if (toType + == typeof(TimeSpan)) //Handle timespan + { + if (fromType == typeof(DateTime)) { + return ((T)(object)(new TimeSpan(((DateTime)v).Ticks))); + } + if (fromType == typeof(string)) { + TimeSpan ts; + if (TimeSpan.TryParse(v.ToString(), out ts)) { + return (T)(object)(ts); } + return default(T); + } + if (cnv.CanConvertTo(typeof(double))) { + return (T) + (object)(new TimeSpan( + DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))).Ticks)); + } + try { + // Issue 14682 -- "GetValue<decimal>() won't convert strings" + // As suggested, after all special cases, all .NET to do it's + // preferred conversion rather than simply returning the default + return (T)Convert.ChangeType(v, typeof(T)); + } catch (Exception) { + // This was the previous behaviour -- no conversion is available. + return default(T); + } + } + if (cnv.CanConvertTo(toType)) { + return (T)cnv.ConvertTo(v, typeof(T)); + } + if (toType.IsGenericType && toType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) { + toType = Nullable.GetUnderlyingType(toType); + if (cnv.CanConvertTo(toType)) { + return (T)cnv.ConvertTo(v, typeof(T)); + } + } - private static void InsertTableColumns(int columnFrom, int columns, ExcelTable tbl) - { - var node = tbl.Columns[0].TopNode.ParentNode; - var ix = columnFrom - tbl.Address.Start.Column - 1; - var insPos = node.ChildNodes[ix]; - ix += 2; - for (int i = 0; i < columns; i++) - { - var name = - tbl.Columns.GetUniqueName(string.Format("Column{0}", - (ix++).ToString(CultureInfo.InvariantCulture))); - XmlElement tableColumn = - (XmlElement) tbl.TableXml.CreateNode(XmlNodeType.Element, "tableColumn", ExcelPackage.schemaMain); - tableColumn.SetAttribute("id", (tbl.Columns.Count + i + 1).ToString(CultureInfo.InvariantCulture)); - tableColumn.SetAttribute("name", name); - insPos = node.InsertAfter(tableColumn, insPos); - } //Create tbl Column - tbl._cols = new ExcelTableColumnCollection(tbl); - } + if (fromType == typeof(double) && toType == typeof(decimal)) { + return (T)(object)Convert.ToDecimal(v); + } + if (fromType == typeof(decimal) && toType == typeof(double)) { + return (T)(object)Convert.ToDouble(v); + } + return default(T); + } - /// <summary> - /// Adds a value to the row of merged cells to fix for inserts or deletes - /// </summary> - /// <param name="row"></param> - /// <param name="rows"></param> - /// <param name="delete"></param> - private void FixMergedCellsRow(int row, int rows, bool delete) - { - if (delete) - { - _mergedCells._cells.Delete(row, 0, rows, 0); - } - else - { - _mergedCells._cells.Insert(row, 0, rows, 0); - } + /// <summary> + /// Set the value of a cell + /// </summary> + /// <param name="row">The row number</param> + /// <param name="column">The column number</param> + /// <param name="value">The value</param> + public void SetValue(int row, int column, object value) { + CheckSheetType(); + if (row < 1 || column < 1 || row > ExcelPackage.MaxRows && column > ExcelPackage.MaxColumns) { + throw new ArgumentOutOfRangeException("Row or Column out of range"); + } + _values.SetValue(row, column, value); + } - List<int> removeIndex = new List<int>(); - for (int i = 0; i < _mergedCells.Count; i++) - { - if (!string.IsNullOrEmpty( _mergedCells[i])) - { - ExcelAddressBase addr = new ExcelAddressBase(_mergedCells[i]), newAddr; - if (delete) - { - newAddr = addr.DeleteRow(row, rows); - if (newAddr == null) - { - removeIndex.Add(i); - continue; - } - } - else - { - newAddr = addr.AddRow(row, rows); - if (newAddr.Address != addr.Address) - { - // _mergedCells._cells.Insert(row, 0, rows, 0); - _mergedCells.SetIndex(newAddr, i); - } - } + /// <summary> + /// Set the value of a cell + /// </summary> + /// <param name="address">The Excel address</param> + /// <param name="value">The value</param> + public void SetValue(string address, object value) { + CheckSheetType(); + int row, + col; + ExcelCellBase.GetRowCol(address, out row, out col, true); + if (row < 1 || col < 1 || row > ExcelPackage.MaxRows && col > ExcelPackage.MaxColumns) { + throw new ArgumentOutOfRangeException("Address is invalid or out of range"); + } + _values.SetValue(row, col, value); + } - if (newAddr.Address != addr.Address) - { - _mergedCells.List[i] = newAddr._address; - } - } - } - for (int i = removeIndex.Count - 1; i >= 0; i--) - { - _mergedCells.List.RemoveAt(removeIndex[i]); - } - } - /// <summary> - /// Adds a value to the row of merged cells to fix for inserts or deletes - /// </summary> - /// <param name="column"></param> - /// <param name="columns"></param> - /// <param name="delete"></param> - private void FixMergedCellsColumn(int column, int columns, bool delete) - { - if (delete) - { - _mergedCells._cells.Delete(0, column, 0, columns); - } - else - { - _mergedCells._cells.Insert(0, column, 0, columns); - } - List<int> removeIndex = new List<int>(); - for (int i = 0; i < _mergedCells.Count; i++) - { - if (!string.IsNullOrEmpty(_mergedCells[i])) - { - ExcelAddressBase addr = new ExcelAddressBase(_mergedCells[i]), newAddr; - if (delete) - { - newAddr = addr.DeleteColumn(column, columns); - if (newAddr == null) - { - removeIndex.Add(i); - continue; - } - } - else - { - newAddr = addr.AddColumn(column, columns); - if (newAddr.Address != addr.Address) - { - _mergedCells.SetIndex(newAddr, i); - } - } + /// <summary> + /// Get MergeCell Index No + /// </summary> + /// <param name="row"></param> + /// <param name="column"></param> + /// <returns></returns> + public int GetMergeCellId(int row, int column) { + for (int i = 0; i < _mergedCells.Count; i++) { + if (!string.IsNullOrEmpty(_mergedCells[i])) { + ExcelRange range = Cells[_mergedCells[i]]; - if (newAddr.Address != addr.Address) - { - _mergedCells.List[i] = newAddr._address; - } - } - } - for (int i = removeIndex.Count - 1; i >= 0; i--) - { - _mergedCells.List.RemoveAt(removeIndex[i]); - } + if (range.Start.Row <= row && row <= range.End.Row) { + if (range.Start.Column <= column && column <= range.End.Column) { + return i + 1; + } } - private void FixSharedFormulasRows(int position, int rows) - { - List<Formulas> added = new List<Formulas>(); - List<Formulas> deleted = new List<Formulas>(); + } + } + return 0; + } - foreach (int id in _sharedFormulas.Keys) - { - var f = _sharedFormulas[id]; - int fromCol, fromRow, toCol, toRow; + internal void Save() { + DeletePrinterSettings(); - ExcelCellBase.GetRowColFromAddress(f.Address, out fromRow, out fromCol, out toRow, out toCol); - if (position >= fromRow && position+(Math.Abs(rows)) <= toRow) //Insert/delete is whithin the share formula address - { - if (rows > 0) //Insert - { - f.Address = ExcelCellBase.GetAddress(fromRow, fromCol) + ":" + ExcelCellBase.GetAddress(position - 1, toCol); - if (toRow != fromRow) - { - Formulas newF = new Formulas(SourceCodeTokenizer.Default); - newF.StartCol = f.StartCol; - newF.StartRow = position + rows; - newF.Address = ExcelCellBase.GetAddress(position + rows, fromCol) + ":" + ExcelCellBase.GetAddress(toRow + rows, toCol); - newF.Formula = ExcelCellBase.TranslateFromR1C1(ExcelCellBase.TranslateToR1C1(f.Formula, f.StartRow, f.StartCol), position, f.StartCol); - added.Add(newF); - } - } - else - { - if (fromRow - rows < toRow) - { - f.Address = ExcelCellBase.GetAddress(fromRow, fromCol, toRow+rows, toCol); - } - else - { - f.Address = ExcelCellBase.GetAddress(fromRow, fromCol) + ":" + ExcelCellBase.GetAddress(toRow + rows, toCol); - } - } - } - else if (position <= toRow) - { - if (rows > 0) //Insert before shift down - { - f.StartRow += rows; - //f.Formula = ExcelCell.UpdateFormulaReferences(f.Formula, rows, 0, position, 0); //Recalc the cells positions - f.Address = ExcelCellBase.GetAddress(fromRow + rows, fromCol) + ":" + ExcelCellBase.GetAddress(toRow + rows, toCol); - } - else - { - //Cells[f.Address].SetSharedFormulaID(int.MinValue); - if (position <= fromRow && position + Math.Abs(rows) > toRow) //Delete the formula - { - deleted.Add(f); - } - else - { - toRow = toRow + rows < position - 1 ? position - 1 : toRow + rows; - if (position <= fromRow) - { - fromRow = fromRow + rows < position ? position : fromRow + rows; - } - - f.Address = ExcelCellBase.GetAddress(fromRow, fromCol, toRow, toCol); - Cells[f.Address].SetSharedFormulaID(f.Index); - //f.StartRow = fromRow; + if (_worksheetXml != null) { + if (!(this is ExcelChartsheet)) { + // save the header & footer (if defined) + if (_headerFooter != null) { + HeaderFooter.Save(); + } - //f.Formula = ExcelCell.UpdateFormulaReferences(f.Formula, rows, 0, position, 0); - - } - } - } - } + var d = Dimension; + if (d == null) { + DeleteAllNode("d:dimension/@ref"); + } else { + SetXmlNodeString("d:dimension/@ref", d.Address); + } - AddFormulas(added, position, rows); + SaveComments(); + SaveTables(); + SavePivotTables(); + } + } + } - //Remove formulas - foreach (Formulas f in deleted) - { - _sharedFormulas.Remove(f.Index); - } + internal void SaveHandler(StreamWriter streamWriter) { + //Create the nodes if they do not exist. + if (this is ExcelChartsheet) { + streamWriter.Write(_worksheetXml.OuterXml); + } else { + CreateNode("d:cols"); + CreateNode("d:sheetData"); + CreateNode("d:mergeCells"); + CreateNode("d:hyperlinks"); + CreateNode("d:rowBreaks"); + CreateNode("d:colBreaks"); - //Fix Formulas - added = new List<Formulas>(); - foreach (int id in _sharedFormulas.Keys) - { - var f = _sharedFormulas[id]; - UpdateSharedFormulaRow(ref f, position, rows, ref added); - } - AddFormulas(added, position, rows); - } + //StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write)); + var xml = _worksheetXml.OuterXml; + int colStart = 0, + colEnd = 0; + GetBlockPos(xml, "cols", ref colStart, ref colEnd); - private void AddFormulas(List<Formulas> added, int position, int rows) - { - //Add new formulas - foreach (Formulas f in added) - { - f.Index = GetMaxShareFunctionIndex(false); - _sharedFormulas.Add(f.Index, f); - Cells[f.Address].SetSharedFormulaID(f.Index); - } - } + streamWriter.Write(xml.Substring(0, colStart)); + var colBreaks = new List<int>(); + //if (_columns.Count > 0) + //{ + UpdateColumnData(streamWriter); + //} - private void UpdateSharedFormulaRow(ref Formulas formula, int startRow, int rows, ref List<Formulas> newFormulas) - { - int fromRow,fromCol, toRow, toCol; - int newFormulasCount = newFormulas.Count; - ExcelCellBase.GetRowColFromAddress(formula.Address, out fromRow, out fromCol, out toRow, out toCol); - //int refSplits = Regex.Split(formula.Formula, "#REF!").GetUpperBound(0); - string formualR1C1; - if (rows > 0 || fromRow <= startRow) - { - formualR1C1 = ExcelRangeBase.TranslateToR1C1(formula.Formula, formula.StartRow, formula.StartCol); - formula.Formula = ExcelRangeBase.TranslateFromR1C1(formualR1C1, fromRow, formula.StartCol); - } - else - { - formualR1C1 = ExcelRangeBase.TranslateToR1C1(formula.Formula, formula.StartRow-rows, formula.StartCol); - formula.Formula = ExcelRangeBase.TranslateFromR1C1(formualR1C1, formula.StartRow, formula.StartCol); - } - //bool isRef = false; - //Formulas restFormula=formula; - string prevFormualR1C1 = formualR1C1; - for (int row = fromRow; row <= toRow; row++) - { - for (int col = fromCol; col <= toCol; col++) - { - string newFormula; - string currentFormulaR1C1; - if (rows > 0 || row < startRow) - { - newFormula = ExcelCellBase.UpdateFormulaReferences(ExcelCellBase.TranslateFromR1C1(formualR1C1, row, col), rows, 0, startRow, 0); - currentFormulaR1C1 = ExcelRangeBase.TranslateToR1C1(newFormula, row, col); - } - else - { - newFormula = ExcelCellBase.UpdateFormulaReferences(ExcelCellBase.TranslateFromR1C1(formualR1C1, row-rows, col), rows, 0, startRow, 0); - currentFormulaR1C1 = ExcelRangeBase.TranslateToR1C1(newFormula, row, col); - } - if (currentFormulaR1C1 != prevFormualR1C1) //newFormula.Contains("#REF!")) - { - //if (refSplits == 0 || Regex.Split(newFormula, "#REF!").GetUpperBound(0) != refSplits) - //{ - //isRef = true; - if (row == fromRow && col == fromCol) - { - formula.Formula = newFormula; - } - else - { - if (newFormulas.Count == newFormulasCount) - { - formula.Address = ExcelCellBase.GetAddress(formula.StartRow, formula.StartCol, row - 1, col); - } - else - { - newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress(newFormulas[newFormulas.Count - 1].StartRow, newFormulas[newFormulas.Count - 1].StartCol, row - 1, col); - } - var refFormula = new Formulas(SourceCodeTokenizer.Default); - refFormula.Formula = newFormula; - refFormula.StartRow = row; - refFormula.StartCol = col; - newFormulas.Add(refFormula); + int cellStart = colEnd, + cellEnd = colEnd; + GetBlockPos(xml, "sheetData", ref cellStart, ref cellEnd); - //restFormula = null; - prevFormualR1C1 = currentFormulaR1C1; - } - } - // } - // else - // { - // isRef = false; - // } - //} - //else - //{ - // isRef = false; - //} - //if (restFormula==null) - //{ - //if (newFormulas.Count == newFormulasCount) - //{ - // formula.Address = ExcelCellBase.GetAddress(formula.StartRow, formula.StartCol, row - 1, col); - //} - //else - //{ -// newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress(newFormulas[newFormulas.Count - 1].StartRow, newFormulas[0].StartCol, row - 1, col); - //} + streamWriter.Write(xml.Substring(colEnd, cellStart - colEnd)); + var rowBreaks = new List<int>(); + UpdateRowCellData(streamWriter); - //restFormula = new Formulas(); - //restFormula.Formula = newFormula; - //restFormula.StartRow = row; - //restFormula.StartCol = col; - //newFormulas.Add(restFormula); - //} - } - } - if (rows < 0 && formula.StartRow > startRow) - { - if (formula.StartRow + rows < startRow) - { - formula.StartRow = startRow; - } - else - { - formula.StartRow += rows; - } - } - if (newFormulas.Count > newFormulasCount) - { - newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress(newFormulas[newFormulas.Count - 1].StartRow, newFormulas[newFormulas.Count - 1].StartCol, toRow, toCol); - } - } - #endregion + int mergeStart = cellEnd, + mergeEnd = cellEnd; - #region DeleteRow - /// <summary> - /// Delete the specified row from the worksheet. - /// </summary> - /// <param name="row">A row to be deleted</param> - public void DeleteRow(int row) - { - DeleteRow(row, 1); - } - /// <summary> - /// Delete the specified row from the worksheet. - /// </summary> - /// <param name="rowFrom">The start row</param> - /// <param name="rows">Number of rows to delete</param> - public void DeleteRow(int rowFrom, int rows) - { - CheckSheetType(); - if (rowFrom < 1 || rowFrom + rows > ExcelPackage.MaxRows) - { - throw(new ArgumentException("Row out of range. Spans from 1 to " + ExcelPackage.MaxRows.ToString(CultureInfo.InvariantCulture))); - } - lock (this) - { - _values.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); - _types.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); - _formulas.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); - _styles.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); - _flags.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); - _commentsStore.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); - _hyperLinks.Delete(rowFrom, 0, rows, ExcelPackage.MaxColumns); + GetBlockPos(xml, "mergeCells", ref mergeStart, ref mergeEnd); + streamWriter.Write(xml.Substring(cellEnd, mergeStart - cellEnd)); - AdjustFormulasRow(rowFrom, rows); - FixMergedCellsRow(rowFrom, rows, true); + CleanupMergedCells(_mergedCells); + if (_mergedCells.Count > 0) { + UpdateMergedCells(streamWriter); + } - foreach (var tbl in Tables) - { - tbl.Address = tbl.Address.DeleteRow(rowFrom, rows); - } - } - } - /// <summary> - /// Delete the specified column from the worksheet. - /// </summary> - /// <param name="column">The column to be deleted</param> - public void DeleteColumn(int column) - { - DeleteColumn(column,1); - } - /// <summary> - /// Delete the specified column from the worksheet. - /// </summary> - /// <param name="columnFrom">The start column</param> - /// <param name="columns">Number of columns to delete</param> - public void DeleteColumn(int columnFrom, int columns) - { - if (columnFrom < 1 || columnFrom + columns > ExcelPackage.MaxColumns) - { - throw (new ArgumentException("Column out of range. Spans from 1 to " + ExcelPackage.MaxColumns.ToString(CultureInfo.InvariantCulture))); - } - lock (this) - { - var col = _values.GetValue(0, columnFrom) as ExcelColumn; - if (col == null) - { - var r = 0; - var c = columnFrom; - if(_values.PrevCell(ref r,ref c)) - { - col = _values.GetValue(0, c) as ExcelColumn; - if(col._columnMax >= columnFrom) - { - col.ColumnMax=columnFrom-1; - } - } - } + int hyperStart = mergeEnd, + hyperEnd = mergeEnd; + GetBlockPos(xml, "hyperlinks", ref hyperStart, ref hyperEnd); + streamWriter.Write(xml.Substring(mergeEnd, hyperStart - mergeEnd)); + //if (_hyperLinkCells.Count > 0) + //{ + UpdateHyperLinks(streamWriter); + // } - _values.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); - _types.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); - _formulas.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); - _styles.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); - _flags.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); - _commentsStore.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); - _hyperLinks.Delete(0, columnFrom, ExcelPackage.MaxRows, columns); + int rowBreakStart = hyperEnd, + rowBreakEnd = hyperEnd; + GetBlockPos(xml, "rowBreaks", ref rowBreakStart, ref rowBreakEnd); + streamWriter.Write(xml.Substring(hyperEnd, rowBreakStart - hyperEnd)); + //if (rowBreaks.Count > 0) + //{ + UpdateRowBreaks(streamWriter); + //} - AdjustFormulasColumn(columnFrom, columns); - FixMergedCellsColumn(columnFrom, columns, true); + int colBreakStart = rowBreakEnd, + colBreakEnd = rowBreakEnd; + GetBlockPos(xml, "colBreaks", ref colBreakStart, ref colBreakEnd); + streamWriter.Write(xml.Substring(rowBreakEnd, colBreakStart - rowBreakEnd)); + //if (colBreaks.Count > 0) + //{ + UpdateColBreaks(streamWriter); + //} + streamWriter.Write(xml.Substring(colBreakEnd, xml.Length - colBreakEnd)); + } + } - var csec = new CellsStoreEnumerator<object>(_values, 0, columnFrom, 0, ExcelPackage.MaxColumns); - foreach (var column in csec) - { - if (column is ExcelColumn) - { - var c = (ExcelColumn)column; - if (c._columnMin >= columnFrom) - { - c._columnMin -= columns; - c._columnMax -= columns; - } - } - } + /// <summary> + /// Delete the printersettings relationship and part. + /// </summary> + private void DeletePrinterSettings() { + //Delete the relationship from the pageSetup tag + XmlAttribute attr = (XmlAttribute) + WorksheetXml.SelectSingleNode("//d:pageSetup/@r:id", NameSpaceManager); + if (attr != null) { + string relId = attr.Value; + //First delete the attribute from the XML + attr.OwnerElement.Attributes.Remove(attr); + if (Part.RelationshipExists(relId)) { + var rel = Part.GetRelationship(relId); + Uri printerSettingsUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); + Part.DeleteRelationship(rel.Id); - foreach (var tbl in Tables) - { - if (columnFrom >= tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column) - { - var node = tbl.Columns[0].TopNode.ParentNode; - var ix = columnFrom - tbl.Address.Start.Column; - for (int i = 0; i < columns; i++) - { - if (node.ChildNodes.Count > ix) - { - node.RemoveChild(node.ChildNodes[ix]); - } - } - tbl._cols = new ExcelTableColumnCollection(tbl); - } + //Delete the part from the package + if (_package.Package.PartExists(printerSettingsUri)) { + _package.Package.DeletePart(printerSettingsUri); + } + } + } + } - tbl.Address = tbl.Address.DeleteColumn(columnFrom, columns); - } - } + private void SaveComments() { + if (_comments != null) { + if (_comments.Count == 0) { + if (_comments.Uri != null) { + Part.DeleteRelationship(_comments.RelId); + _package.Package.DeletePart(_comments.Uri); } - internal void AdjustFormulasRow(int rowFrom, int rows) - { - var delSF = new List<int>(); - foreach (var sf in _sharedFormulas.Values) - { - var a = new ExcelAddress(sf.Address).DeleteRow(rowFrom, rows); - if (a==null) - { - delSF.Add(sf.Index); - } - else - { - sf.Address = a.Address; - if (sf.StartRow > rowFrom) - { - var r = Math.Min(sf.StartRow - rowFrom, rows); - sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, -r, 0, rowFrom, 0); - sf.StartRow -= r; - } - } - } - foreach (var ix in delSF) - { - _sharedFormulas.Remove(ix); - } - delSF = null; - var cse = new CellsStoreEnumerator<object>(_formulas, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - while (cse.Next()) - { - if (cse.Value is string) - { - cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), -rows, 0, rowFrom, 0); - } - } + RemoveLegacyDrawingRel(VmlDrawingsComments.RelId); + } else { + if (_comments.Uri == null) { + _comments.Uri = new(string.Format("/xl/comments{0}.xml", SheetID), UriKind.Relative); + } + if (_comments.Part == null) { + _comments.Part = _package.Package.CreatePart( + _comments.Uri, + "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", + _package.Compression); + var rel = Part.CreateRelationship( + UriHelper.GetRelativeUri(WorksheetUri, _comments.Uri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/comments"); } - internal void AdjustFormulasColumn(int columnFrom, int columns) - { - var delSF = new List<int>(); - foreach (var sf in _sharedFormulas.Values) - { - var a = new ExcelAddress(sf.Address).DeleteColumn(columnFrom, columns); - if (a == null) - { - delSF.Add(sf.Index); - } - else - { - sf.Address = a.Address; - //sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -columns, 0, columnFrom); - if (sf.StartCol > columnFrom) - { - var c = Math.Min(sf.StartCol - columnFrom, columns); - sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -c, 0, 1); - sf.StartCol-= c; - } + _comments.CommentXml.Save(_comments.Part.GetStream(FileMode.Create)); + } + } - //sf.Address = a.Address; - //sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0,-columns,0, columnFrom); - //if (sf.StartCol >= columnFrom) - //{ - // sf.StartCol -= sf.StartCol; - //} - } - } - foreach (var ix in delSF) - { - _sharedFormulas.Remove(ix); - } - delSF = null; - var cse = new CellsStoreEnumerator<object>(_formulas, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - while (cse.Next()) - { - if (cse.Value is string) - { - cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), 0, -columns, 0, columnFrom); - } - } + if (_vmlDrawings != null) { + if (_vmlDrawings.Count == 0) { + if (_vmlDrawings.Uri != null) { + Part.DeleteRelationship(_vmlDrawings.RelId); + _package.Package.DeletePart(_vmlDrawings.Uri); } - /// <summary> - /// Deletes the specified row from the worksheet. - /// </summary> - /// <param name="rowFrom">The number of the start row to be deleted</param> - /// <param name="rows">Number of rows to delete</param> - /// <param name="shiftOtherRowsUp">Not used. Rows are always shifted</param> - public void DeleteRow(int rowFrom, int rows, bool shiftOtherRowsUp) - { - DeleteRow(rowFrom, rows); + } else { + if (_vmlDrawings.Uri == null) { + _vmlDrawings.Uri = GetNewUri(_package.Package, "/xl/drawings/vmlDrawing{0}.vml"); } - #endregion - /// <summary> - /// Get the cell value from thw worksheet - /// </summary> - /// <param name="Row">The row number</param> - /// <param name="Column">The row number</param> - /// <returns>The value</returns> - public object GetValue(int Row, int Column) - { - CheckSheetType(); - //ulong cellID = ExcelCellBase.GetCellID(SheetID, Row, Column); - var v = _values.GetValue(Row, Column); - if (v!=null) - { - //var cell = ((ExcelCell)_cells[cellID]); - if (_flags.GetFlagValue(Row, Column, CellFlags.RichText)) - { - return (object)Cells[Row, Column].RichText.Text; - } - else - { - return v; - } - } - else - { - return null; - } + if (_vmlDrawings.Part == null) { + _vmlDrawings.Part = _package.Package.CreatePart( + _vmlDrawings.Uri, + "application/vnd.openxmlformats-officedocument.vmlDrawing", + _package.Compression); + var rel = Part.CreateRelationship( + UriHelper.GetRelativeUri(WorksheetUri, _vmlDrawings.Uri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/vmlDrawing"); + SetXmlNodeString("d:legacyDrawing/@r:id", rel.Id); + _vmlDrawings.RelId = rel.Id; } + _vmlDrawings.VmlDrawingXml.Save(_vmlDrawings.Part.GetStream()); + } + } + } - /// <summary> - /// Get a strongly typed cell value from the worksheet - /// </summary> - /// <typeparam name="T">The type</typeparam> - /// <param name="Row">The row number</param> - /// <param name="Column">The row number</param> - /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns> - public T GetValue<T>(int Row, int Column) - { - CheckSheetType(); - //ulong cellID=ExcelCellBase.GetCellID(SheetID, Row, Column); - var v = _values.GetValue(Row, Column); - if (v==null) - { - return default(T); + /// <summary> + /// Save all table data + /// </summary> + private void SaveTables() { + foreach (var tbl in Tables) { + if (tbl.ShowHeader || tbl.ShowTotal) { + int colNum = tbl.Address._fromCol; + var colVal = new HashSet<string>(); + foreach (var col in tbl.Columns) { + string n = col.Name.ToLower(CultureInfo.InvariantCulture); + if (tbl.ShowHeader) { + n = tbl.WorkSheet.GetValue<string>( + tbl.Address._fromRow, + tbl.Address._fromCol + col.Position); + if (string.IsNullOrEmpty(n)) { + n = col.Name.ToLower(CultureInfo.InvariantCulture); + } else { + col.Name = n; } + } else { + n = col.Name.ToLower(CultureInfo.InvariantCulture); + } - //var cell=((ExcelCell)_cells[cellID]); - if (_flags.GetFlagValue(Row, Column, CellFlags.RichText)) - { - return (T)(object)Cells[Row, Column].RichText.Text; - } - else - { - return GetTypedValue<T>(v); + if (colVal.Contains(n)) { + throw (new InvalidDataException( + string.Format( + "Table {0} Column {1} does not have a unique name.", + tbl.Name, + col.Name))); + } + colVal.Add(n); + col.Name = ConvertUtil.ExcelEncodeString(col.Name); + if (tbl.ShowHeader) { + _values.SetValue(tbl.Address._fromRow, colNum, col.Name); + } + if (tbl.ShowTotal) { + SetTableTotalFunction(tbl, col, colNum); + } + if (!string.IsNullOrEmpty(col.CalculatedColumnFormula)) { + int fromRow = tbl.ShowHeader ? tbl.Address._fromRow + 1 : tbl.Address._fromRow; + int toRow = tbl.ShowTotal ? tbl.Address._toRow - 1 : tbl.Address._toRow; + for (int row = fromRow; row <= toRow; row++) { + //Cell(row, colNum).Formula = col.CalculatedColumnFormula; + SetFormula(row, colNum, col.CalculatedColumnFormula); } + } + colNum++; } - //Thanks to Michael Tran for parts of this method - internal T GetTypedValue<T>(object v) - { - if (v == null) - { - return default(T); - } - Type fromType = v.GetType(); - Type toType = typeof(T); - if (fromType == toType) - { - return (T)v; - } - var cnv = TypeDescriptor.GetConverter(fromType); - if (toType == typeof(DateTime)) //Handle dates - { - if (fromType == typeof(TimeSpan)) - { - return ((T)(object)(new DateTime(((TimeSpan)v).Ticks))); - } - else if (fromType == typeof(string)) - { - DateTime dt; - if (DateTime.TryParse(v.ToString(), out dt)) - { - return (T)(object)(dt); - } - else - { - return default(T); - } + } + if (tbl.Part == null) { + tbl.TableUri = GetNewUri(_package.Package, "/xl/tables/table{0}.xml", tbl.Id); + tbl.Part = _package.Package.CreatePart( + tbl.TableUri, + "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", + Workbook._package.Compression); + var stream = tbl.Part.GetStream(FileMode.Create); + tbl.TableXml.Save(stream); + var rel = Part.CreateRelationship( + UriHelper.GetRelativeUri(WorksheetUri, tbl.TableUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/table"); + tbl.RelationshipID = rel.Id; - } - else - { - if (cnv.CanConvertTo(typeof(double))) - { - return (T)(object)(DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double)))); - } - else - { - return default(T); - } - } - } - else if (toType == typeof(TimeSpan)) //Handle timespan - { - if (fromType == typeof(DateTime)) - { - return ((T)(object)(new TimeSpan(((DateTime)v).Ticks))); - } - else if (fromType == typeof(string)) - { - TimeSpan ts; - if (TimeSpan.TryParse(v.ToString(), out ts)) - { - return (T)(object)(ts); - } - else - { - return default(T); - } - } - else - { - if (cnv.CanConvertTo(typeof(double))) - { + CreateNode("d:tableParts"); + XmlNode tbls = TopNode.SelectSingleNode("d:tableParts", NameSpaceManager); - return (T)(object)(new TimeSpan(DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))).Ticks)); - } - else - { - try - { - // Issue 14682 -- "GetValue<decimal>() won't convert strings" - // As suggested, after all special cases, all .NET to do it's - // preferred conversion rather than simply returning the default - return (T)Convert.ChangeType(v, typeof(T)); - } - catch (Exception) - { - // This was the previous behaviour -- no conversion is available. - return default(T); - } - } - } - } - else - { - if (cnv.CanConvertTo(toType)) - { - return (T)cnv.ConvertTo(v, typeof(T)); - } - else - { - if (toType.IsGenericType && toType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) - { - toType = Nullable.GetUnderlyingType(toType); - if (cnv.CanConvertTo(toType)) - { - return (T)cnv.ConvertTo(v, typeof(T)); - } - } + var tblNode = tbls.OwnerDocument.CreateElement("tablePart", ExcelPackage._schemaMain); + tbls.AppendChild(tblNode); + tblNode.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id); + } else { + var stream = tbl.Part.GetStream(FileMode.Create); + tbl.TableXml.Save(stream); + } + } + } - if(fromType==typeof(double) && toType==typeof(decimal)) - { - return (T)(object)Convert.ToDecimal(v); - } - else if (fromType == typeof(decimal) && toType == typeof(double)) - { - return (T)(object)Convert.ToDouble(v); - } - else - { - return default(T); - } - } - } + internal void SetTableTotalFunction(ExcelTable tbl, ExcelTableColumn col, int colNum = -1) { + if (tbl.ShowTotal == false) { + return; + } + if (colNum == -1) { + for (int i = 0; i < tbl.Columns.Count; i++) { + if (tbl.Columns[i].Name == col.Name) { + colNum = tbl.Address._fromCol + i; } - /// <summary> - /// Set the value of a cell - /// </summary> - /// <param name="Row">The row number</param> - /// <param name="Column">The column number</param> - /// <param name="Value">The value</param> - public void SetValue(int Row, int Column, object Value) - { - CheckSheetType(); - if (Row < 1 || Column < 1 || Row > ExcelPackage.MaxRows && Column > ExcelPackage.MaxColumns) - { - throw new ArgumentOutOfRangeException("Row or Column out of range"); - } - _values.SetValue(Row, Column, Value); - } - /// <summary> - /// Set the value of a cell - /// </summary> - /// <param name="Address">The Excel address</param> - /// <param name="Value">The value</param> - public void SetValue(string Address, object Value) - { - CheckSheetType(); - int row, col; - ExcelAddressBase.GetRowCol(Address, out row, out col, true); - if (row < 1 || col < 1 || row > ExcelPackage.MaxRows && col > ExcelPackage.MaxColumns) - { - throw new ArgumentOutOfRangeException("Address is invalid or out of range"); - } - _values.SetValue(row, col, Value); - } + } + } + if (col.TotalsRowFunction == RowFunctions.Custom) { + SetFormula(tbl.Address._toRow, colNum, col.TotalsRowFormula); + } else if (col.TotalsRowFunction != RowFunctions.None) { + switch (col.TotalsRowFunction) { + case RowFunctions.Average: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "101")); + break; + case RowFunctions.Count: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "102")); + break; + case RowFunctions.CountNums: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "103")); + break; + case RowFunctions.Max: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "104")); + break; + case RowFunctions.Min: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "105")); + break; + case RowFunctions.StdDev: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "107")); + break; + case RowFunctions.Var: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "110")); + break; + case RowFunctions.Sum: + SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "109")); + break; + default: + throw (new("Unknown RowFunction enum")); + } + } else { + _values.SetValue(tbl.Address._toRow, colNum, col.TotalsRowLabel); + } + } - #region MergeCellId + internal void SetFormula(int row, int col, object value) { + _formulas.SetValue(row, col, value); + if (!_values.Exists(row, col)) { + _values.SetValue(row, col, null); + } + } - /// <summary> - /// Get MergeCell Index No - /// </summary> - /// <param name="row"></param> - /// <param name="column"></param> - /// <returns></returns> - public int GetMergeCellId(int row, int column) - { - for (int i = 0; i < _mergedCells.Count; i++) - { - if(!string.IsNullOrEmpty( _mergedCells[i])) - { - ExcelRange range = Cells[_mergedCells[i]]; + internal void SetStyle(int row, int col, int value) { + _styles.SetValue(row, col, value); + if (!_values.Exists(row, col)) { + _values.SetValue(row, col, null); + } + } + + private void SavePivotTables() { + foreach (var pt in PivotTables) { + if (pt.DataFields.Count > 1) { + XmlElement parentNode; + if (pt.DataOnRows) { + parentNode = + pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) as XmlElement; + if (parentNode == null) { + pt.CreateNode("d:rowFields"); + parentNode = + pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) + as XmlElement; + } + } else { + parentNode = + pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) as XmlElement; + if (parentNode == null) { + pt.CreateNode("d:colFields"); + parentNode = + pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) + as XmlElement; + } + } - if (range.Start.Row <= row && row <= range.End.Row) - { - if (range.Start.Column <= column && column <= range.End.Column) - { - return i + 1; - } - } - } + if (parentNode.SelectSingleNode("d:field[@ x= \"-2\"]", pt.NameSpaceManager) == null) { + XmlElement fieldNode = pt.PivotTableXml.CreateElement("field", ExcelPackage._schemaMain); + fieldNode.SetAttribute("x", "-2"); + parentNode.AppendChild(fieldNode); + } + } + var ws = Workbook.Worksheets[pt.CacheDefinition.SourceRange.WorkSheet]; + var t = ws.Tables.GetFromRange(pt.CacheDefinition.SourceRange); + var fields = pt.CacheDefinition.CacheDefinitionXml.SelectNodes( + "d:pivotCacheDefinition/d:cacheFields/d:cacheField", + NameSpaceManager); + int ix = 0; + if (fields != null) { + var flds = new HashSet<string>(); + foreach (XmlElement node in fields) { + if (ix >= pt.CacheDefinition.SourceRange.Columns) { + break; + } + var fldName = node.GetAttribute("name"); //Fixes issue 15295 dup name error + if (string.IsNullOrEmpty(fldName)) { + fldName = + (t == null + ? pt.CacheDefinition.SourceRange.Offset(0, ix++, 1, 1).Value.ToString() + : t.Columns[ix++].Name); + } + if (flds.Contains(fldName)) { + fldName = GetNewName(flds, fldName); + } + flds.Add(fldName); + node.SetAttribute("name", fldName); + } + foreach (var df in pt.DataFields) { + if (string.IsNullOrEmpty(df.Name)) { + string name; + if (df.Function == DataFieldFunctions.None) { + name = df.Field.Name; //Name must be set or Excel will crash on rename. + } else { + name = df.Function + " of " + df.Field.Name; //Name must be set or Excel will crash on rename. + } + //Make sure name is unique + var newName = name; + var i = 2; + while (pt.DataFields.ExistsDfName(newName, df)) { + newName = name + (i++).ToString(CultureInfo.InvariantCulture); } - return 0; + df.Name = newName; + } } + } + pt.PivotTableXml.Save(pt.Part.GetStream(FileMode.Create)); + pt.CacheDefinition.CacheDefinitionXml.Save( + pt.CacheDefinition.Part.GetStream(FileMode.Create)); + } + } - #endregion - #endregion // END Worksheet Public Methods + private string GetNewName(HashSet<string> flds, string fldName) { + int ix = 2; + while (flds.Contains(fldName + ix.ToString(CultureInfo.InvariantCulture))) { + ix++; + } + return fldName + ix.ToString(CultureInfo.InvariantCulture); + } - #region Worksheet Private Methods + private static string GetTotalFunction(ExcelTableColumn col, string functionNum) { + return string.Format("SUBTOTAL({0},{1}[{2}])", functionNum, col._tbl.Name, col.Name); + } - #region Worksheet Save - internal void Save() - { - DeletePrinterSettings(); + private void CleanupMergedCells(MergeCellsCollection mergedCells) { + int i = 0; + while (i < mergedCells.List.Count) { + if (mergedCells[i] == null) { + mergedCells.List.RemoveAt(i); + } else { + i++; + } + } + } - if (_worksheetXml != null) - { + private void UpdateColBreaks(StreamWriter sw) { + StringBuilder breaks = new StringBuilder(); + int count = 0; + var cse = new CellsStoreEnumerator<object>(_values, 0, 0, 0, ExcelPackage.MaxColumns); + //foreach (ExcelColumn col in _columns) + while (cse.Next()) { + var col = cse.Value as ExcelColumn; + if (col != null && col.PageBreak) { + breaks.AppendFormat("<brk id=\"{0}\" max=\"16383\" man=\"1\" />", cse.Column); + count++; + } + } + if (count > 0) { + sw.Write("<colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</colBreaks>", count, breaks); + } + } + + private void UpdateRowBreaks(StreamWriter sw) { + StringBuilder breaks = new StringBuilder(); + int count = 0; + var cse = new CellsStoreEnumerator<object>(_values, 0, 0, ExcelPackage.MaxRows, 0); + //foreach(ExcelRow row in _rows) + while (cse.Next()) { + var row = cse.Value as RowInternal; + if (row != null && row.PageBreak) { + breaks.AppendFormat("<brk id=\"{0}\" max=\"1048575\" man=\"1\" />", cse.Row); + count++; + } + } + if (count > 0) { + sw.Write("<rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</rowBreaks>", count, breaks); + } + } - if (!(this is ExcelChartsheet)) - { - // save the header & footer (if defined) - if (_headerFooter != null) - HeaderFooter.Save(); + /// <summary> + /// Inserts the cols collection into the XML document + /// </summary> + private void UpdateColumnData(StreamWriter sw) { + //ExcelColumn prevCol = null; //commented out 11/1-12 JK + //foreach (ExcelColumn col in _columns) + //{ + // if (prevCol != null) + // { + // if(prevCol.ColumnMax != col.ColumnMin-1) + // { + // prevCol._columnMax=col.ColumnMin-1; + // } + // } + // prevCol = col; + //} + var cse = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns); + //sw.Write("<cols>"); + //foreach (ExcelColumn col in _columns) + bool first = true; + while (cse.Next()) { + if (first) { + sw.Write("<cols>"); + first = false; + } + var col = cse.Value as ExcelColumn; + ExcelStyleCollection<ExcelXfs> cellXfs = _package.Workbook.Styles.CellXfs; - var d = Dimension; - if (d == null) - { - this.DeleteAllNode("d:dimension/@ref"); - } - else - { - this.SetXmlNodeString("d:dimension/@ref", d.Address); - } - - SaveComments(); - SaveTables(); - SavePivotTables(); - } - } + sw.Write("<col min=\"{0}\" max=\"{1}\"", col.ColumnMin, col.ColumnMax); + if (col.Hidden) { + //sbXml.Append(" width=\"0\" hidden=\"1\" customWidth=\"1\""); + sw.Write(" hidden=\"1\""); + } else if (col.BestFit) { + sw.Write(" bestFit=\"1\""); + } + sw.Write( + string.Format( + CultureInfo.InvariantCulture, + " width=\"{0}\" customWidth=\"1\"", + col.Width)); + if (col.OutlineLevel > 0) { + sw.Write(" outlineLevel=\"{0}\" ", col.OutlineLevel); + if (col.Collapsed) { + if (col.Hidden) { + sw.Write(" collapsed=\"1\""); + } else { + sw.Write(" collapsed=\"1\" hidden=\"1\""); //Always hidden + } } - internal void SaveHandler(StreamWriter streamWriter) - { - //Create the nodes if they do not exist. - if (this is ExcelChartsheet) - { - streamWriter.Write(_worksheetXml.OuterXml); - } - else - { - CreateNode("d:cols"); - CreateNode("d:sheetData"); - CreateNode("d:mergeCells"); - CreateNode("d:hyperlinks"); - CreateNode("d:rowBreaks"); - CreateNode("d:colBreaks"); + } + if (col.Phonetic) { + sw.Write(" phonetic=\"1\""); + } - //StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write)); - var xml = _worksheetXml.OuterXml; - int colStart = 0, colEnd = 0; - GetBlockPos(xml, "cols", ref colStart, ref colEnd); - - streamWriter.Write(xml.Substring(0, colStart)); - var colBreaks = new List<int>(); - //if (_columns.Count > 0) - //{ - UpdateColumnData(streamWriter); - //} - - int cellStart = colEnd, cellEnd = colEnd; - GetBlockPos(xml, "sheetData", ref cellStart, ref cellEnd); - - streamWriter.Write(xml.Substring(colEnd, cellStart - colEnd)); - var rowBreaks = new List<int>(); - UpdateRowCellData(streamWriter); + var styleId = col.StyleID >= 0 ? cellXfs[col.StyleID].newID : col.StyleID; + if (styleId > 0) { + sw.Write(" style=\"{0}\"", styleId); + } + sw.Write(" />"); - int mergeStart = cellEnd, mergeEnd = cellEnd; + //if (col.PageBreak) + //{ + // colBreaks.Add(col.ColumnMin); + //} + } + if (!first) { + sw.Write("</cols>"); + } + } - GetBlockPos(xml, "mergeCells", ref mergeStart, ref mergeEnd); - streamWriter.Write(xml.Substring(cellEnd, mergeStart - cellEnd)); + /// <summary> + /// Insert row and cells into the XML document + /// </summary> + private void UpdateRowCellData(StreamWriter sw) { + ExcelStyleCollection<ExcelXfs> cellXfs = _package.Workbook.Styles.CellXfs; - CleanupMergedCells(_mergedCells); - if (_mergedCells.Count > 0) - { - UpdateMergedCells(streamWriter); - } + int row = -1; - int hyperStart = mergeEnd, hyperEnd = mergeEnd; - GetBlockPos(xml, "hyperlinks", ref hyperStart, ref hyperEnd); - streamWriter.Write(xml.Substring(mergeEnd, hyperStart - mergeEnd)); - //if (_hyperLinkCells.Count > 0) - //{ - UpdateHyperLinks(streamWriter); - // } + StringBuilder sbXml = new StringBuilder(); + var ss = _package.Workbook._sharedStrings; + var styles = _package.Workbook.Styles; + var cache = new StringBuilder(); + cache.Append("<sheetData>"); - int rowBreakStart = hyperEnd, rowBreakEnd = hyperEnd; - GetBlockPos(xml, "rowBreaks", ref rowBreakStart, ref rowBreakEnd); - streamWriter.Write(xml.Substring(hyperEnd, rowBreakStart - hyperEnd)); - //if (rowBreaks.Count > 0) - //{ - UpdateRowBreaks(streamWriter); - //} + //Set a value for cells with style and no value set. + var cseStyle = new CellsStoreEnumerator<int>( + _styles, + 0, + 0, + ExcelPackage.MaxRows, + ExcelPackage.MaxColumns); + foreach (var s in cseStyle) { + if (!_values.Exists(cseStyle.Row, cseStyle.Column)) { + _values.SetValue(cseStyle.Row, cseStyle.Column, null); + } + } - int colBreakStart = rowBreakEnd, colBreakEnd = rowBreakEnd; - GetBlockPos(xml, "colBreaks", ref colBreakStart, ref colBreakEnd); - streamWriter.Write(xml.Substring(rowBreakEnd, colBreakStart - rowBreakEnd)); - //if (colBreaks.Count > 0) - //{ - UpdateColBreaks(streamWriter); - //} - streamWriter.Write(xml.Substring(colBreakEnd, xml.Length - colBreakEnd)); - } + var cse = new CellsStoreEnumerator<object>( + _values, + 1, + 0, + ExcelPackage.MaxRows, + ExcelPackage.MaxColumns); + //foreach (IRangeID r in _cells) + while (cse.Next()) { + if (cse.Column > 0) { + int styleId = cellXfs[styles.GetStyleId(this, cse.Row, cse.Column)].newID; + //Add the row element if it's a new row + if (cse.Row != row) { + WriteRow(cache, cellXfs, row, cse.Row); + row = cse.Row; } - - /// <summary> - /// Delete the printersettings relationship and part. - /// </summary> - private void DeletePrinterSettings() - { - //Delete the relationship from the pageSetup tag - XmlAttribute attr = (XmlAttribute)WorksheetXml.SelectSingleNode("//d:pageSetup/@r:id", NameSpaceManager); - if (attr != null) - { - string relID = attr.Value; - //First delete the attribute from the XML - attr.OwnerElement.Attributes.Remove(attr); - if(Part.RelationshipExists(relID)) - { - var rel = Part.GetRelationship(relID); - Uri printerSettingsUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); - Part.DeleteRelationship(rel.Id); - - //Delete the part from the package - if(_package.Package.PartExists(printerSettingsUri)) - { - _package.Package.DeletePart(printerSettingsUri); - } - } + object v = cse.Value; + object formula = _formulas.GetValue(cse.Row, cse.Column); + if (formula is int) { + int sfId = (int)formula; + var f = _sharedFormulas[sfId]; + if (f.Address.IndexOf(':') > 0) { + if (f.StartCol == cse.Column && f.StartRow == cse.Row) { + if (f.IsArray) { + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", + cse.CellAddress, + styleId < 0 ? 0 : styleId, + f.Address, + SecurityElement.Escape(f.Formula), + GetFormulaValue(v), + GetCellType(v, true)); + } else { + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\"{6}><f ref=\"{2}\" t=\"shared\" si=\"{3}\">{4}</f>{5}</c>", + cse.CellAddress, + styleId < 0 ? 0 : styleId, + f.Address, + sfId, + SecurityElement.Escape(f.Formula), + GetFormulaValue(v), + GetCellType(v, true)); + } + } else if (f.IsArray) { + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\" />", + cse.CellAddress, + styleId < 0 ? 0 : styleId); + } else { + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\"{4}><f t=\"shared\" si=\"{2}\" />{3}</c>", + cse.CellAddress, + styleId < 0 ? 0 : styleId, + sfId, + GetFormulaValue(v), + GetCellType(v, true)); } - } - private void SaveComments() - { - if (_comments != null) - { - if (_comments.Count == 0) - { - if (_comments.Uri != null) - { - Part.DeleteRelationship(_comments.RelId); - _package.Package.DeletePart(_comments.Uri); - } - RemoveLegacyDrawingRel(VmlDrawingsComments.RelId); - } - else - { - if (_comments.Uri == null) - { - _comments.Uri=new Uri(string.Format(@"/xl/comments{0}.xml", SheetID), UriKind.Relative); - } - if(_comments.Part==null) - { - _comments.Part = _package.Package.CreatePart(_comments.Uri, "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", _package.Compression); - var rel = Part.CreateRelationship(UriHelper.GetRelativeUri(WorksheetUri, _comments.Uri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships+"/comments"); - } - _comments.CommentXml.Save(_comments.Part.GetStream(FileMode.Create)); - } + } else { + // We can also have a single cell array formula + if (f.IsArray) { + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", + cse.CellAddress, + styleId < 0 ? 0 : styleId, + string.Format("{0}:{1}", f.Address, f.Address), + SecurityElement.Escape(f.Formula), + GetFormulaValue(v), + GetCellType(v, true)); + } else { + cache.AppendFormat("<c r=\"{0}\" s=\"{1}\">", f.Address, styleId < 0 ? 0 : styleId); + cache.AppendFormat( + "<f>{0}</f>{1}</c>", + SecurityElement.Escape(f.Formula), + GetFormulaValue(v)); } - - if (_vmlDrawings != null) - { - if (_vmlDrawings.Count == 0) - { - if (_vmlDrawings.Uri != null) - { - Part.DeleteRelationship(_vmlDrawings.RelId); - _package.Package.DeletePart(_vmlDrawings.Uri); - } - } - else - { - if (_vmlDrawings.Uri == null) - { - _vmlDrawings.Uri = XmlHelper.GetNewUri(_package.Package, @"/xl/drawings/vmlDrawing{0}.vml"); - } - if (_vmlDrawings.Part == null) - { - _vmlDrawings.Part = _package.Package.CreatePart(_vmlDrawings.Uri, "application/vnd.openxmlformats-officedocument.vmlDrawing", _package.Compression); - var rel = Part.CreateRelationship(UriHelper.GetRelativeUri(WorksheetUri, _vmlDrawings.Uri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/vmlDrawing"); - SetXmlNodeString("d:legacyDrawing/@r:id", rel.Id); - _vmlDrawings.RelId = rel.Id; - } - _vmlDrawings.VmlDrawingXml.Save(_vmlDrawings.Part.GetStream()); - } + } + } else if (formula != null && formula.ToString() != "") { + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\"{2}>", + cse.CellAddress, + styleId < 0 ? 0 : styleId, + GetCellType(v, true)); + cache.AppendFormat( + "<f>{0}</f>{1}</c>", + SecurityElement.Escape(formula.ToString()), + GetFormulaValue(v)); + } else { + if (v == null && styleId > 0) { + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\" />", + cse.CellAddress, + styleId < 0 ? 0 : styleId); + } else if (v != null) { + if ((v.GetType().IsPrimitive + || v is double + || v is decimal + || v is DateTime + || v is TimeSpan)) { + //string sv = GetValueForXml(v); + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\" {2}>", + cse.CellAddress, + styleId < 0 ? 0 : styleId, + GetCellType(v)); + cache.AppendFormat("{0}</c>", GetFormulaValue(v)); + } else { + int ix; + if (!ss.ContainsKey(v.ToString())) { + ix = ss.Count; + ss.Add( + v.ToString(), + new() { + isRichText = _flags.GetFlagValue(cse.Row, cse.Column, CellFlags.RichText), + pos = ix, + }); + } else { + ix = ss[v.ToString()].pos; + } + cache.AppendFormat( + "<c r=\"{0}\" s=\"{1}\" t=\"s\">", + cse.CellAddress, + styleId < 0 ? 0 : styleId); + cache.AppendFormat("<v>{0}</v></c>", ix); } + } } - /// <summary> - /// Save all table data - /// </summary> - private void SaveTables() - { - foreach (var tbl in Tables) - { - if (tbl.ShowHeader || tbl.ShowTotal) - { - int colNum = tbl.Address._fromCol; - var colVal = new HashSet<string>(); - foreach (var col in tbl.Columns) - { - string n=col.Name.ToLower(CultureInfo.InvariantCulture); - if (tbl.ShowHeader) - { - n = tbl.WorkSheet.GetValue<string>(tbl.Address._fromRow, - tbl.Address._fromCol + col.Position); - if (string.IsNullOrEmpty(n)) - { - n = col.Name.ToLower(CultureInfo.InvariantCulture); - } - else - { - col.Name = n; - } - } - else - { - n = col.Name.ToLower(CultureInfo.InvariantCulture); - } - - if(colVal.Contains(n)) - { - throw(new InvalidDataException(string.Format("Table {0} Column {1} does not have a unique name.", tbl.Name, col.Name))); - } - colVal.Add(n); - col.Name = ConvertUtil.ExcelEncodeString(col.Name); - if (tbl.ShowHeader) - { - _values.SetValue(tbl.Address._fromRow, colNum, col.Name); - } - if (tbl.ShowTotal) - { - SetTableTotalFunction(tbl, col, colNum); - } - if (!string.IsNullOrEmpty(col.CalculatedColumnFormula)) - { - int fromRow = tbl.ShowHeader ? tbl.Address._fromRow + 1 : tbl.Address._fromRow; - int toRow = tbl.ShowTotal ? tbl.Address._toRow - 1 : tbl.Address._toRow; - for (int row = fromRow; row <= toRow; row++) - { - //Cell(row, colNum).Formula = col.CalculatedColumnFormula; - SetFormula(row, colNum, col.CalculatedColumnFormula); - } - } - colNum++; - } - } - if (tbl.Part == null) - { - tbl.TableUri = GetNewUri(_package.Package, @"/xl/tables/table{0}.xml", tbl.Id); - tbl.Part = _package.Package.CreatePart(tbl.TableUri, "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", Workbook._package.Compression); - var stream = tbl.Part.GetStream(FileMode.Create); - tbl.TableXml.Save(stream); - var rel = Part.CreateRelationship(UriHelper.GetRelativeUri(WorksheetUri, tbl.TableUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/table"); - tbl.RelationshipID = rel.Id; + ////Update hyperlinks. + //if (cell.Hyperlink != null) + //{ + // _hyperLinkCells.Add(cell.CellID); + //} + } else //ExcelRow + { + //int newRow=((ExcelRow)cse.Value).Row; + WriteRow(cache, cellXfs, row, cse.Row); + row = cse.Row; + } + if (cache.Length > 0x600000) { + sw.Write(cache.ToString()); + cache = new(); + } + } - CreateNode("d:tableParts"); - XmlNode tbls = TopNode.SelectSingleNode("d:tableParts",NameSpaceManager); + if (row != -1) { + cache.Append("</row>"); + } + cache.Append("</sheetData>"); + sw.Write(cache.ToString()); + sw.Flush(); + } + + private object GetFormulaValue(object v) { + //if (_package.Workbook._isCalculated) + //{ + if (v != null && v.ToString() != "") { + return "<v>" + SecurityElement.Escape(GetValueForXml(v)) + "</v>"; //Fixes issue 15071 + } + return ""; + } - var tblNode = tbls.OwnerDocument.CreateElement("tablePart",ExcelPackage.schemaMain); - tbls.AppendChild(tblNode); - tblNode.SetAttribute("id",ExcelPackage.schemaRelationships, rel.Id); - } - else - { - var stream = tbl.Part.GetStream(FileMode.Create); - tbl.TableXml.Save(stream); - } - } - } + private string GetCellType(object v, bool allowStr = false) { + if (v is bool) { + return " t=\"b\""; + } + if ((v is double && double.IsInfinity((double)v)) || v is ExcelErrorValue) { + return " t=\"e\""; + } + if (allowStr + && v != null + && !(v.GetType().IsPrimitive + || v is double + || v is decimal + || v is DateTime + || v is TimeSpan)) { + return " t=\"str\""; + } + return ""; + } - internal void SetTableTotalFunction(ExcelTable tbl, ExcelTableColumn col, int colNum=-1) - { - if (tbl.ShowTotal == false) return; - if (colNum == -1) - { - for (int i = 0; i < tbl.Columns.Count; i++) - { - if (tbl.Columns[i].Name == col.Name) - { - colNum = tbl.Address._fromCol + i; - } - } - } - if (col.TotalsRowFunction == RowFunctions.Custom) - { - SetFormula(tbl.Address._toRow, colNum, col.TotalsRowFormula); - } - else if (col.TotalsRowFunction != RowFunctions.None) - { - switch (col.TotalsRowFunction) - { - case RowFunctions.Average: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "101")); - break; - case RowFunctions.Count: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "102")); - break; - case RowFunctions.CountNums: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "103")); - break; - case RowFunctions.Max: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "104")); - break; - case RowFunctions.Min: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "105")); - break; - case RowFunctions.StdDev: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "107")); - break; - case RowFunctions.Var: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "110")); - break; - case RowFunctions.Sum: - SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "109")); - break; - default: - throw (new Exception("Unknown RowFunction enum")); - } - } - else - { - _values.SetValue(tbl.Address._toRow, colNum, col.TotalsRowLabel); + private string GetValueForXml(object v) { + string s; + try { + if (v is DateTime) { + double sdv = ((DateTime)v).ToOADate(); - } + if (Workbook.Date1904) { + sdv -= ExcelWorkbook._date1904Offset; } - internal void SetFormula(int row, int col, object value) - { - _formulas.SetValue(row, col, value); - if (!_values.Exists(row, col)) _values.SetValue(row, col, null); + s = sdv.ToString(CultureInfo.InvariantCulture); + } else if (v is TimeSpan) { + s = new DateTime(((TimeSpan)v).Ticks).ToOADate().ToString(CultureInfo.InvariantCulture); + ; + } else if (v.GetType().IsPrimitive || v is double || v is decimal) { + if (v is double && double.IsNaN((double)v)) { + s = ""; + } else if (v is double && double.IsInfinity((double)v)) { + s = "#NUM!"; + } else { + s = Convert + .ToDouble(v, CultureInfo.InvariantCulture) + .ToString("R15", CultureInfo.InvariantCulture); } - internal void SetStyle(int row, int col, int value) - { - _styles.SetValue(row, col, value); - if(!_values.Exists(row,col)) _values.SetValue(row, col, null); + } else { + s = v.ToString(); + } + } catch { + s = "0"; + } + return s; + } + + private void WriteRow( + StringBuilder cache, + ExcelStyleCollection<ExcelXfs> cellXfs, + int prevRow, + int row) { + if (prevRow != -1) { + cache.Append("</row>"); + } + //ulong rowID = ExcelRow.GetRowID(SheetID, row); + cache.AppendFormat("<row r=\"{0}\" ", row); + RowInternal currRow = _values.GetValue(row, 0) as RowInternal; + if (currRow != null) { + if (currRow.Hidden) { + cache.Append("ht=\"0\" hidden=\"1\" "); + } else if (currRow.Height != DefaultRowHeight && currRow.Height >= 0) { + cache.AppendFormat(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height); + if (currRow.CustomHeight) { + cache.Append("customHeight=\"1\" "); } - - private void SavePivotTables() - { - foreach (var pt in PivotTables) - { - if (pt.DataFields.Count > 1) - { - XmlElement parentNode; - if(pt.DataOnRows==true) - { - parentNode = pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) as XmlElement; - if (parentNode == null) - { - pt.CreateNode("d:rowFields"); - parentNode = pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) as XmlElement; - } - } - else - { - parentNode = pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) as XmlElement; - if (parentNode == null) - { - pt.CreateNode("d:colFields"); - parentNode = pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) as XmlElement; - } - } + } - if (parentNode.SelectSingleNode("d:field[@ x= \"-2\"]", pt.NameSpaceManager) == null) - { - XmlElement fieldNode = pt.PivotTableXml.CreateElement("field", ExcelPackage.schemaMain); - fieldNode.SetAttribute("x", "-2"); - parentNode.AppendChild(fieldNode); - } - } - var ws = Workbook.Worksheets[pt.CacheDefinition.SourceRange.WorkSheet]; - var t = ws.Tables.GetFromRange(pt.CacheDefinition.SourceRange); - var fields = - pt.CacheDefinition.CacheDefinitionXml.SelectNodes( - "d:pivotCacheDefinition/d:cacheFields/d:cacheField", NameSpaceManager); - int ix = 0; - if (fields != null) - { - var flds = new HashSet<string>(); - foreach (XmlElement node in fields) - { - if (ix >= pt.CacheDefinition.SourceRange.Columns) break; - var fldName = node.GetAttribute("name"); //Fixes issue 15295 dup name error - if (string.IsNullOrEmpty(fldName)) - { - fldName = (t == null - ? pt.CacheDefinition.SourceRange.Offset(0, ix++, 1, 1).Value.ToString() - : t.Columns[ix++].Name); - } - if (flds.Contains(fldName)) - { - fldName = GetNewName(flds, fldName); - } - flds.Add(fldName); - node.SetAttribute("name", fldName); - } - foreach (var df in pt.DataFields) - { - if (string.IsNullOrEmpty(df.Name)) - { - string name; - if (df.Function == DataFieldFunctions.None) - { - name = df.Field.Name; //Name must be set or Excel will crash on rename. - } - else - { - name = df.Function.ToString() + " of " + df.Field.Name; //Name must be set or Excel will crash on rename. - } - //Make sure name is unique - var newName = name; - var i = 2; - while (pt.DataFields.ExistsDfName(newName, df)) - { - newName = name + (i++).ToString(CultureInfo.InvariantCulture); - } - df.Name = newName; - } - } - } - pt.PivotTableXml.Save(pt.Part.GetStream(FileMode.Create)); - pt.CacheDefinition.CacheDefinitionXml.Save(pt.CacheDefinition.Part.GetStream(FileMode.Create)); - } + if (currRow.OutlineLevel > 0) { + cache.AppendFormat("outlineLevel =\"{0}\" ", currRow.OutlineLevel); + if (currRow.Collapsed) { + if (currRow.Hidden) { + cache.Append(" collapsed=\"1\" "); + } else { + cache.Append(" collapsed=\"1\" hidden=\"1\" "); //Always hidden + } } + } + if (currRow.Phonetic) { + cache.Append("ph=\"1\" "); + } + } + var s = _styles.GetValue(row, 0); + if (s > 0) { + cache.AppendFormat("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID); + } + cache.Append(">"); + } - private string GetNewName(HashSet<string> flds, string fldName) - { - int ix = 2; - while (flds.Contains(fldName + ix.ToString(CultureInfo.InvariantCulture))) - { - ix++; - } - return fldName + ix.ToString(CultureInfo.InvariantCulture); + private void WriteRow( + StreamWriter sw, + ExcelStyleCollection<ExcelXfs> cellXfs, + int prevRow, + int row) { + if (prevRow != -1) { + sw.Write("</row>"); + } + //ulong rowID = ExcelRow.GetRowID(SheetID, row); + sw.Write("<row r=\"{0}\" ", row); + RowInternal currRow = _values.GetValue(row, 0) as RowInternal; + if (currRow != null) { + if (currRow.Hidden) { + sw.Write("ht=\"0\" hidden=\"1\" "); + } else if (currRow.Height != DefaultRowHeight) { + sw.Write(string.Format(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height)); + if (currRow.CustomHeight) { + sw.Write("customHeight=\"1\" "); } + } - private static string GetTotalFunction(ExcelTableColumn col,string FunctionNum) - { - return string.Format("SUBTOTAL({0},{1}[{2}])", FunctionNum, col._tbl.Name, col.Name); + if (currRow.OutlineLevel > 0) { + sw.Write("outlineLevel =\"{0}\" ", currRow.OutlineLevel); + if (currRow.Collapsed) { + if (currRow.Hidden) { + sw.Write(" collapsed=\"1\" "); + } else { + sw.Write(" collapsed=\"1\" hidden=\"1\" "); //Always hidden + } } + } + if (currRow.Phonetic) { + sw.Write("ph=\"1\" "); + } + } + var s = _styles.GetValue(row, 0); + if (s > 0) { + sw.Write("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID); + } + sw.Write(">"); + } - private void CleanupMergedCells(MergeCellsCollection _mergedCells) - { - int i=0; - while (i < _mergedCells.List.Count) - { - if (_mergedCells[i] == null) - { - _mergedCells.List.RemoveAt(i); - } - else - { - i++; - } - } + /// <summary> + /// Update xml with hyperlinks + /// </summary> + /// <param name="sw">The stream</param> + private void UpdateHyperLinks(StreamWriter sw) { + Dictionary<string, string> hyps = new Dictionary<string, string>(); + var cse = new CellsStoreEnumerator<Uri>(_hyperLinks); + bool first = true; + //foreach (ulong cell in _hyperLinks) + while (cse.Next()) { + if (first) { + sw.Write("<hyperlinks>"); + first = false; + } + //int row, col; + var uri = _hyperLinks.GetValue(cse.Row, cse.Column); + //ExcelCell cell = _cells[cellId] as ExcelCell; + if (uri is ExcelHyperLink + && !string.IsNullOrEmpty((uri as ExcelHyperLink).ReferenceAddress)) { + ExcelHyperLink hl = uri as ExcelHyperLink; + sw.Write( + "<hyperlink ref=\"{0}\" location=\"{1}\" {2}{3}/>", + Cells[cse.Row, cse.Column, cse.Row + hl.RowSpann, cse.Column + hl.ColSpann].Address, + ExcelCellBase.GetFullAddress( + SecurityElement.Escape(Name), + SecurityElement.Escape(hl.ReferenceAddress)), + string.IsNullOrEmpty(hl.Display) + ? "" + : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ", + string.IsNullOrEmpty(hl.ToolTip) + ? "" + : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" "); + } else if (uri != null) { + string id; + Uri hyp; + if (uri is ExcelHyperLink) { + hyp = ((ExcelHyperLink)uri).OriginalUri; + } else { + hyp = uri; } - private void UpdateColBreaks(StreamWriter sw) - { - StringBuilder breaks = new StringBuilder(); - int count = 0; - var cse = new CellsStoreEnumerator<object>(_values, 0, 0, 0, ExcelPackage.MaxColumns); - //foreach (ExcelColumn col in _columns) - while(cse.Next()) - { - var col=cse.Value as ExcelColumn; - if (col != null && col.PageBreak) - { - breaks.AppendFormat("<brk id=\"{0}\" max=\"16383\" man=\"1\" />", cse.Column); - count++; - } - } - if (count > 0) - { - sw.Write(string.Format("<colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</colBreaks>", count, breaks.ToString())); - } + if (hyps.ContainsKey(hyp.OriginalString)) { + id = hyps[hyp.OriginalString]; + } else { + var relationship = Part.CreateRelationship( + hyp, + TargetMode.External, + ExcelPackage._schemaHyperlink); + if (uri is ExcelHyperLink) { + ExcelHyperLink hl = uri as ExcelHyperLink; + sw.Write( + "<hyperlink ref=\"{0}\" {2}{3}r:id=\"{1}\" />", + ExcelCellBase.GetAddress(cse.Row, cse.Column), + relationship.Id, + string.IsNullOrEmpty(hl.Display) + ? "" + : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ", + string.IsNullOrEmpty(hl.ToolTip) + ? "" + : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" "); + } else { + sw.Write( + "<hyperlink ref=\"{0}\" r:id=\"{1}\" />", + ExcelCellBase.GetAddress(cse.Row, cse.Column), + relationship.Id); + } + id = relationship.Id; } + //cell.HyperLinkRId = id; + } + } + if (!first) { + sw.Write("</hyperlinks>"); + } + } - private void UpdateRowBreaks(StreamWriter sw) - { - StringBuilder breaks=new StringBuilder(); - int count = 0; - var cse = new CellsStoreEnumerator<object>(_values, 0, 0, ExcelPackage.MaxRows, 0); - //foreach(ExcelRow row in _rows) - while(cse.Next()) - { - var row=cse.Value as RowInternal; - if (row != null && row.PageBreak) - { - breaks.AppendFormat("<brk id=\"{0}\" max=\"1048575\" man=\"1\" />", cse.Row); - count++; - } - } - if (count>0) - { - sw.Write(string.Format("<rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</rowBreaks>", count, breaks.ToString())); - } - } - /// <summary> - /// Inserts the cols collection into the XML document - /// </summary> - private void UpdateColumnData(StreamWriter sw) - { - //ExcelColumn prevCol = null; //commented out 11/1-12 JK - //foreach (ExcelColumn col in _columns) - //{ - // if (prevCol != null) - // { - // if(prevCol.ColumnMax != col.ColumnMin-1) - // { - // prevCol._columnMax=col.ColumnMin-1; - // } - // } - // prevCol = col; - //} - var cse = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns); - //sw.Write("<cols>"); - //foreach (ExcelColumn col in _columns) - bool first = true; - while(cse.Next()) - { - if (first) - { - sw.Write("<cols>"); - first = false; - } - var col = cse.Value as ExcelColumn; - ExcelStyleCollection<ExcelXfs> cellXfs = _package.Workbook.Styles.CellXfs; + /// <summary> + /// Create the hyperlinks node in the XML + /// </summary> + /// <returns></returns> + private XmlNode CreateHyperLinkCollection() { + XmlElement hl = _worksheetXml.CreateElement("hyperlinks", ExcelPackage._schemaMain); + XmlNode prevNode = _worksheetXml.SelectSingleNode( + "//d:conditionalFormatting", + NameSpaceManager); + if (prevNode == null) { + prevNode = _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager); + if (prevNode == null) { + prevNode = _worksheetXml.SelectSingleNode("//d:sheetData", NameSpaceManager); + } + } + return _worksheetXml.DocumentElement.InsertAfter(hl, prevNode); + } - sw.Write("<col min=\"{0}\" max=\"{1}\"", col.ColumnMin, col.ColumnMax); - if (col.Hidden == true) - { - //sbXml.Append(" width=\"0\" hidden=\"1\" customWidth=\"1\""); - sw.Write(" hidden=\"1\""); - } - else if (col.BestFit) - { - sw.Write(" bestFit=\"1\""); - } - sw.Write(string.Format(CultureInfo.InvariantCulture, " width=\"{0}\" customWidth=\"1\"", col.Width)); - if (col.OutlineLevel > 0) - { - sw.Write(" outlineLevel=\"{0}\" ", col.OutlineLevel); - if (col.Collapsed) - { - if (col.Hidden) - { - sw.Write(" collapsed=\"1\""); - } - else - { - sw.Write(" collapsed=\"1\" hidden=\"1\""); //Always hidden - } - } - } - if (col.Phonetic) - { - sw.Write(" phonetic=\"1\""); - } + /// <summary> + /// Dimension address for the worksheet. + /// Top left cell to Bottom right. + /// If the worksheet has no cells, null is returned + /// </summary> + public ExcelAddressBase Dimension { + get { + CheckSheetType(); + int fromRow, + fromCol, + toRow, + toCol; + if (_values.GetDimension(out fromRow, out fromCol, out toRow, out toCol)) { + var addr = new ExcelAddressBase(fromRow, fromCol, toRow, toCol); + addr._ws = Name; + return addr; + } + return null; + } + } + + private ExcelSheetProtection _protection; + + /// <summary> + /// Access to sheet protection properties + /// </summary> + public ExcelSheetProtection Protection { + get { + if (_protection == null) { + _protection = new(NameSpaceManager, TopNode, this); + } + return _protection; + } + } - var styleID = col.StyleID >= 0 ? cellXfs[col.StyleID].newID : col.StyleID; - if (styleID > 0) - { - sw.Write(" style=\"{0}\"", styleID); - } - sw.Write(" />"); + private ExcelProtectedRangeCollection _protectedRanges; - //if (col.PageBreak) - //{ - // colBreaks.Add(col.ColumnMin); - //} - } - if (!first) - { - sw.Write("</cols>"); - } - } - /// <summary> - /// Insert row and cells into the XML document - /// </summary> - private void UpdateRowCellData(StreamWriter sw) - { - ExcelStyleCollection<ExcelXfs> cellXfs = _package.Workbook.Styles.CellXfs; - - int row = -1; + public ExcelProtectedRangeCollection ProtectedRanges { + get { + if (_protectedRanges == null) { + _protectedRanges = new(NameSpaceManager, TopNode, this); + } + return _protectedRanges; + } + } - StringBuilder sbXml = new StringBuilder(); - var ss = _package.Workbook._sharedStrings; - var styles = _package.Workbook.Styles; - var cache = new StringBuilder(); - cache.Append("<sheetData>"); - - //Set a value for cells with style and no value set. - var cseStyle = new CellsStoreEnumerator<int>(_styles, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - foreach (var s in cseStyle) - { - if(!_values.Exists(cseStyle.Row, cseStyle.Column)) - { - _values.SetValue(cseStyle.Row, cseStyle.Column, null); - } - } + private ExcelTableCollection _tables; - var cse = new CellsStoreEnumerator<object>(_values, 1, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns); - //foreach (IRangeID r in _cells) - while(cse.Next()) - { - if (cse.Column>0) - { - int styleID = cellXfs[styles.GetStyleId(this, cse.Row, cse.Column)].newID; - //Add the row element if it's a new row - if (cse.Row != row) - { - WriteRow(cache, cellXfs, row, cse.Row); - row = cse.Row; - } - object v = cse.Value; - object formula = _formulas.GetValue(cse.Row, cse.Column); - if (formula is int) - { - int sfId = (int)formula; - var f = _sharedFormulas[(int)sfId]; - if (f.Address.IndexOf(':') > 0) - { - if (f.StartCol == cse.Column && f.StartRow == cse.Row) - { - if (f.IsArray) - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, SecurityElement.Escape(f.Formula), GetFormulaValue(v), GetCellType(v,true)); - } - else - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{6}><f ref=\"{2}\" t=\"shared\" si=\"{3}\">{4}</f>{5}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, sfId, SecurityElement.Escape(f.Formula), GetFormulaValue(v), GetCellType(v,true)); - } + /// <summary> + /// Tables defined in the worksheet. + /// </summary> + public ExcelTableCollection Tables { + get { + CheckSheetType(); + if (Workbook._nextTableID == int.MinValue) { + Workbook.ReadAllTables(); + } + if (_tables == null) { + _tables = new(this); + } + return _tables; + } + } - } - else if (f.IsArray) - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" />", cse.CellAddress, styleID < 0 ? 0 : styleID); - } - else - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{4}><f t=\"shared\" si=\"{2}\" />{3}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, sfId, GetFormulaValue(v), GetCellType(v,true)); - } - } - else - { - // We can also have a single cell array formula - if(f.IsArray) - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, string.Format("{0}:{1}", f.Address, f.Address), SecurityElement.Escape(f.Formula), GetFormulaValue(v), GetCellType(v,true)); - } - else - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\">", f.Address, styleID < 0 ? 0 : styleID); - cache.AppendFormat("<f>{0}</f>{1}</c>", SecurityElement.Escape(f.Formula), GetFormulaValue(v)); - } - } - } - else if (formula!=null && formula.ToString()!="") - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{2}>", cse.CellAddress, styleID < 0 ? 0 : styleID, GetCellType(v,true)); - cache.AppendFormat("<f>{0}</f>{1}</c>", SecurityElement.Escape(formula.ToString()), GetFormulaValue(v)); - } - else - { - if (v == null && styleID > 0) - { - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" />", cse.CellAddress, styleID < 0 ? 0 : styleID); - } - else if(v != null) - { - if ((v.GetType().IsPrimitive || v is double || v is decimal || v is DateTime || v is TimeSpan)) - { - //string sv = GetValueForXml(v); - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" {2}>", cse.CellAddress, styleID < 0 ? 0 : styleID, GetCellType(v)); - cache.AppendFormat("{0}</c>", GetFormulaValue(v)); - } - else - { - int ix; - if (!ss.ContainsKey(v.ToString())) - { - ix = ss.Count; - ss.Add(v.ToString(), new ExcelWorkbook.SharedStringItem() { isRichText = _flags.GetFlagValue(cse.Row,cse.Column,CellFlags.RichText), pos = ix }); - } - else - { - ix = ss[v.ToString()].pos; - } - cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" t=\"s\">", cse.CellAddress, styleID < 0 ? 0 : styleID); - cache.AppendFormat("<v>{0}</v></c>", ix); - } - } - } - ////Update hyperlinks. - //if (cell.Hyperlink != null) - //{ - // _hyperLinkCells.Add(cell.CellID); - //} - } - else //ExcelRow - { - //int newRow=((ExcelRow)cse.Value).Row; - WriteRow(cache, cellXfs, row, cse.Row); - row = cse.Row; - } - if (cache.Length > 0x600000) - { - sw.Write(cache.ToString()); - cache = new StringBuilder(); - } - } + private ExcelPivotTableCollection _pivotTables; - if (row != -1) cache.Append("</row>"); - cache.Append("</sheetData>"); - sw.Write(cache.ToString()); - sw.Flush(); + /// <summary> + /// Pivottables defined in the worksheet. + /// </summary> + public ExcelPivotTableCollection PivotTables { + get { + CheckSheetType(); + if (_pivotTables == null) { + if (Workbook._nextPivotTableID == int.MinValue) { + Workbook.ReadAllTables(); } + _pivotTables = new(this); + } + return _pivotTables; + } + } - private object GetFormulaValue(object v) - { - //if (_package.Workbook._isCalculated) - //{ - if (v != null && v.ToString()!="") - { - return "<v>" + SecurityElement.Escape(GetValueForXml(v)) + "</v>"; //Fixes issue 15071 - } - else - { - return ""; - } - } + private ExcelConditionalFormattingCollection _conditionalFormatting; - private string GetCellType(object v, bool allowStr=false) - { - if (v is bool) - { - return " t=\"b\""; - } - else if ((v is double && double.IsInfinity((double)v)) || v is ExcelErrorValue) - { - return " t=\"e\""; - } - else if(allowStr && v!=null && !(v.GetType().IsPrimitive || v is double || v is decimal || v is DateTime || v is TimeSpan)) - { - return " t=\"str\""; - } - else - { - return ""; - } - } + /// <summary> + /// ConditionalFormatting defined in the worksheet. Use the Add methods to create ConditionalFormatting and add them to the worksheet. Then + /// set the properties on the instance returned. + /// </summary> + /// <seealso cref="ExcelConditionalFormattingCollection"/> + public ExcelConditionalFormattingCollection ConditionalFormatting { + get { + CheckSheetType(); + if (_conditionalFormatting == null) { + _conditionalFormatting = new(this); + } + return _conditionalFormatting; + } + } - private string GetValueForXml(object v) - { - string s; - try - { - if (v is DateTime) - { - double sdv = ((DateTime)v).ToOADate(); + private ExcelDataValidationCollection _dataValidation; - if (Workbook.Date1904) - { - sdv -= ExcelWorkbook.date1904Offset; - } + /// <summary> + /// DataValidation defined in the worksheet. Use the Add methods to create DataValidations and add them to the worksheet. Then + /// set the properties on the instance returned. + /// </summary> + /// <seealso cref="ExcelDataValidationCollection"/> + public ExcelDataValidationCollection DataValidations { + get { + CheckSheetType(); + if (_dataValidation == null) { + _dataValidation = new(this); + } + return _dataValidation; + } + } - s = sdv.ToString(CultureInfo.InvariantCulture); - } - else if (v is TimeSpan) - { - s = new DateTime(((TimeSpan)v).Ticks).ToOADate().ToString(CultureInfo.InvariantCulture); ; - } - else if(v.GetType().IsPrimitive || v is double || v is decimal) - { - if (v is double && double.IsNaN((double)v)) - { - s = ""; - } - else if (v is double && double.IsInfinity((double)v)) - { - s = "#NUM!"; - } - else - { - s = Convert.ToDouble(v, CultureInfo.InvariantCulture).ToString("R15", CultureInfo.InvariantCulture); - } - } - else - { - s = v.ToString(); - } - } + /// <summary> + /// Returns the style ID given a style name. + /// The style ID will be created if not found, but only if the style name exists! + /// </summary> + /// <param name="styleName"></param> + /// <returns></returns> + internal int GetStyleId(string styleName) { + ExcelNamedStyleXml namedStyle = null; + Workbook.Styles.NamedStyles.FindById(styleName, ref namedStyle); + if (namedStyle.XfId == int.MinValue) { + namedStyle.XfId = Workbook.Styles.CellXfs.FindIndexById(namedStyle.Style.Id); + } + return namedStyle.XfId; + } - catch - { - s = "0"; - } - return s; - } - private void WriteRow(StringBuilder cache, ExcelStyleCollection<ExcelXfs> cellXfs, int prevRow, int row) - { - if (prevRow != -1) cache.Append("</row>"); - //ulong rowID = ExcelRow.GetRowID(SheetID, row); - cache.AppendFormat("<row r=\"{0}\" ", row); - RowInternal currRow = _values.GetValue(row, 0) as RowInternal; - if (currRow != null) - { + /// <summary> + /// The workbook object + /// </summary> + public ExcelWorkbook Workbook => _package.Workbook; - if (currRow.Hidden == true) - { - cache.Append("ht=\"0\" hidden=\"1\" "); - } - else if (currRow.Height != DefaultRowHeight && currRow.Height>=0) - { - cache.AppendFormat(string.Format(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height)); - if (currRow.CustomHeight) - { - cache.Append("customHeight=\"1\" "); - } - } + /// <summary> + /// Get the next ID from a shared formula or an Array formula + /// Sharedforumlas will have an id from 0-x. Array formula ids start from 0x4000001-. + /// </summary> + /// <param name="isArray">If the formula is an array formula</param> + /// <returns></returns> + internal int GetMaxShareFunctionIndex(bool isArray) { + int i = _sharedFormulas.Count + 1; + if (isArray) { + i |= 0x40000000; + } - if (currRow.OutlineLevel > 0) - { - cache.AppendFormat("outlineLevel =\"{0}\" ", currRow.OutlineLevel); - if (currRow.Collapsed) - { - if (currRow.Hidden) - { - cache.Append(" collapsed=\"1\" "); - } - else - { - cache.Append(" collapsed=\"1\" hidden=\"1\" "); //Always hidden - } - } - } - if (currRow.Phonetic) - { - cache.Append("ph=\"1\" "); - } - } - var s = _styles.GetValue(row, 0); - if (s > 0) - { - cache.AppendFormat("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID); - } - cache.Append(">"); - } - private void WriteRow(StreamWriter sw, ExcelStyleCollection<ExcelXfs> cellXfs, int prevRow, int row) - { - if (prevRow != -1) sw.Write("</row>"); - //ulong rowID = ExcelRow.GetRowID(SheetID, row); - sw.Write("<row r=\"{0}\" ", row); - RowInternal currRow = _values.GetValue(row, 0) as RowInternal; - if (currRow!=null) - { - - if (currRow.Hidden == true) - { - sw.Write("ht=\"0\" hidden=\"1\" "); - } - else if (currRow.Height != DefaultRowHeight) - { - sw.Write(string.Format(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height)); - if (currRow.CustomHeight) - { - sw.Write("customHeight=\"1\" "); - } - } + while (_sharedFormulas.ContainsKey(i)) { + i++; + } + return i; + } - if (currRow.OutlineLevel > 0) - { - sw.Write("outlineLevel =\"{0}\" ", currRow.OutlineLevel); - if (currRow.Collapsed) - { - if (currRow.Hidden) - { - sw.Write(" collapsed=\"1\" "); - } - else - { - sw.Write(" collapsed=\"1\" hidden=\"1\" "); //Always hidden - } - } - } - if (currRow.Phonetic) - { - sw.Write("ph=\"1\" "); - } - } - var s = _styles.GetValue(row, 0); - if (s > 0) - { - sw.Write("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID); - } - sw.Write(">"); - } + internal void SetHfLegacyDrawingRel(string relId) { + SetXmlNodeString("d:legacyDrawingHF/@r:id", relId); + } - /// <summary> - /// Update xml with hyperlinks - /// </summary> - /// <param name="sw">The stream</param> - private void UpdateHyperLinks(StreamWriter sw) - { - Dictionary<string, string> hyps = new Dictionary<string, string>(); - var cse = new CellsStoreEnumerator<Uri>(_hyperLinks); - bool first = true; - //foreach (ulong cell in _hyperLinks) - while(cse.Next()) - { - if (first) - { - sw.Write("<hyperlinks>"); - first = false; - } - //int row, col; - var uri = _hyperLinks.GetValue(cse.Row, cse.Column); - //ExcelCell cell = _cells[cellId] as ExcelCell; - if (uri is ExcelHyperLink && !string.IsNullOrEmpty((uri as ExcelHyperLink).ReferenceAddress)) - { - ExcelHyperLink hl = uri as ExcelHyperLink; - sw.Write("<hyperlink ref=\"{0}\" location=\"{1}\" {2}{3}/>", - Cells[cse.Row, cse.Column, cse.Row + hl.RowSpann, cse.Column + hl.ColSpann].Address, - ExcelCellBase.GetFullAddress(SecurityElement.Escape(Name), SecurityElement.Escape(hl.ReferenceAddress)), - string.IsNullOrEmpty(hl.Display) ? "" : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ", - string.IsNullOrEmpty(hl.ToolTip) ? "" : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" "); - } - else if( uri!=null) - { - string id; - Uri hyp; - if (uri is ExcelHyperLink) - { - hyp = ((ExcelHyperLink)uri).OriginalUri; - } - else - { - hyp = uri; - } - if (hyps.ContainsKey(hyp.OriginalString)) - { - id = hyps[hyp.OriginalString]; - } - else - { - var relationship = Part.CreateRelationship(hyp, Packaging.TargetMode.External, ExcelPackage.schemaHyperlink); - if (uri is ExcelHyperLink) - { - ExcelHyperLink hl = uri as ExcelHyperLink; - sw.Write("<hyperlink ref=\"{0}\" {2}{3}r:id=\"{1}\" />", ExcelCellBase.GetAddress(cse.Row, cse.Column), relationship.Id, - string.IsNullOrEmpty(hl.Display) ? "" : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ", - string.IsNullOrEmpty(hl.ToolTip) ? "" : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" "); - } - else - { - sw.Write("<hyperlink ref=\"{0}\" r:id=\"{1}\" />", ExcelCellBase.GetAddress(cse.Row, cse.Column), relationship.Id); - } - id = relationship.Id; - } - //cell.HyperLinkRId = id; - } - } - if (!first) - { - sw.Write("</hyperlinks>"); - } - } - /// <summary> - /// Create the hyperlinks node in the XML - /// </summary> - /// <returns></returns> - private XmlNode CreateHyperLinkCollection() - { - XmlElement hl=_worksheetXml.CreateElement("hyperlinks",ExcelPackage.schemaMain); - XmlNode prevNode = _worksheetXml.SelectSingleNode("//d:conditionalFormatting", NameSpaceManager); - if (prevNode == null) - { - prevNode = _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager); - if (prevNode == null) - { - prevNode = _worksheetXml.SelectSingleNode("//d:sheetData", NameSpaceManager); - } - } - return _worksheetXml.DocumentElement.InsertAfter(hl, prevNode); - } - /// <summary> - /// Dimension address for the worksheet. - /// Top left cell to Bottom right. - /// If the worksheet has no cells, null is returned - /// </summary> - public ExcelAddressBase Dimension - { - get - { - CheckSheetType(); - int fromRow, fromCol, toRow, toCol; - if (_values.GetDimension(out fromRow, out fromCol, out toRow, out toCol)) - { - var addr = new ExcelAddressBase(fromRow, fromCol, toRow, toCol); - addr._ws = Name; - return addr; - } - else - { - return null; - } - } - } - ExcelSheetProtection _protection=null; - /// <summary> - /// Access to sheet protection properties - /// </summary> - public ExcelSheetProtection Protection - { - get - { - if (_protection == null) - { - _protection = new ExcelSheetProtection(NameSpaceManager, TopNode, this); - } - return _protection; - } - } + internal void RemoveLegacyDrawingRel(string relId) { + var n = WorksheetXml.DocumentElement.SelectSingleNode( + string.Format("d:legacyDrawing[@r:id=\"{0}\"]", relId), + NameSpaceManager); + if (n != null) { + n.ParentNode.RemoveChild(n); + } + } - private ExcelProtectedRangeCollection _protectedRanges; - public ExcelProtectedRangeCollection ProtectedRanges - { - get - { - if (_protectedRanges == null) - _protectedRanges = new ExcelProtectedRangeCollection(NameSpaceManager, TopNode, this); - return _protectedRanges; - } - } - - ExcelTableCollection _tables = null; - /// <summary> - /// Tables defined in the worksheet. - /// </summary> - public ExcelTableCollection Tables - { - get - { - CheckSheetType(); - if (Workbook._nextTableID == int.MinValue) Workbook.ReadAllTables(); - if (_tables == null) - { - _tables = new ExcelTableCollection(this); - } - return _tables; - } - } - ExcelPivotTableCollection _pivotTables = null; - /// <summary> - /// Pivottables defined in the worksheet. - /// </summary> - public ExcelPivotTableCollection PivotTables - { - get - { - CheckSheetType(); - if (_pivotTables == null) - { - if (Workbook._nextPivotTableID == int.MinValue) Workbook.ReadAllTables(); - _pivotTables = new ExcelPivotTableCollection(this); - } - return _pivotTables; - } - } - private ExcelConditionalFormattingCollection _conditionalFormatting = null; - /// <summary> - /// ConditionalFormatting defined in the worksheet. Use the Add methods to create ConditionalFormatting and add them to the worksheet. Then - /// set the properties on the instance returned. - /// </summary> - /// <seealso cref="ExcelConditionalFormattingCollection"/> - public ExcelConditionalFormattingCollection ConditionalFormatting - { - get - { - CheckSheetType(); - if (_conditionalFormatting == null) - { - _conditionalFormatting = new ExcelConditionalFormattingCollection(this); - } - return _conditionalFormatting; - } - } - private ExcelDataValidationCollection _dataValidation = null; - /// <summary> - /// DataValidation defined in the worksheet. Use the Add methods to create DataValidations and add them to the worksheet. Then - /// set the properties on the instance returned. - /// </summary> - /// <seealso cref="ExcelDataValidationCollection"/> - public ExcelDataValidationCollection DataValidations - { - get - { - CheckSheetType(); - if (_dataValidation == null) - { - _dataValidation = new ExcelDataValidationCollection(this); - } - return _dataValidation; - } - } + internal void UpdateCellsWithDate1904Setting() { + var cse = new CellsStoreEnumerator<object>(_values); + var offset = Workbook.Date1904 ? -ExcelWorkbook._date1904Offset : ExcelWorkbook._date1904Offset; + while (cse.MoveNext()) { + if (cse.Value is DateTime) { + try { + double sdv = ((DateTime)cse.Value).ToOADate(); + sdv += offset; - /// <summary> - /// Returns the style ID given a style name. - /// The style ID will be created if not found, but only if the style name exists! - /// </summary> - /// <param name="StyleName"></param> - /// <returns></returns> - internal int GetStyleID(string StyleName) - { - ExcelNamedStyleXml namedStyle=null; - Workbook.Styles.NamedStyles.FindByID(StyleName, ref namedStyle); - if (namedStyle.XfId == int.MinValue) - { - namedStyle.XfId=Workbook.Styles.CellXfs.FindIndexByID(namedStyle.Style.Id); - } - return namedStyle.XfId; - } - /// <summary> - /// The workbook object - /// </summary> - public ExcelWorkbook Workbook - { - get - { - return _package.Workbook; - } - } - #endregion - #endregion // END Worksheet Private Methods + cse.Value = DateTime.FromOADate(sdv); + } catch {} + } + } + } - /// <summary> - /// Get the next ID from a shared formula or an Array formula - /// Sharedforumlas will have an id from 0-x. Array formula ids start from 0x4000001-. - /// </summary> - /// <param name="isArray">If the formula is an array formula</param> - /// <returns></returns> - internal int GetMaxShareFunctionIndex(bool isArray) - { - int i=_sharedFormulas.Count + 1; - if (isArray) - i |= 0x40000000; + public string GetFormula(int row, int col) { + var v = _formulas.GetValue(row, col); + if (v is int) { + return _sharedFormulas[(int)v].GetFormula(row, col, Name); + } + if (v != null) { + return v.ToString(); + } + return ""; + } - while(_sharedFormulas.ContainsKey(i)) - { - i++; - } - return i; - } - internal void SetHFLegacyDrawingRel(string relID) - { - SetXmlNodeString("d:legacyDrawingHF/@r:id", relID); - } - internal void RemoveLegacyDrawingRel(string relID) - { - var n = WorksheetXml.DocumentElement.SelectSingleNode(string.Format("d:legacyDrawing[@r:id=\"{0}\"]", relID), NameSpaceManager); - if (n != null) - { - n.ParentNode.RemoveChild(n); - } - } + public string GetFormulaR1C1(int row, int col) { + var v = _formulas.GetValue(row, col); + if (v is int) { + var sf = _sharedFormulas[(int)v]; + return ExcelCellBase.TranslateToR1C1( + Formulas.RemoveDummyFunction(sf.Formula), + sf.StartRow, + sf.StartCol); + } + if (v != null) { + return ExcelCellBase.TranslateToR1C1(Formulas.RemoveDummyFunction(v.ToString()), row, col); + } + return ""; + } - internal void UpdateCellsWithDate1904Setting() - { - var cse = new CellsStoreEnumerator<object>(_values); - var offset = Workbook.Date1904 ? -ExcelWorkbook.date1904Offset : ExcelWorkbook.date1904Offset; - while(cse.MoveNext()) - { - if (cse.Value is DateTime) - { - try - { - double sdv = ((DateTime)cse.Value).ToOADate(); - sdv += offset; + public string GetFormulaR1C1_V1(int row, int col) { + var v = _formulas.GetValue(row, col); + if (v is int) { + var sf = _sharedFormulas[(int)v]; + return ExcelCellBase.TranslateToR1C1_V1( + Formulas.RemoveDummyFunction(sf.Formula), + sf.StartRow, + sf.StartCol); + } + if (v != null) { + return ExcelCellBase.TranslateToR1C1_V1(Formulas.RemoveDummyFunction(v.ToString()), row, col); + } + return ""; + } - cse.Value = DateTime.FromOADate(sdv); - } - catch - { - } - } - } - } - public string GetFormula(int row, int col) - { - var v = _formulas.GetValue(row, col); - if (v is int) - { - return _sharedFormulas[(int)v].GetFormula(row,col, Name); - } - else if (v != null) - { - return v.ToString(); - } - else - { - return ""; - } - } - public string GetFormulaR1C1(int row, int col) - { - var v = _formulas.GetValue(row, col); - if (v is int) - { - var sf = _sharedFormulas[(int)v]; - return ExcelCellBase.TranslateToR1C1(Formulas.RemoveDummyFunction(sf.Formula), sf.StartRow, sf.StartCol); - } - else if (v != null) - { - return ExcelCellBase.TranslateToR1C1(Formulas.RemoveDummyFunction(v.ToString()), row, col); - } - else - { - return ""; - } - } + public bool IsArrayFormula(int row, int col) => + _flags.GetFlagValue(row, col, CellFlags.ArrayFormula); - public string GetFormulaR1C1_V1(int row, int col) - { - var v = _formulas.GetValue(row, col); - if (v is int) - { - var sf = _sharedFormulas[(int)v]; - return ExcelCellBase.TranslateToR1C1_V1(Formulas.RemoveDummyFunction(sf.Formula), sf.StartRow, sf.StartCol); - } - else if (v != null) - { - return ExcelCellBase.TranslateToR1C1_V1(Formulas.RemoveDummyFunction(v.ToString()), row, col); - } - else - { - return ""; - } - } + public string GetArrayFormulaAddress(int row, int col) { + var v = _formulas.GetValue(row, col); + if ((v is int) && (_sharedFormulas[(int)v].IsArray)) { + return _sharedFormulas[(int)v].Address; + } + return ""; + } - public bool IsArrayFormula(int row, int col) => _flags.GetFlagValue(row, col, CellFlags.ArrayFormula); - - public string GetArrayFormulaAddress(int row, int col) - { - var v = _formulas.GetValue(row, col); - if ((v is int) && (_sharedFormulas[(int)v].IsArray)) - { - return _sharedFormulas[(int)v].Address; - } - else - { - return ""; - } - } - - public int GetStyleId(int row, int col) { - int styleId = 0; - if (!_styles.Exists(row, col, ref styleId) && !_styles.Exists(row, 0, ref styleId)) { - styleId = _styles.GetValue(0, col); - } - return styleId; - } - - /// <summary> - /// Get the ExcelColumn for column (span ColumnMin and ColumnMax) - /// </summary> - /// <param name="column"></param> - /// <returns></returns> - internal ExcelColumn GetColumn(int column) - { - var c = _values.GetValue(0, column) as ExcelColumn; - if (c == null) - { - int row = 0, col = column; - if (_values.PrevCell(ref row, ref col)) - { - c = _values.GetValue(0, col) as ExcelColumn; - if (c != null && c.ColumnMax >= column) - { - return c; - } - return null; - } - } - return c; + public int GetStyleId(int row, int col) { + int styleId = 0; + if (!_styles.Exists(row, col, ref styleId) && !_styles.Exists(row, 0, ref styleId)) { + styleId = _styles.GetValue(0, col); + } + return styleId; + } + /// <summary> + /// Get the ExcelColumn for column (span ColumnMin and ColumnMax) + /// </summary> + /// <param name="column"></param> + /// <returns></returns> + internal ExcelColumn GetColumn(int column) { + var c = _values.GetValue(0, column) as ExcelColumn; + if (c == null) { + int row = 0, + col = column; + if (_values.PrevCell(ref row, ref col)) { + c = _values.GetValue(0, col) as ExcelColumn; + if (c != null && c.ColumnMax >= column) { + return c; } + return null; + } + } + return c; + } - public bool Equals(ExcelWorksheet x, ExcelWorksheet y) - { - return x.Name == y.Name && x.SheetID == y.SheetID && x.WorksheetXml.OuterXml == y.WorksheetXml.OuterXml; - } + public bool Equals(ExcelWorksheet x, ExcelWorksheet y) { + return x.Name == y.Name + && x.SheetID == y.SheetID + && x.WorksheetXml.OuterXml == y.WorksheetXml.OuterXml; + } - public int GetHashCode(ExcelWorksheet obj) - { - return obj.WorksheetXml.OuterXml.GetHashCode(); - } - } // END class Worksheet + public int GetHashCode(ExcelWorksheet obj) { + return obj.WorksheetXml.OuterXml.GetHashCode(); + } }
diff --git a/EPPlus/ExcelWorksheetView.cs b/EPPlus/ExcelWorksheetView.cs index 254a0d0..c3047a2 100644 --- a/EPPlus/ExcelWorksheetView.cs +++ b/EPPlus/ExcelWorksheetView.cs
@@ -4,7 +4,7 @@ * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. * See http://www.codeplex.com/EPPlus for details. * - * Copyright (C) 2011 Jan Källman + * Copyright (C) 2011 Jan K�llman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -13,455 +13,388 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** - * Jan Källman Initial Release 2009-10-01 - * Jan Källman License changed GPL-->LGPL 2011-12-27 + * Jan K�llman Initial Release 2009-10-01 + * Jan K�llman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; using System.Xml; -namespace OfficeOpenXml -{ - /// <summary> - /// Represents the different view states of the worksheet - /// </summary> - public class ExcelWorksheetView : XmlHelper - { - /// <summary> - /// The worksheet panes after a freeze or split. - /// </summary> - public class ExcelWorksheetPanes : XmlHelper - { - XmlElement _selectionNode = null; - internal ExcelWorksheetPanes(XmlNamespaceManager ns, XmlNode topNode) : - base(ns, topNode) - { - if(topNode.Name=="selection") - { - _selectionNode=topNode as XmlElement; - } - } +namespace OfficeOpenXml; - const string _activeCellPath = "@activeCell"; - /// <summary> - /// Set the active cell. Must be set within the SelectedRange. - /// </summary> - public string ActiveCell - { - get - { - string address = GetXmlNodeString(_activeCellPath); - if (address == "") - { - return "A1"; - } - return address; - } - set - { - int fromCol, fromRow, toCol, toRow; - if(_selectionNode==null) CreateSelectionElement(); - ExcelCellBase.GetRowColFromAddress(value, out fromRow, out fromCol, out toRow, out toCol); - SetXmlNodeString(_activeCellPath, value); - if (((XmlElement)TopNode).GetAttribute("sqref") == "") - { +/// <summary> +/// Represents the different view states of the worksheet +/// </summary> +public class ExcelWorksheetView : XmlHelper { + /// <summary> + /// The worksheet panes after a freeze or split. + /// </summary> + public class ExcelWorksheetPanes : XmlHelper { + private XmlElement _selectionNode; - SelectedRange = ExcelCellBase.GetAddress(fromRow, fromCol); - } - else - { - //TODO:Add fix for out of range here - } - } - } - - private void CreateSelectionElement() - { - _selectionNode=TopNode.OwnerDocument.CreateElement("selection", ExcelPackage.schemaMain); - TopNode.AppendChild(_selectionNode); - TopNode=_selectionNode; - } - const string _selectionRangePath = "@sqref"; - /// <summary> - /// Selected Cells.Used in combination with ActiveCell - /// </summary> - public string SelectedRange - { - get - { - string address = GetXmlNodeString(_selectionRangePath); - if (address == "") - { - return "A1"; - } - return address; - } - set - { - int fromCol, fromRow, toCol, toRow; - if(_selectionNode==null) CreateSelectionElement(); - ExcelCellBase.GetRowColFromAddress(value, out fromRow, out fromCol, out toRow, out toCol); - SetXmlNodeString(_selectionRangePath, value); - if (((XmlElement)TopNode).GetAttribute("activeCell") == "") - { - - ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol); - } - else - { - //TODO:Add fix for out of range here - } - } - } - } - private ExcelWorksheet _worksheet; - - #region ExcelWorksheetView Constructor - /// <summary> - /// Creates a new ExcelWorksheetView which provides access to all the view states of the worksheet. - /// </summary> - /// <param name="ns"></param> - /// <param name="node"></param> - /// <param name="xlWorksheet"></param> - internal ExcelWorksheetView(XmlNamespaceManager ns, XmlNode node, ExcelWorksheet xlWorksheet) : - base(ns, node) - { - _worksheet = xlWorksheet; - SchemaNodeOrder = new string[] { "sheetViews", "sheetView", "pane", "selection" }; - Panes = LoadPanes(); - } - - #endregion - private ExcelWorksheetPanes[] LoadPanes() - { - XmlNodeList nodes = TopNode.SelectNodes("//d:selection", NameSpaceManager); - if(nodes.Count==0) - { - return new ExcelWorksheetPanes[] { new ExcelWorksheetPanes(NameSpaceManager, TopNode) }; - } - else - { - ExcelWorksheetPanes[] panes = new ExcelWorksheetPanes[nodes.Count]; - int i=0; - foreach(XmlElement elem in nodes) - { - panes[i++] = new ExcelWorksheetPanes(NameSpaceManager, elem); - } - return panes; - } - } - #region SheetViewElement - /// <summary> - /// Returns a reference to the sheetView element - /// </summary> - protected internal XmlElement SheetViewElement - { - get - { - return (XmlElement)TopNode; - } - } - #endregion - #region TabSelected - private XmlElement _selectionNode = null; - private XmlElement SelectionNode - { - get - { - _selectionNode = SheetViewElement.SelectSingleNode("//d:selection", _worksheet.NameSpaceManager) as XmlElement; - if (_selectionNode == null) - { - _selectionNode = _worksheet.WorksheetXml.CreateElement("selection", ExcelPackage.schemaMain); - SheetViewElement.AppendChild(_selectionNode); - } - return _selectionNode; - } - } - #endregion - #region Public Methods & Properties - /// <summary> - /// The active cell. - /// </summary> - public string ActiveCell - { - get - { - return Panes[Panes.GetUpperBound(0)].ActiveCell; - } - set - { - Panes[Panes.GetUpperBound(0)].ActiveCell = value; - } - } - /// <summary> - /// Selected Cells in the worksheet.Used in combination with ActiveCell - /// </summary> - public string SelectedRange - { - get - { - return Panes[Panes.GetUpperBound(0)].SelectedRange; - } - set - { - Panes[Panes.GetUpperBound(0)].SelectedRange = value; - } - } - /// <summary> - /// Indicates if the worksheet is selected within the workbook - /// </summary> - public bool TabSelected - { - get - { - return GetXmlNodeBool("@tabSelected"); - } - set - { - if (value) - { - // // ensure no other worksheet has its tabSelected attribute set to 1 - foreach (ExcelWorksheet sheet in _worksheet._package.Workbook.Worksheets) - sheet.View.TabSelected = false; - - SheetViewElement.SetAttribute("tabSelected", "1"); - XmlElement bookView = _worksheet.Workbook.WorkbookXml.SelectSingleNode("//d:workbookView", _worksheet.NameSpaceManager) as XmlElement; - if (bookView != null) - { - bookView.SetAttribute("activeTab", (_worksheet.PositionID - 1).ToString()); - } - } - else - SetXmlNodeString("@tabSelected", "0"); - - } - } - - /// <summary> - /// Sets the view mode of the worksheet to pagelayout - /// </summary> - public bool PageLayoutView - { - get - { - return GetXmlNodeString("@view") == "pageLayout"; - } - set - { - if (value) - SetXmlNodeString("@view", "pageLayout"); - else - SheetViewElement.RemoveAttribute("view"); - } - } - /// <summary> - /// Sets the view mode of the worksheet to pagebreak - /// </summary> - public bool PageBreakView - { - get - { - return GetXmlNodeString("@view") == "pageBreakPreview"; - } - set - { - if (value) - SetXmlNodeString("@view", "pageBreakPreview"); - else - SheetViewElement.RemoveAttribute("view"); - } - } - /// <summary> - /// Show gridlines in the worksheet - /// </summary> - public bool ShowGridLines - { - get - { - return GetXmlNodeBool("@showGridLines"); - } - set - { - SetXmlNodeString("@showGridLines", value ? "1" : "0"); - } - } - /// <summary> - /// Show the Column/Row headers (containg column letters and row numbers) - /// </summary> - public bool ShowHeaders - { - get - { - return GetXmlNodeBool("@showRowColHeaders"); - } - set - { - SetXmlNodeString("@showRowColHeaders", value ? "1" : "0"); - } - } - /// <summary> - /// Window zoom magnification for current view representing percent values. - /// </summary> - public int ZoomScale - { - get - { - return GetXmlNodeInt("@zoomScale"); - } - set - { - if (value < 10 || value > 400) - { - throw new ArgumentOutOfRangeException("Zoome scale out of range (10-400)"); - } - SetXmlNodeString("@zoomScale", value.ToString()); - } - } - /// <summary> - /// Flag indicating whether the sheet is in 'right to left' display mode. When in this mode,Column A is on the far right, Column B ;is one column left of Column A, and so on. Also,information in cells is displayed in the Right to Left format. - /// </summary> - public bool RightToLeft - { - get - { - return GetXmlNodeBool("@rightToLeft"); - } - set - { - SetXmlNodeString("@rightToLeft", value == true ? "1" : "0"); - } - } - internal bool WindowProtection - { - get - { - return GetXmlNodeBool("@windowProtection",false); - } - set - { - SetXmlNodeBool("@windowProtection",value,false); - } - } - /// <summary> - /// Reference to the panes - /// </summary> - public ExcelWorksheetPanes[] Panes - { - get; - internal set; - } - string _paneNodePath = "d:pane"; - string _selectionNodePath = "d:selection"; - /// <summary> - /// Freeze the columns/rows to left and above the cell - /// </summary> - /// <param name="Row"></param> - /// <param name="Column"></param> - public void FreezePanes(int Row, int Column) - { - //TODO:fix this method to handle splits as well. - if (Row == 1 && Column == 1) UnFreezePanes(); - string sqRef = SelectedRange, activeCell = ActiveCell; - - XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement; - if (paneNode == null) - { - CreateNode(_paneNodePath); - paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement; - } - paneNode.RemoveAll(); //Clear all attributes - if (Column > 1) paneNode.SetAttribute("xSplit", (Column - 1).ToString()); - if (Row > 1) paneNode.SetAttribute("ySplit", (Row - 1).ToString()); - paneNode.SetAttribute("topLeftCell", ExcelCellBase.GetAddress(Row, Column)); - paneNode.SetAttribute("state", "frozen"); - - RemoveSelection(); - - if (Row > 1 && Column==1) - { - paneNode.SetAttribute("activePane", "bottomLeft"); - XmlElement sel=TopNode.OwnerDocument.CreateElement("selection", ExcelPackage.schemaMain); - sel.SetAttribute("pane", "bottomLeft"); - if (activeCell != "") sel.SetAttribute("activeCell", activeCell); - if (sqRef != "") sel.SetAttribute("sqref", sqRef); - sel.SetAttribute("sqref", sqRef); - TopNode.InsertAfter(sel, paneNode); - } - else if (Column > 1 && Row == 1) - { - paneNode.SetAttribute("activePane", "topRight"); - XmlElement sel = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage.schemaMain); - sel.SetAttribute("pane", "topRight"); - if (activeCell != "") sel.SetAttribute("activeCell", activeCell); - if (sqRef != "") sel.SetAttribute("sqref", sqRef); - TopNode.InsertAfter(sel, paneNode); - } - else - { - paneNode.SetAttribute("activePane", "bottomRight"); - XmlElement sel1 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage.schemaMain); - sel1.SetAttribute("pane", "topRight"); - string cell = ExcelCellBase.GetAddress(1, Column); - sel1.SetAttribute("activeCell", cell); - sel1.SetAttribute("sqref", cell); - paneNode.ParentNode.InsertAfter(sel1, paneNode); - - XmlElement sel2 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage.schemaMain); - cell = ExcelCellBase.GetAddress(Row, 1); - sel2.SetAttribute("pane", "bottomLeft"); - sel2.SetAttribute("activeCell", cell); - sel2.SetAttribute("sqref", cell); - sel1.ParentNode.InsertAfter(sel2, sel1); - - XmlElement sel3 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage.schemaMain); - sel3.SetAttribute("pane", "bottomRight"); - if(activeCell!="") sel3.SetAttribute("activeCell", activeCell); - if(sqRef!="") sel3.SetAttribute("sqref", sqRef); - sel2.ParentNode.InsertAfter(sel3, sel2); - - } - Panes=LoadPanes(); - } - private void RemoveSelection() - { - //Find selection nodes and remove them - XmlNodeList selections = TopNode.SelectNodes(_selectionNodePath, NameSpaceManager); - foreach (XmlNode sel in selections) - { - sel.ParentNode.RemoveChild(sel); - } - } - /// <summary> - /// Unlock all rows and columns to scroll freely - /// /// </summary> - public void UnFreezePanes() - { - string sqRef = SelectedRange, activeCell = ActiveCell; - - XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement; - if (paneNode != null) - { - paneNode.ParentNode.RemoveChild(paneNode); - } - RemoveSelection(); - - Panes=LoadPanes(); - - SelectedRange = sqRef; - ActiveCell = activeCell; - } - #endregion + internal ExcelWorksheetPanes(XmlNamespaceManager ns, XmlNode topNode) + : base(ns, topNode) { + if (topNode.Name == "selection") { + _selectionNode = topNode as XmlElement; + } } + + private const string _activeCellPath = "@activeCell"; + + /// <summary> + /// Set the active cell. Must be set within the SelectedRange. + /// </summary> + public string ActiveCell { + get { + string address = GetXmlNodeString(_activeCellPath); + if (address == "") { + return "A1"; + } + return address; + } + set { + int fromCol, + fromRow, + toCol, + toRow; + if (_selectionNode == null) { + CreateSelectionElement(); + } + ExcelCellBase.GetRowColFromAddress(value, out fromRow, out fromCol, out toRow, out toCol); + SetXmlNodeString(_activeCellPath, value); + if (((XmlElement)TopNode).GetAttribute("sqref") == "") { + SelectedRange = ExcelCellBase.GetAddress(fromRow, fromCol); + } + //TODO:Add fix for out of range here + } + } + + private void CreateSelectionElement() { + _selectionNode = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain); + TopNode.AppendChild(_selectionNode); + TopNode = _selectionNode; + } + + private const string _selectionRangePath = "@sqref"; + + /// <summary> + /// Selected Cells.Used in combination with ActiveCell + /// </summary> + public string SelectedRange { + get { + string address = GetXmlNodeString(_selectionRangePath); + if (address == "") { + return "A1"; + } + return address; + } + set { + int fromCol, + fromRow, + toCol, + toRow; + if (_selectionNode == null) { + CreateSelectionElement(); + } + ExcelCellBase.GetRowColFromAddress(value, out fromRow, out fromCol, out toRow, out toCol); + SetXmlNodeString(_selectionRangePath, value); + if (((XmlElement)TopNode).GetAttribute("activeCell") == "") { + ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol); + } + //TODO:Add fix for out of range here + } + } + } + + private ExcelWorksheet _worksheet; + + /// <summary> + /// Creates a new ExcelWorksheetView which provides access to all the view states of the worksheet. + /// </summary> + /// <param name="ns"></param> + /// <param name="node"></param> + /// <param name="xlWorksheet"></param> + internal ExcelWorksheetView(XmlNamespaceManager ns, XmlNode node, ExcelWorksheet xlWorksheet) + : base(ns, node) { + _worksheet = xlWorksheet; + SchemaNodeOrder = new[] { "sheetViews", "sheetView", "pane", "selection" }; + Panes = LoadPanes(); + } + + private ExcelWorksheetPanes[] LoadPanes() { + XmlNodeList nodes = TopNode.SelectNodes("//d:selection", NameSpaceManager); + if (nodes.Count == 0) { + return new[] { new ExcelWorksheetPanes(NameSpaceManager, TopNode) }; + } + ExcelWorksheetPanes[] panes = new ExcelWorksheetPanes[nodes.Count]; + int i = 0; + foreach (XmlElement elem in nodes) { + panes[i++] = new(NameSpaceManager, elem); + } + return panes; + } + + /// <summary> + /// Returns a reference to the sheetView element + /// </summary> + protected internal XmlElement SheetViewElement => (XmlElement)TopNode; + + private XmlElement _selectionNode; + + private XmlElement SelectionNode { + get { + _selectionNode = + SheetViewElement.SelectSingleNode("//d:selection", _worksheet.NameSpaceManager) + as XmlElement; + if (_selectionNode == null) { + _selectionNode = _worksheet.WorksheetXml.CreateElement( + "selection", + ExcelPackage._schemaMain); + SheetViewElement.AppendChild(_selectionNode); + } + return _selectionNode; + } + } + + /// <summary> + /// The active cell. + /// </summary> + public string ActiveCell { + get { return Panes[Panes.GetUpperBound(0)].ActiveCell; } + set { Panes[Panes.GetUpperBound(0)].ActiveCell = value; } + } + + /// <summary> + /// Selected Cells in the worksheet.Used in combination with ActiveCell + /// </summary> + public string SelectedRange { + get { return Panes[Panes.GetUpperBound(0)].SelectedRange; } + set { Panes[Panes.GetUpperBound(0)].SelectedRange = value; } + } + + /// <summary> + /// Indicates if the worksheet is selected within the workbook + /// </summary> + public bool TabSelected { + get { return GetXmlNodeBool("@tabSelected"); } + set { + if (value) { + // // ensure no other worksheet has its tabSelected attribute set to 1 + foreach (ExcelWorksheet sheet in _worksheet._package.Workbook.Worksheets) { + sheet.View.TabSelected = false; + } + + SheetViewElement.SetAttribute("tabSelected", "1"); + XmlElement bookView = + _worksheet.Workbook.WorkbookXml.SelectSingleNode( + "//d:workbookView", + _worksheet.NameSpaceManager) as XmlElement; + if (bookView != null) { + bookView.SetAttribute("activeTab", (_worksheet.PositionID - 1).ToString()); + } + } else { + SetXmlNodeString("@tabSelected", "0"); + } + } + } + + /// <summary> + /// Sets the view mode of the worksheet to pagelayout + /// </summary> + public bool PageLayoutView { + get { return GetXmlNodeString("@view") == "pageLayout"; } + set { + if (value) { + SetXmlNodeString("@view", "pageLayout"); + } else { + SheetViewElement.RemoveAttribute("view"); + } + } + } + + /// <summary> + /// Sets the view mode of the worksheet to pagebreak + /// </summary> + public bool PageBreakView { + get { return GetXmlNodeString("@view") == "pageBreakPreview"; } + set { + if (value) { + SetXmlNodeString("@view", "pageBreakPreview"); + } else { + SheetViewElement.RemoveAttribute("view"); + } + } + } + + /// <summary> + /// Show gridlines in the worksheet + /// </summary> + public bool ShowGridLines { + get { return GetXmlNodeBool("@showGridLines"); } + set { SetXmlNodeString("@showGridLines", value ? "1" : "0"); } + } + + /// <summary> + /// Show the Column/Row headers (containg column letters and row numbers) + /// </summary> + public bool ShowHeaders { + get { return GetXmlNodeBool("@showRowColHeaders"); } + set { SetXmlNodeString("@showRowColHeaders", value ? "1" : "0"); } + } + + /// <summary> + /// Window zoom magnification for current view representing percent values. + /// </summary> + public int ZoomScale { + get { return GetXmlNodeInt("@zoomScale"); } + set { + if (value < 10 || value > 400) { + throw new ArgumentOutOfRangeException("Zoome scale out of range (10-400)"); + } + SetXmlNodeString("@zoomScale", value.ToString()); + } + } + + /// <summary> + /// Flag indicating whether the sheet is in 'right to left' display mode. When in this mode,Column A is on the far right, Column B ;is one column left of Column A, and so on. Also,information in cells is displayed in the Right to Left format. + /// </summary> + public bool RightToLeft { + get { return GetXmlNodeBool("@rightToLeft"); } + set { SetXmlNodeString("@rightToLeft", value ? "1" : "0"); } + } + + internal bool WindowProtection { + get { return GetXmlNodeBool("@windowProtection", false); } + set { SetXmlNodeBool("@windowProtection", value, false); } + } + + /// <summary> + /// Reference to the panes + /// </summary> + public ExcelWorksheetPanes[] Panes { get; internal set; } + + private string _paneNodePath = "d:pane"; + private string _selectionNodePath = "d:selection"; + + /// <summary> + /// Freeze the columns/rows to left and above the cell + /// </summary> + /// <param name="row"></param> + /// <param name="column"></param> + public void FreezePanes(int row, int column) { + //TODO:fix this method to handle splits as well. + if (row == 1 && column == 1) { + UnFreezePanes(); + } + string sqRef = SelectedRange, + activeCell = ActiveCell; + + XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement; + if (paneNode == null) { + CreateNode(_paneNodePath); + paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement; + } + paneNode.RemoveAll(); //Clear all attributes + if (column > 1) { + paneNode.SetAttribute("xSplit", (column - 1).ToString()); + } + if (row > 1) { + paneNode.SetAttribute("ySplit", (row - 1).ToString()); + } + paneNode.SetAttribute("topLeftCell", ExcelCellBase.GetAddress(row, column)); + paneNode.SetAttribute("state", "frozen"); + + RemoveSelection(); + + if (row > 1 && column == 1) { + paneNode.SetAttribute("activePane", "bottomLeft"); + XmlElement sel = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain); + sel.SetAttribute("pane", "bottomLeft"); + if (activeCell != "") { + sel.SetAttribute("activeCell", activeCell); + } + if (sqRef != "") { + sel.SetAttribute("sqref", sqRef); + } + sel.SetAttribute("sqref", sqRef); + TopNode.InsertAfter(sel, paneNode); + } else if (column > 1 && row == 1) { + paneNode.SetAttribute("activePane", "topRight"); + XmlElement sel = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain); + sel.SetAttribute("pane", "topRight"); + if (activeCell != "") { + sel.SetAttribute("activeCell", activeCell); + } + if (sqRef != "") { + sel.SetAttribute("sqref", sqRef); + } + TopNode.InsertAfter(sel, paneNode); + } else { + paneNode.SetAttribute("activePane", "bottomRight"); + XmlElement sel1 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain); + sel1.SetAttribute("pane", "topRight"); + string cell = ExcelCellBase.GetAddress(1, column); + sel1.SetAttribute("activeCell", cell); + sel1.SetAttribute("sqref", cell); + paneNode.ParentNode.InsertAfter(sel1, paneNode); + + XmlElement sel2 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain); + cell = ExcelCellBase.GetAddress(row, 1); + sel2.SetAttribute("pane", "bottomLeft"); + sel2.SetAttribute("activeCell", cell); + sel2.SetAttribute("sqref", cell); + sel1.ParentNode.InsertAfter(sel2, sel1); + + XmlElement sel3 = TopNode.OwnerDocument.CreateElement("selection", ExcelPackage._schemaMain); + sel3.SetAttribute("pane", "bottomRight"); + if (activeCell != "") { + sel3.SetAttribute("activeCell", activeCell); + } + if (sqRef != "") { + sel3.SetAttribute("sqref", sqRef); + } + sel2.ParentNode.InsertAfter(sel3, sel2); + } + Panes = LoadPanes(); + } + + private void RemoveSelection() { + //Find selection nodes and remove them + XmlNodeList selections = TopNode.SelectNodes(_selectionNodePath, NameSpaceManager); + foreach (XmlNode sel in selections) { + sel.ParentNode.RemoveChild(sel); + } + } + + /// <summary> + /// Unlock all rows and columns to scroll freely + /// /// </summary> + public void UnFreezePanes() { + string sqRef = SelectedRange, + activeCell = ActiveCell; + + XmlElement paneNode = TopNode.SelectSingleNode(_paneNodePath, NameSpaceManager) as XmlElement; + if (paneNode != null) { + paneNode.ParentNode.RemoveChild(paneNode); + } + RemoveSelection(); + + Panes = LoadPanes(); + + SelectedRange = sqRef; + ActiveCell = activeCell; + } }
diff --git a/EPPlus/ExcelWorksheets.cs b/EPPlus/ExcelWorksheets.cs index 18c2ecf..91e3cdb 100644 --- a/EPPlus/ExcelWorksheets.cs +++ b/EPPlus/ExcelWorksheets.cs
@@ -13,516 +13,516 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; using System.Collections; using System.Collections.Generic; -using System.Xml; using System.IO; +using System.Text.RegularExpressions; +using System.Xml; +using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils; -namespace OfficeOpenXml -{ - /// <summary> - /// The collection of worksheets for the workbook - /// </summary> - public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet> - { - #region Private Properties - private ExcelPackage _pck; - private Dictionary<int, ExcelWorksheet> _worksheets; - private XmlNamespaceManager _namespaceManager; - #endregion - #region ExcelWorksheets Constructor - internal ExcelWorksheets(ExcelPackage pck, XmlNamespaceManager nsm, XmlNode topNode) : - base(nsm, topNode) - { - _pck = pck; - _namespaceManager = nsm; - _worksheets = new Dictionary<int, ExcelWorksheet>(); - int positionID = 1; - foreach (XmlNode sheetNode in topNode.ChildNodes) - { - if (sheetNode.NodeType == XmlNodeType.Element) - { - string name = sheetNode.Attributes["name"].Value; - //Get the relationship id - string relId = sheetNode.Attributes["r:id"].Value; - int sheetID = Convert.ToInt32(sheetNode.Attributes["sheetId"].Value); +namespace OfficeOpenXml; - //Hidden property - eWorkSheetHidden hidden = eWorkSheetHidden.Visible; - XmlNode attr = sheetNode.Attributes["state"]; - if (attr != null) - hidden = TranslateHidden(attr.Value); +/// <summary> +/// The collection of worksheets for the workbook +/// </summary> +public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet> { + private ExcelPackage _pck; + private Dictionary<int, ExcelWorksheet> _worksheets; + private XmlNamespaceManager _namespaceManager; - var sheetRelation = pck.Workbook.Part.GetRelationship(relId); - Uri uriWorksheet = UriHelper.ResolvePartUri(pck.Workbook.WorkbookUri, sheetRelation.TargetUri); + internal ExcelWorksheets(ExcelPackage pck, XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + _pck = pck; + _namespaceManager = nsm; + _worksheets = new(); + int positionId = 1; - //add the worksheet - if (sheetRelation.RelationshipType.EndsWith("chartsheet")) - { - _worksheets.Add(positionID, new ExcelChartsheet(_namespaceManager, _pck, relId, uriWorksheet, name, sheetID, positionID, hidden)); - } - else - { - _worksheets.Add(positionID, new ExcelWorksheet(_namespaceManager, _pck, relId, uriWorksheet, name, sheetID, positionID, hidden)); - } - positionID++; - } - } - } + foreach (XmlNode sheetNode in topNode.ChildNodes) { + if (sheetNode.NodeType == XmlNodeType.Element) { + string name = sheetNode.Attributes["name"].Value; + //Get the relationship id + string relId = sheetNode.Attributes["r:id"].Value; + int sheetId = Convert.ToInt32(sheetNode.Attributes["sheetId"].Value); - private eWorkSheetHidden TranslateHidden(string value) - { - switch (value) - { - case "hidden": - return eWorkSheetHidden.Hidden; - case "veryHidden": - return eWorkSheetHidden.VeryHidden; - default: - return eWorkSheetHidden.Visible; - } - } - #endregion - #region ExcelWorksheets Public Properties - /// <summary> - /// Returns the number of worksheets in the workbook - /// </summary> - public int Count - { - get { return (_worksheets.Count); } - } - #endregion - private const string ERR_DUP_WORKSHEET = "A worksheet with this name already exists in the workbook"; - internal const string WORKSHEET_CONTENTTYPE = @"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"; - internal const string CHARTSHEET_CONTENTTYPE = @"application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"; - #region ExcelWorksheets Public Methods - /// <summary> - /// Foreach support - /// </summary> - /// <returns>An enumerator</returns> - public IEnumerator<ExcelWorksheet> GetEnumerator() - { - return (_worksheets.Values.GetEnumerator()); - } - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() - { - return (_worksheets.Values.GetEnumerator()); + //Hidden property + eWorkSheetHidden hidden = eWorkSheetHidden.Visible; + XmlNode attr = sheetNode.Attributes["state"]; + if (attr != null) { + hidden = TranslateHidden(attr.Value); } - #endregion - #region Add Worksheet - /// <summary> - /// Adds a new blank worksheet. - /// </summary> - /// <param name="Name">The name of the workbook</param> - public ExcelWorksheet Add(string Name) - { - int sheetID; - Uri uriWorksheet; - lock (_worksheets) - { - Name = ValidateFixSheetName(Name); - if (GetByName(Name) != null) - { - throw (new InvalidOperationException(ERR_DUP_WORKSHEET + " : " + Name)); - } - GetSheetURI(ref Name, out sheetID, out uriWorksheet, false); - Packaging.ZipPackagePart worksheetPart = _pck.Package.CreatePart(uriWorksheet, WORKSHEET_CONTENTTYPE, _pck.Compression); + var sheetRelation = pck.Workbook.Part.GetRelationship(relId); + Uri uriWorksheet = UriHelper.ResolvePartUri( + pck.Workbook.WorkbookUri, + sheetRelation.TargetUri); - //Create the new, empty worksheet and save it to the package - StreamWriter streamWorksheet = new StreamWriter(worksheetPart.GetStream(FileMode.Create, FileAccess.Write)); - XmlDocument worksheetXml = CreateNewWorksheet(false); - worksheetXml.Save(streamWorksheet); - - string rel = CreateWorkbookRel(Name, sheetID, uriWorksheet, false); - - int positionID = _worksheets.Count + 1; - ExcelWorksheet worksheet; - - { - worksheet = new ExcelWorksheet(_namespaceManager, _pck, rel, uriWorksheet, Name, sheetID, positionID, eWorkSheetHidden.Visible); - } - - _worksheets.Add(positionID, worksheet); - return worksheet; - } + //add the worksheet + if (sheetRelation.RelationshipType.EndsWith("chartsheet")) { + _worksheets.Add( + positionId, + new ExcelChartsheet( + _namespaceManager, + _pck, + relId, + uriWorksheet, + name, + sheetId, + positionId, + hidden)); + } else { + _worksheets.Add( + positionId, + new(_namespaceManager, _pck, relId, uriWorksheet, name, sheetId, positionId, hidden)); } + positionId++; + } + } + } - string CreateWorkbookRel(string Name, int sheetID, Uri uriWorksheet, bool isChart) - { - //Create the relationship between the workbook and the new worksheet - var rel = _pck.Workbook.Part.CreateRelationship(UriHelper.GetRelativeUri(_pck.Workbook.WorkbookUri, uriWorksheet), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/" + (isChart ? "chartsheet" : "worksheet")); + private eWorkSheetHidden TranslateHidden(string value) { + switch (value) { + case "hidden": + return eWorkSheetHidden.Hidden; + case "veryHidden": + return eWorkSheetHidden.VeryHidden; + default: + return eWorkSheetHidden.Visible; + } + } - //Create the new sheet node - XmlElement worksheetNode = _pck.Workbook.WorkbookXml.CreateElement("sheet", ExcelPackage.schemaMain); - worksheetNode.SetAttribute("name", Name); - worksheetNode.SetAttribute("sheetId", sheetID.ToString()); - worksheetNode.SetAttribute("id", ExcelPackage.schemaRelationships, rel.Id); + /// <summary> + /// Returns the number of worksheets in the workbook + /// </summary> + public int Count => (_worksheets.Count); - TopNode.AppendChild(worksheetNode); - return rel.Id; + private const string _errDupWorksheet = + "A worksheet with this name already exists in the workbook"; + internal const string _worksheetContenttype = + "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"; + internal const string _chartsheetContenttype = + "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml"; + + /// <summary> + /// Foreach support + /// </summary> + /// <returns>An enumerator</returns> + public IEnumerator<ExcelWorksheet> GetEnumerator() { + return (_worksheets.Values.GetEnumerator()); + } + + IEnumerator IEnumerable.GetEnumerator() { + return (_worksheets.Values.GetEnumerator()); + } + + /// <summary> + /// Adds a new blank worksheet. + /// </summary> + /// <param name="name">The name of the workbook</param> + public ExcelWorksheet Add(string name) { + int sheetId; + Uri uriWorksheet; + lock (_worksheets) { + name = ValidateFixSheetName(name); + if (GetByName(name) != null) { + throw (new InvalidOperationException(_errDupWorksheet + " : " + name)); + } + GetSheetUri(ref name, out sheetId, out uriWorksheet, false); + ZipPackagePart worksheetPart = _pck.Package.CreatePart( + uriWorksheet, + _worksheetContenttype, + _pck.Compression); + + //Create the new, empty worksheet and save it to the package + StreamWriter streamWorksheet = new StreamWriter( + worksheetPart.GetStream(FileMode.Create, FileAccess.Write)); + XmlDocument worksheetXml = CreateNewWorksheet(false); + worksheetXml.Save(streamWorksheet); + + string rel = CreateWorkbookRel(name, sheetId, uriWorksheet, false); + + int positionId = _worksheets.Count + 1; + ExcelWorksheet worksheet; + + { + worksheet = new( + _namespaceManager, + _pck, + rel, + uriWorksheet, + name, + sheetId, + positionId, + eWorkSheetHidden.Visible); + } + + _worksheets.Add(positionId, worksheet); + return worksheet; + } + } + + private string CreateWorkbookRel(string name, int sheetId, Uri uriWorksheet, bool isChart) { + //Create the relationship between the workbook and the new worksheet + var rel = _pck.Workbook.Part.CreateRelationship( + UriHelper.GetRelativeUri(_pck.Workbook.WorkbookUri, uriWorksheet), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/" + (isChart ? "chartsheet" : "worksheet")); + + //Create the new sheet node + XmlElement worksheetNode = _pck.Workbook.WorkbookXml.CreateElement( + "sheet", + ExcelPackage._schemaMain); + worksheetNode.SetAttribute("name", name); + worksheetNode.SetAttribute("sheetId", sheetId.ToString()); + worksheetNode.SetAttribute("id", ExcelPackage._schemaRelationships, rel.Id); + + TopNode.AppendChild(worksheetNode); + return rel.Id; + } + + private void GetSheetUri(ref string name, out int sheetId, out Uri uriWorksheet, bool isChart) { + name = ValidateFixSheetName(name); + + //First find maximum existing sheetID + sheetId = 0; + foreach (var ws in this) { + if (ws.SheetID > sheetId) { + sheetId = ws.SheetID; + } + } + // we now have the max existing values, so add one + sheetId++; + + // add the new worksheet to the package + if (isChart) { + uriWorksheet = new("/xl/chartsheets/chartsheet" + sheetId + ".xml", UriKind.Relative); + } else { + uriWorksheet = new("/xl/worksheets/sheet" + sheetId + ".xml", UriKind.Relative); + } + } + + internal string ValidateFixSheetName(string name) { + //remove invalid characters + if (ValidateName(name)) { + if (name.IndexOf(':') > -1) { + name = name.Replace(":", " "); + } + if (name.IndexOf('/') > -1) { + name = name.Replace("/", " "); + } + if (name.IndexOf('\\') > -1) { + name = name.Replace("\\", " "); + } + if (name.IndexOf('?') > -1) { + name = name.Replace("?", " "); + } + if (name.IndexOf('[') > -1) { + name = name.Replace("[", " "); + } + if (name.IndexOf(']') > -1) { + name = name.Replace("]", " "); + } + } + + if (name.Trim() == "") { + throw new ArgumentException("The worksheet can not have an empty name"); + } + if (name.Length > 31) { + name = name.Substring(0, 31); //A sheet can have max 31 char's + } + return name; + } + + /// <summary> + /// Validate the sheetname + /// </summary> + /// <param name="name">The Name</param> + /// <returns>True if valid</returns> + private bool ValidateName(string name) { + return Regex.IsMatch(name, @":|\?|/|\\|\[|\]"); + } + + /// <summary> + /// Creates the XML document representing a new empty worksheet + /// </summary> + /// <returns></returns> + internal XmlDocument CreateNewWorksheet(bool isChart) { + XmlDocument xmlDoc = new XmlDocument(); + XmlElement elemWs = xmlDoc.CreateElement( + isChart ? "chartsheet" : "worksheet", + ExcelPackage._schemaMain); + elemWs.SetAttribute("xmlns:r", ExcelPackage._schemaRelationships); + xmlDoc.AppendChild(elemWs); + + if (isChart) { + XmlElement elemSheetPr = xmlDoc.CreateElement("sheetPr", ExcelPackage._schemaMain); + elemWs.AppendChild(elemSheetPr); + + XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage._schemaMain); + elemWs.AppendChild(elemSheetViews); + + XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage._schemaMain); + elemSheetView.SetAttribute("workbookViewId", "0"); + elemSheetView.SetAttribute("zoomToFit", "1"); + + elemSheetViews.AppendChild(elemSheetView); + } else { + XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage._schemaMain); + elemWs.AppendChild(elemSheetViews); + + XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage._schemaMain); + elemSheetView.SetAttribute("workbookViewId", "0"); + elemSheetViews.AppendChild(elemSheetView); + + XmlElement elemSheetFormatPr = xmlDoc.CreateElement( + "sheetFormatPr", + ExcelPackage._schemaMain); + elemSheetFormatPr.SetAttribute("defaultRowHeight", "15"); + elemWs.AppendChild(elemSheetFormatPr); + + XmlElement elemSheetData = xmlDoc.CreateElement("sheetData", ExcelPackage._schemaMain); + elemWs.AppendChild(elemSheetData); + } + return xmlDoc; + } + + /// <summary> + /// Returns the worksheet at the specified position. + /// </summary> + /// <param name="positionId">The position of the worksheet. 1-base</param> + /// <returns></returns> + public ExcelWorksheet this[int positionId] { + get { + if (_worksheets.ContainsKey(positionId)) { + return _worksheets[positionId]; + } + throw (new IndexOutOfRangeException("Worksheet position out of range.")); + } + } + + /// <summary> + /// Returns the worksheet matching the specified name + /// </summary> + /// <param name="name">The name of the worksheet</param> + /// <returns></returns> + public ExcelWorksheet this[string name] { + get { return GetByName(name); } + } + + internal ExcelWorksheet GetBySheetId(int localSheetId) { + foreach (ExcelWorksheet ws in this) { + if (ws.SheetID == localSheetId) { + return ws; + } + } + return null; + } + + private ExcelWorksheet GetByName(string name) { + if (string.IsNullOrEmpty(name)) { + return null; + } + ExcelWorksheet xlWorksheet = null; + foreach (ExcelWorksheet worksheet in _worksheets.Values) { + if (worksheet.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) { + xlWorksheet = worksheet; + } + } + return (xlWorksheet); + } + + /// <summary> + /// Moves the source worksheet to the position before the target worksheet + /// </summary> + /// <param name="sourceName">The name of the source worksheet</param> + /// <param name="targetName">The name of the target worksheet</param> + public void MoveBefore(string sourceName, string targetName) { + Move(sourceName, targetName, false); + } + + /// <summary> + /// Moves the source worksheet to the position before the target worksheet + /// </summary> + /// <param name="sourcePositionId">The id of the source worksheet</param> + /// <param name="targetPositionId">The id of the target worksheet</param> + public void MoveBefore(int sourcePositionId, int targetPositionId) { + Move(sourcePositionId, targetPositionId, false); + } + + /// <summary> + /// Moves the source worksheet to the position after the target worksheet + /// </summary> + /// <param name="sourceName">The name of the source worksheet</param> + /// <param name="targetName">The name of the target worksheet</param> + public void MoveAfter(string sourceName, string targetName) { + Move(sourceName, targetName, true); + } + + /// <summary> + /// Moves the source worksheet to the position after the target worksheet + /// </summary> + /// <param name="sourcePositionId">The id of the source worksheet</param> + /// <param name="targetPositionId">The id of the target worksheet</param> + public void MoveAfter(int sourcePositionId, int targetPositionId) { + Move(sourcePositionId, targetPositionId, true); + } + + /// <summary> + /// + /// </summary> + /// <param name="sourceName"></param> + public void MoveToStart(string sourceName) { + var sourceSheet = this[sourceName]; + if (sourceSheet == null) { + throw new( + string.Format( + "Move worksheet error: Could not find worksheet to move '{0}'", + sourceName)); + } + Move(sourceSheet.PositionID, 1, false); + } + + /// <summary> + /// + /// </summary> + /// <param name="sourcePositionId"></param> + public void MoveToStart(int sourcePositionId) { + Move(sourcePositionId, 1, false); + } + + /// <summary> + /// + /// </summary> + /// <param name="sourceName"></param> + public void MoveToEnd(string sourceName) { + var sourceSheet = this[sourceName]; + if (sourceSheet == null) { + throw new( + string.Format( + "Move worksheet error: Could not find worksheet to move '{0}'", + sourceName)); + } + Move(sourceSheet.PositionID, _worksheets.Count, true); + } + + /// <summary> + /// + /// </summary> + /// <param name="sourcePositionId"></param> + public void MoveToEnd(int sourcePositionId) { + Move(sourcePositionId, _worksheets.Count, true); + } + + private void Move(string sourceName, string targetName, bool placeAfter) { + var sourceSheet = this[sourceName]; + if (sourceSheet == null) { + throw new( + string.Format( + "Move worksheet error: Could not find worksheet to move '{0}'", + sourceName)); + } + var targetSheet = this[targetName]; + if (targetSheet == null) { + throw new( + string.Format( + "Move worksheet error: Could not find worksheet to move '{0}'", + targetName)); + } + Move(sourceSheet.PositionID, targetSheet.PositionID, placeAfter); + } + + private void Move(int sourcePositionId, int targetPositionId, bool placeAfter) { + // Bugfix: if source and target are the same worksheet the following code will create a duplicate + // which will cause a corrupt workbook. /swmal 2014-05-10 + if (sourcePositionId == targetPositionId) { + return; + } + + lock (_worksheets) { + var sourceSheet = this[sourcePositionId]; + if (sourceSheet == null) { + throw new( + string.Format( + "Move worksheet error: Could not find worksheet at position '{0}'", + sourcePositionId)); + } + var targetSheet = this[targetPositionId]; + if (targetSheet == null) { + throw new( + string.Format( + "Move worksheet error: Could not find worksheet at position '{0}'", + targetPositionId)); + } + if (sourcePositionId == targetPositionId && _worksheets.Count < 2) { + return; //--- no reason to attempt to re-arrange a single item with itself + } + + var index = 1; + var newOrder = new Dictionary<int, ExcelWorksheet>(); + foreach (var entry in _worksheets) { + if (entry.Key == targetPositionId) { + if (!placeAfter) { + sourceSheet.PositionID = index; + newOrder.Add(index++, sourceSheet); + } + + entry.Value.PositionID = index; + newOrder.Add(index++, entry.Value); + + if (placeAfter) { + sourceSheet.PositionID = index; + newOrder.Add(index++, sourceSheet); + } + } else if (entry.Key == sourcePositionId) { + //--- do nothing + } else { + entry.Value.PositionID = index; + newOrder.Add(index++, entry.Value); } - private void GetSheetURI(ref string Name, out int sheetID, out Uri uriWorksheet, bool isChart) - { - Name = ValidateFixSheetName(Name); + } + _worksheets = newOrder; - //First find maximum existing sheetID - sheetID = 0; - foreach(var ws in this) - { - if (ws.SheetID > sheetID) - { - sheetID = ws.SheetID; - } - } - // we now have the max existing values, so add one - sheetID++; + MoveSheetXmlNode(sourceSheet, targetSheet, placeAfter); + } + } - // add the new worksheet to the package - if (isChart) - { - uriWorksheet = new Uri("/xl/chartsheets/chartsheet" + sheetID.ToString() + ".xml", UriKind.Relative); - } - else - { - uriWorksheet = new Uri("/xl/worksheets/sheet" + sheetID.ToString() + ".xml", UriKind.Relative); - } - } - - internal string ValidateFixSheetName(string Name) - { - //remove invalid characters - if (ValidateName(Name)) - { - if (Name.IndexOf(':') > -1) Name = Name.Replace(":", " "); - if (Name.IndexOf('/') > -1) Name = Name.Replace("/", " "); - if (Name.IndexOf('\\') > -1) Name = Name.Replace("\\", " "); - if (Name.IndexOf('?') > -1) Name = Name.Replace("?", " "); - if (Name.IndexOf('[') > -1) Name = Name.Replace("[", " "); - if (Name.IndexOf(']') > -1) Name = Name.Replace("]", " "); - } - - if (Name.Trim() == "") - { - throw new ArgumentException("The worksheet can not have an empty name"); - } - if (Name.Length > 31) Name = Name.Substring(0, 31); //A sheet can have max 31 char's - return Name; - } - /// <summary> - /// Validate the sheetname - /// </summary> - /// <param name="Name">The Name</param> - /// <returns>True if valid</returns> - private bool ValidateName(string Name) - { - return System.Text.RegularExpressions.Regex.IsMatch(Name, @":|\?|/|\\|\[|\]"); - } - - /// <summary> - /// Creates the XML document representing a new empty worksheet - /// </summary> - /// <returns></returns> - internal XmlDocument CreateNewWorksheet(bool isChart) - { - XmlDocument xmlDoc = new XmlDocument(); - XmlElement elemWs = xmlDoc.CreateElement(isChart ? "chartsheet" : "worksheet", ExcelPackage.schemaMain); - elemWs.SetAttribute("xmlns:r", ExcelPackage.schemaRelationships); - xmlDoc.AppendChild(elemWs); - - - if (isChart) - { - XmlElement elemSheetPr = xmlDoc.CreateElement("sheetPr", ExcelPackage.schemaMain); - elemWs.AppendChild(elemSheetPr); - - XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage.schemaMain); - elemWs.AppendChild(elemSheetViews); - - XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage.schemaMain); - elemSheetView.SetAttribute("workbookViewId", "0"); - elemSheetView.SetAttribute("zoomToFit", "1"); - - elemSheetViews.AppendChild(elemSheetView); - } - else - { - XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage.schemaMain); - elemWs.AppendChild(elemSheetViews); - - XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage.schemaMain); - elemSheetView.SetAttribute("workbookViewId", "0"); - elemSheetViews.AppendChild(elemSheetView); - - XmlElement elemSheetFormatPr = xmlDoc.CreateElement("sheetFormatPr", ExcelPackage.schemaMain); - elemSheetFormatPr.SetAttribute("defaultRowHeight", "15"); - elemWs.AppendChild(elemSheetFormatPr); - - XmlElement elemSheetData = xmlDoc.CreateElement("sheetData", ExcelPackage.schemaMain); - elemWs.AppendChild(elemSheetData); - } - return xmlDoc; - } - #endregion - - /// <summary> - /// Returns the worksheet at the specified position. - /// </summary> - /// <param name="PositionID">The position of the worksheet. 1-base</param> - /// <returns></returns> - public ExcelWorksheet this[int PositionID] - { - get - { - if (_worksheets.ContainsKey(PositionID)) - { - return _worksheets[PositionID]; - } - else - { - throw (new IndexOutOfRangeException("Worksheet position out of range.")); - } - } - } - - /// <summary> - /// Returns the worksheet matching the specified name - /// </summary> - /// <param name="Name">The name of the worksheet</param> - /// <returns></returns> - public ExcelWorksheet this[string Name] - { - get - { - return GetByName(Name); - } - } - #endregion - internal ExcelWorksheet GetBySheetID(int localSheetID) - { - foreach (ExcelWorksheet ws in this) - { - if (ws.SheetID == localSheetID) - { - return ws; - } - } - return null; - } - private ExcelWorksheet GetByName(string Name) - { - if (string.IsNullOrEmpty(Name)) return null; - ExcelWorksheet xlWorksheet = null; - foreach (ExcelWorksheet worksheet in _worksheets.Values) - { - if (worksheet.Name.Equals(Name, StringComparison.InvariantCultureIgnoreCase)) - xlWorksheet = worksheet; - } - return (xlWorksheet); - } - #region MoveBefore and MoveAfter Methods - /// <summary> - /// Moves the source worksheet to the position before the target worksheet - /// </summary> - /// <param name="sourceName">The name of the source worksheet</param> - /// <param name="targetName">The name of the target worksheet</param> - public void MoveBefore(string sourceName, string targetName) - { - Move(sourceName, targetName, false); - } - - /// <summary> - /// Moves the source worksheet to the position before the target worksheet - /// </summary> - /// <param name="sourcePositionId">The id of the source worksheet</param> - /// <param name="targetPositionId">The id of the target worksheet</param> - public void MoveBefore(int sourcePositionId, int targetPositionId) - { - Move(sourcePositionId, targetPositionId, false); - } - - /// <summary> - /// Moves the source worksheet to the position after the target worksheet - /// </summary> - /// <param name="sourceName">The name of the source worksheet</param> - /// <param name="targetName">The name of the target worksheet</param> - public void MoveAfter(string sourceName, string targetName) - { - Move(sourceName, targetName, true); - } - - /// <summary> - /// Moves the source worksheet to the position after the target worksheet - /// </summary> - /// <param name="sourcePositionId">The id of the source worksheet</param> - /// <param name="targetPositionId">The id of the target worksheet</param> - public void MoveAfter(int sourcePositionId, int targetPositionId) - { - Move(sourcePositionId, targetPositionId, true); - } - - /// <summary> - /// - /// </summary> - /// <param name="sourceName"></param> - public void MoveToStart(string sourceName) - { - var sourceSheet = this[sourceName]; - if (sourceSheet == null) - { - throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", sourceName)); - } - Move(sourceSheet.PositionID, 1, false); - } - - /// <summary> - /// - /// </summary> - /// <param name="sourcePositionId"></param> - public void MoveToStart(int sourcePositionId) - { - Move(sourcePositionId, 1, false); - } - - /// <summary> - /// - /// </summary> - /// <param name="sourceName"></param> - public void MoveToEnd(string sourceName) - { - var sourceSheet = this[sourceName]; - if (sourceSheet == null) - { - throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", sourceName)); - } - Move(sourceSheet.PositionID, _worksheets.Count, true); - } - - /// <summary> - /// - /// </summary> - /// <param name="sourcePositionId"></param> - public void MoveToEnd(int sourcePositionId) - { - Move(sourcePositionId, _worksheets.Count, true); - } - - private void Move(string sourceName, string targetName, bool placeAfter) - { - var sourceSheet = this[sourceName]; - if (sourceSheet == null) - { - throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", sourceName)); - } - var targetSheet = this[targetName]; - if (targetSheet == null) - { - throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", targetName)); - } - Move(sourceSheet.PositionID, targetSheet.PositionID, placeAfter); - } - - private void Move(int sourcePositionId, int targetPositionId, bool placeAfter) - { - // Bugfix: if source and target are the same worksheet the following code will create a duplicate - // which will cause a corrupt workbook. /swmal 2014-05-10 - if (sourcePositionId == targetPositionId) return; - - lock (_worksheets) - { - var sourceSheet = this[sourcePositionId]; - if (sourceSheet == null) - { - throw new Exception(string.Format("Move worksheet error: Could not find worksheet at position '{0}'", sourcePositionId)); - } - var targetSheet = this[targetPositionId]; - if (targetSheet == null) - { - throw new Exception(string.Format("Move worksheet error: Could not find worksheet at position '{0}'", targetPositionId)); - } - if (sourcePositionId == targetPositionId && _worksheets.Count < 2) - { - return; //--- no reason to attempt to re-arrange a single item with itself - } - - var index = 1; - var newOrder = new Dictionary<int, ExcelWorksheet>(); - foreach (var entry in _worksheets) - { - if (entry.Key == targetPositionId) - { - if (!placeAfter) - { - sourceSheet.PositionID = index; - newOrder.Add(index++, sourceSheet); - } - - entry.Value.PositionID = index; - newOrder.Add(index++, entry.Value); - - if (placeAfter) - { - sourceSheet.PositionID = index; - newOrder.Add(index++, sourceSheet); - } - } - else if (entry.Key == sourcePositionId) - { - //--- do nothing - } - else - { - entry.Value.PositionID = index; - newOrder.Add(index++, entry.Value); - } - } - _worksheets = newOrder; - - MoveSheetXmlNode(sourceSheet, targetSheet, placeAfter); - } - } - - private void MoveSheetXmlNode(ExcelWorksheet sourceSheet, ExcelWorksheet targetSheet, bool placeAfter) - { - lock (TopNode.OwnerDocument) - { - var sourceNode = TopNode.SelectSingleNode(string.Format("d:sheet[@sheetId = '{0}']", sourceSheet.SheetID), _namespaceManager); - var targetNode = TopNode.SelectSingleNode(string.Format("d:sheet[@sheetId = '{0}']", targetSheet.SheetID), _namespaceManager); - if (sourceNode == null || targetNode == null) - { - throw new Exception("Source SheetId and Target SheetId must be valid"); - } - if (placeAfter) - { - TopNode.InsertAfter(sourceNode, targetNode); - } - else - { - TopNode.InsertBefore(sourceNode, targetNode); - } - } - } - - #endregion - } // end class Worksheets -} + private void MoveSheetXmlNode( + ExcelWorksheet sourceSheet, + ExcelWorksheet targetSheet, + bool placeAfter) { + lock (TopNode.OwnerDocument) { + var sourceNode = TopNode.SelectSingleNode( + string.Format("d:sheet[@sheetId = '{0}']", sourceSheet.SheetID), + _namespaceManager); + var targetNode = TopNode.SelectSingleNode( + string.Format("d:sheet[@sheetId = '{0}']", targetSheet.SheetID), + _namespaceManager); + if (sourceNode == null || targetNode == null) { + throw new("Source SheetId and Target SheetId must be valid"); + } + if (placeAfter) { + TopNode.InsertAfter(sourceNode, targetNode); + } else { + TopNode.InsertBefore(sourceNode, targetNode); + } + } + } +} // end class Worksheets
diff --git a/EPPlus/FormulaParsing/CalculateExtentions.cs b/EPPlus/FormulaParsing/CalculateExtentions.cs index 69bc3ee..9cb1c28 100644 --- a/EPPlus/FormulaParsing/CalculateExtentions.cs +++ b/EPPlus/FormulaParsing/CalculateExtentions.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,193 +13,181 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** - * Jan Källman Added 2012-03-04 + * Jan Källman Added 2012-03-04 *******************************************************************************/ -using System.Threading; -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using System; using System.Collections.Generic; -using System.Linq; +using System.IO; using System.Text; using OfficeOpenXml.FormulaParsing; +using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Exceptions; -using System.IO; -namespace OfficeOpenXml -{ - public static class CalculationExtension - { - public static void Calculate(this ExcelWorkbook workbook) - { - Calculate(workbook, new ExcelCalculationOption(){AllowCirculareReferences=false}); - } - public static void Calculate(this ExcelWorkbook workbook, ExcelCalculationOption options) - { - Init(workbook); +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; - var dc = DependencyChainFactory.Create(workbook, options); - workbook.FormulaParser.InitNewCalc(); - CalcChain(workbook, workbook.FormulaParser, dc); - } - public static void Calculate(this ExcelWorksheet worksheet) - { - Calculate(worksheet, new ExcelCalculationOption()); - } - public static void Calculate(this ExcelWorksheet worksheet, ExcelCalculationOption options) - { - Init(worksheet.Workbook); - //worksheet.Workbook._formulaParser = null; TODO:Cant reset. Don't work with userdefined or overrided worksheet functions - var dc = DependencyChainFactory.Create(worksheet, options); +namespace OfficeOpenXml; - // Display Calc Chain to determine why formula calculation is taking so long. - // Uncomment the following line to display the Calc Chain. - // DisplayCalcChain(worksheet, dc); +public static class CalculationExtension { + public static void Calculate(this ExcelWorkbook workbook) { + Calculate( + workbook, + new() { + AllowCirculareReferences = false, + }); + } - var parser = worksheet.Workbook.FormulaParser; - parser.InitNewCalc(); - CalcChain(worksheet.Workbook, parser, dc); - } + public static void Calculate(this ExcelWorkbook workbook, ExcelCalculationOption options) { + Init(workbook); - // I added this method in December 2019 to analyze why formula calculation was taking - // so long during a 'Regenerate' of a Microsoft Excel table. - private static void DisplayCalcChain(ExcelWorksheet worksheet, DependencyChain dc) - { - // Open Output file - string outputFolderName = @"C:\\EPPlus"; - Directory.CreateDirectory(outputFolderName); - DateTime invocationDateTime = DateTime.Now; - string outputFileName = Path.Combine(outputFolderName, $"CalcChain_{worksheet.Name}_{invocationDateTime.ToString("yyyyMMdd_HHmmss_fff")}.txt"); - FileStream fileStream = new FileStream(outputFileName, FileMode.CreateNew); - StreamWriter streamWriter = new System.IO.StreamWriter(fileStream, Encoding.UTF8, 65536); + var dc = DependencyChainFactory.Create(workbook, options); + workbook.FormulaParser.InitNewCalc(); + CalcChain(workbook, workbook.FormulaParser, dc); + } - // Display CalcChain - foreach (int index in dc.CalcOrder) - { - FormulaCell formulaCell = dc.list[index]; - string calcChainValue = ""; - calcChainValue += $"Index {index}, "; - calcChainValue += $"Worksheet '{formulaCell.ws.Name}', "; - calcChainValue += $"Row {formulaCell.Row}, "; - calcChainValue += $"Col {formulaCell.Column}, "; - calcChainValue += $" Formula '{formulaCell.Formula}'"; - streamWriter.WriteLine(calcChainValue); - } + public static void Calculate(this ExcelWorksheet worksheet) { + Calculate(worksheet, new ExcelCalculationOption()); + } - // Close Output file - streamWriter.Flush(); - streamWriter.Close(); - } + public static void Calculate(this ExcelWorksheet worksheet, ExcelCalculationOption options) { + Init(worksheet.Workbook); + //worksheet.Workbook._formulaParser = null; TODO:Cant reset. Don't work with userdefined or overrided worksheet functions + var dc = DependencyChainFactory.Create(worksheet, options); - public static void Calculate(this ExcelRangeBase range) - { - Calculate(range, new ExcelCalculationOption()); - } - public static void Calculate(this ExcelRangeBase range, ExcelCalculationOption options) - { - Init(range._workbook); - var parser = range._workbook.FormulaParser; - parser.InitNewCalc(); - var dc = DependencyChainFactory.Create(range, options); - CalcChain(range._workbook, parser, dc); - } - public static object Calculate(this ExcelWorksheet worksheet, string Formula) - { - return Calculate(worksheet, Formula, new ExcelCalculationOption()); - } - public static object Calculate(this ExcelWorksheet worksheet, string Formula, ExcelCalculationOption options) - { - try - { - worksheet.CheckSheetType(); - if(string.IsNullOrEmpty(Formula.Trim())) return null; - Init(worksheet.Workbook); - var parser = worksheet.Workbook.FormulaParser; - parser.InitNewCalc(); - if (Formula[0] == '=') Formula = Formula.Substring(1); //Remove any starting equal sign - var dc = DependencyChainFactory.Create(worksheet, Formula, options); - var f = dc.list[0]; - dc.CalcOrder.RemoveAt(dc.CalcOrder.Count - 1); + // Display Calc Chain to determine why formula calculation is taking so long. + // Uncomment the following line to display the Calc Chain. + // DisplayCalcChain(worksheet, dc); - CalcChain(worksheet.Workbook, parser, dc); + var parser = worksheet.Workbook.FormulaParser; + parser.InitNewCalc(); + CalcChain(worksheet.Workbook, parser, dc); + } - return parser.ParseCell(f.Tokens, worksheet.Name, -1, -1); - } - catch (Exception ex) - { - return new ExcelErrorValueException(ex.Message, ExcelErrorValue.Create(eErrorType.Value)); - } - } - private static void CalcChain(ExcelWorkbook wb, FormulaParser parser, DependencyChain dc) - { - foreach (var ix in dc.CalcOrder) - { - var item = dc.list[ix]; - try - { - var ws = wb.Worksheets.GetBySheetID(item.SheetID); - var v = parser.ParseCell(item.Tokens, ws == null ? "" : ws.Name, item.Row, item.Column); - SetValue(wb, item, v); - } - catch (OfficeOpenXml.FormulaParsing.Excel.Functions.FunctionException) - { - // Excel function is not supported by EPPlus - throw; - } - catch (FormatException) - { - throw; - } - catch (Exception) - { - var error = ExcelErrorValue.Parse(ExcelErrorValue.Values.Value); - SetValue(wb, item, error); - } - } - } - private static void Init(ExcelWorkbook workbook) - { - workbook._formulaTokens = new CellStore<List<Token>>();; - foreach (var ws in workbook.Worksheets) - { - if (!(ws is ExcelChartsheet)) - { - ws._formulaTokens = new CellStore<List<Token>>(); - } - } - } + // I added this method in December 2019 to analyze why formula calculation was taking + // so long during a 'Regenerate' of a Microsoft Excel table. + private static void DisplayCalcChain(ExcelWorksheet worksheet, DependencyChain dc) { + // Open Output file + string outputFolderName = @"C:\\EPPlus"; + Directory.CreateDirectory(outputFolderName); + DateTime invocationDateTime = DateTime.Now; + string outputFileName = Path.Combine( + outputFolderName, + $"CalcChain_{worksheet.Name}_{invocationDateTime.ToString("yyyyMMdd_HHmmss_fff")}.txt"); + FileStream fileStream = new FileStream(outputFileName, FileMode.CreateNew); + StreamWriter streamWriter = new StreamWriter(fileStream, Encoding.UTF8, 65536); - private static void SetValue(ExcelWorkbook workbook, FormulaCell item, object v) - { - if (item.Column == 0) - { - if (item.SheetID <= 0) - { - workbook.Names[item.Row].NameValue = v; - } - else - { - var sh = workbook.Worksheets.GetBySheetID(item.SheetID); - sh.Names[item.Row].NameValue = v; - } - } - else - { - var sheet = workbook.Worksheets.GetBySheetID(item.SheetID); - sheet._values.SetValue(item.Row, item.Column, v); - } - } + // Display CalcChain + foreach (int index in dc.CalcOrder) { + FormulaCell formulaCell = dc.list[index]; + string calcChainValue = ""; + calcChainValue += $"Index {index}, "; + calcChainValue += $"Worksheet '{formulaCell.ws.Name}', "; + calcChainValue += $"Row {formulaCell.Row}, "; + calcChainValue += $"Col {formulaCell.Column}, "; + calcChainValue += $" Formula '{formulaCell.Formula}'"; + streamWriter.WriteLine(calcChainValue); } + + // Close Output file + streamWriter.Flush(); + streamWriter.Close(); + } + + public static void Calculate(this ExcelRangeBase range) { + Calculate(range, new()); + } + + public static void Calculate(this ExcelRangeBase range, ExcelCalculationOption options) { + Init(range._workbook); + var parser = range._workbook.FormulaParser; + parser.InitNewCalc(); + var dc = DependencyChainFactory.Create(range, options); + CalcChain(range._workbook, parser, dc); + } + + public static object Calculate(this ExcelWorksheet worksheet, string formula) { + return Calculate(worksheet, formula, new()); + } + + public static object Calculate( + this ExcelWorksheet worksheet, + string formula, + ExcelCalculationOption options) { + try { + worksheet.CheckSheetType(); + if (string.IsNullOrEmpty(formula.Trim())) { + return null; + } + Init(worksheet.Workbook); + var parser = worksheet.Workbook.FormulaParser; + parser.InitNewCalc(); + if (formula[0] == '=') { + formula = formula.Substring(1); //Remove any starting equal sign + } + var dc = DependencyChainFactory.Create(worksheet, formula, options); + var f = dc.list[0]; + dc.CalcOrder.RemoveAt(dc.CalcOrder.Count - 1); + + CalcChain(worksheet.Workbook, parser, dc); + + return parser.ParseCell(f.Tokens, worksheet.Name, -1, -1); + } catch (Exception ex) { + return new ExcelErrorValueException(ex.Message, ExcelErrorValue.Create(eErrorType.Value)); + } + } + + private static void CalcChain(ExcelWorkbook wb, FormulaParser parser, DependencyChain dc) { + foreach (var ix in dc.CalcOrder) { + var item = dc.list[ix]; + try { + var ws = wb.Worksheets.GetBySheetId(item.SheetID); + var v = parser.ParseCell(item.Tokens, ws == null ? "" : ws.Name, item.Row, item.Column); + SetValue(wb, item, v); + } catch (FunctionException) { + // Excel function is not supported by EPPlus + throw; + } catch (FormatException) { + throw; + } catch (Exception) { + var error = ExcelErrorValue.Parse(ExcelErrorValue.Values.Value); + SetValue(wb, item, error); + } + } + } + + private static void Init(ExcelWorkbook workbook) { + workbook._formulaTokens = new(); + ; + foreach (var ws in workbook.Worksheets) { + if (!(ws is ExcelChartsheet)) { + ws._formulaTokens = new(); + } + } + } + + private static void SetValue(ExcelWorkbook workbook, FormulaCell item, object v) { + if (item.Column == 0) { + if (item.SheetID <= 0) { + workbook.Names[item.Row].NameValue = v; + } else { + var sh = workbook.Worksheets.GetBySheetId(item.SheetID); + sh.Names[item.Row].NameValue = v; + } + } else { + var sheet = workbook.Worksheets.GetBySheetId(item.SheetID); + sheet._values.SetValue(item.Row, item.Column, v); + } + } }
diff --git a/EPPlus/FormulaParsing/DependencyChain/DependencyChain.cs b/EPPlus/FormulaParsing/DependencyChain/DependencyChain.cs index 9bc936f..74a0a7e 100644 --- a/EPPlus/FormulaParsing/DependencyChain/DependencyChain.cs +++ b/EPPlus/FormulaParsing/DependencyChain/DependencyChain.cs
@@ -1,17 +1,15 @@ using System.Collections.Generic; -namespace OfficeOpenXml.FormulaParsing -{ - internal class DependencyChain - { - internal List<FormulaCell> list = new List<FormulaCell>(); - internal Dictionary<ulong, int> index = new Dictionary<ulong, int>(); - internal List<int> CalcOrder = new List<int>(); - internal void Add(FormulaCell f) - { - list.Add(f); - f.Index = list.Count - 1; - index.Add(ExcelCellBase.GetCellID(f.SheetID, f.Row, f.Column), f.Index); - } - } -} \ No newline at end of file +namespace OfficeOpenXml.FormulaParsing; + +internal class DependencyChain { + internal List<FormulaCell> list = new(); + internal Dictionary<ulong, int> index = new(); + internal List<int> CalcOrder = new(); + + internal void Add(FormulaCell f) { + list.Add(f); + f.Index = list.Count - 1; + index.Add(ExcelCellBase.GetCellId(f.SheetID, f.Row, f.Column), f.Index); + } +}
diff --git a/EPPlus/FormulaParsing/DependencyChain/DependenyChainFactory.cs b/EPPlus/FormulaParsing/DependencyChain/DependenyChainFactory.cs index c150817..bd3bbd9 100644 --- a/EPPlus/FormulaParsing/DependencyChain/DependenyChainFactory.cs +++ b/EPPlus/FormulaParsing/DependencyChain/DependenyChainFactory.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,354 +13,363 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** - * Jan Källman Added 2012-03-04 + * Jan Källman Added 2012-03-04 *******************************************************************************/ -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.Exceptions; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing -{ - internal static class DependencyChainFactory - { - internal static DependencyChain Create(ExcelWorkbook wb, ExcelCalculationOption options) - { - var depChain = new DependencyChain(); - foreach (var ws in wb.Worksheets) - { - if (!(ws is ExcelChartsheet)) - { - GetChain(depChain, wb.FormulaParser.Lexer, ws.Cells, options); - GetWorksheetNames(ws, depChain, options); - } - } - foreach (var name in wb.Names) - { - if (name.NameValue==null) - { - GetChain(depChain, wb.FormulaParser.Lexer, name, options); - } - } - return depChain; - } +namespace OfficeOpenXml.FormulaParsing; - internal static DependencyChain Create(ExcelWorksheet ws, ExcelCalculationOption options) - { - ws.CheckSheetType(); - var depChain = new DependencyChain(); - - GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws.Cells, options); - - GetWorksheetNames(ws, depChain, options); - - return depChain; - } - internal static DependencyChain Create(ExcelWorksheet ws, string Formula, ExcelCalculationOption options) - { - ws.CheckSheetType(); - var depChain = new DependencyChain(); - - GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws, Formula, options); - - return depChain; - } - - private static void GetWorksheetNames(ExcelWorksheet ws, DependencyChain depChain, ExcelCalculationOption options) - { - foreach (var name in ws.Names) - { - if (!string.IsNullOrEmpty(name.NameFormula)) - { - GetChain(depChain, ws.Workbook.FormulaParser.Lexer, name, options); - } - } - } - internal static DependencyChain Create(ExcelRangeBase range, ExcelCalculationOption options) - { - var depChain = new DependencyChain(); - - GetChain(depChain, range.Worksheet.Workbook.FormulaParser.Lexer, range, options); - - return depChain; - } - private static void GetChain(DependencyChain depChain, ILexer lexer, ExcelNamedRange name, ExcelCalculationOption options) - { - var ws = name.Worksheet; - var id = ExcelCellBase.GetCellID(ws==null?0:ws.SheetID, name.Index, 0); - if (!depChain.index.ContainsKey(id)) - { - var f = new FormulaCell() { SheetID = ws == null ? 0 : ws.SheetID, Row = name.Index, Column = 0, Formula=name.NameFormula }; - if (!string.IsNullOrEmpty(f.Formula)) - { - f.Tokens = lexer.Tokenize(f.Formula, (ws==null ? null : ws.Name)).ToList(); - if (ws == null) - { - name._workbook._formulaTokens.SetValue(name.Index, 0, f.Tokens); - } - else - { - ws._formulaTokens.SetValue(name.Index, 0, f.Tokens); - } - depChain.Add(f); - FollowChain(depChain, lexer,name._workbook, ws, f, options); - } - } - } - private static void GetChain(DependencyChain depChain, ILexer lexer, ExcelWorksheet ws, string formula, ExcelCalculationOption options) - { - var f = new FormulaCell() { SheetID = ws.SheetID, Row = -1, Column = -1 }; - f.Formula = formula; - if (!string.IsNullOrEmpty(f.Formula)) - { - f.Tokens = lexer.Tokenize(f.Formula, ws.Name).ToList(); - depChain.Add(f); - FollowChain(depChain, lexer, ws.Workbook, ws, f, options); - } - } - - private static void GetChain(DependencyChain depChain, ILexer lexer, ExcelRangeBase Range, ExcelCalculationOption options) - { - var ws = Range.Worksheet; - var fs = new CellsStoreEnumerator<object>(ws._formulas, Range.Start.Row, Range.Start.Column, Range.End.Row, Range.End.Column); - while (fs.Next()) - { - if (fs.Value == null || fs.Value.ToString().Trim() == "") continue; - var id = ExcelCellBase.GetCellID(ws.SheetID, fs.Row, fs.Column); - if (!depChain.index.ContainsKey(id)) - { - var f = new FormulaCell() { SheetID = ws.SheetID, Row = fs.Row, Column = fs.Column }; - if (fs.Value is int) - { - f.Formula = ws._sharedFormulas[(int)fs.Value].GetFormula(fs.Row, fs.Column, ws.Name); - } - else - { - f.Formula = fs.Value.ToString(); - } - if (!string.IsNullOrEmpty(f.Formula)) - { - f.Tokens = lexer.Tokenize(f.Formula, Range.Worksheet.Name).ToList(); - ws._formulaTokens.SetValue(fs.Row, fs.Column, f.Tokens); - depChain.Add(f); - FollowChain(depChain, lexer, ws.Workbook, ws, f, options); - } - } - } - } - /// <summary> - /// This method follows the calculation chain to get the order of the calculation - /// Goto (!) is used internally to prevent stackoverflow on extremly larget dependency trees (that is, many recursive formulas). - /// </summary> - /// <param name="depChain">The dependency chain object</param> - /// <param name="lexer">The formula tokenizer</param> - /// <param name="wb">The workbook where the formula comes from</param> - /// <param name="ws">The worksheet where the formula comes from</param> - /// <param name="f">The cell function object</param> - /// <param name="options">Calcultaiton options</param> - private static void FollowChain(DependencyChain depChain, ILexer lexer, ExcelWorkbook wb, ExcelWorksheet ws, FormulaCell f, ExcelCalculationOption options) - { - Stack<FormulaCell> stack = new Stack<FormulaCell>(); - iterateToken: - while (f.tokenIx < f.Tokens.Count) - { - var t = f.Tokens[f.tokenIx]; - if (t.TokenType == TokenType.ExcelAddress) - { - var adr = new ExcelFormulaAddress(t.Value); - if (adr.Table != null) - { - adr.SetRCFromTable(ws._package, new ExcelAddressBase(f.Row, f.Column, f.Row, f.Column)); - } - - if (adr.WorkSheet == null && adr.Collide(new ExcelAddressBase(f.Row, f.Column, f.Row, f.Column))!=ExcelAddressBase.eAddressCollition.No) - { - throw (new CircularReferenceException(string.Format("Circular Reference in cell {0}", ExcelAddressBase.GetAddress(f.Row, f.Column)))); - } - - if (adr._fromRow > 0 && adr._fromCol > 0) - { - if (string.IsNullOrEmpty(adr.WorkSheet)) - { - if (f.ws == null) - { - f.ws = ws; - } - else if (f.ws.SheetID != f.SheetID) - { - f.ws = wb.Worksheets.GetBySheetID(f.SheetID); - } - } - else - { - f.ws = wb.Worksheets[adr.WorkSheet]; - } - - if (f.ws != null) - { - f.iterator = new CellsStoreEnumerator<object>(f.ws._formulas, adr.Start.Row, adr.Start.Column, adr.End.Row, adr.End.Column); - goto iterateCells; - } - } - } - else if (t.TokenType == TokenType.NameValue) - { - string adrWb, adrWs, adrName; - ExcelNamedRange name; - ExcelAddressBase.SplitAddress(t.Value, out adrWb, out adrWs, out adrName, f.ws==null ? "" : f.ws.Name); - if (!string.IsNullOrEmpty(adrWs)) - { - if (f.ws == null) - { - f.ws = wb.Worksheets[adrWs]; - } - if(f.ws.Names.ContainsKey(t.Value)) - { - name = f.ws.Names[adrName]; - } - else if (wb.Names.ContainsKey(adrName)) - { - name = wb.Names[adrName]; - } - else - { - name = null; - } - if(name != null) f.ws = name.Worksheet; - } - else if (wb.Names.ContainsKey(adrName)) - { - name = wb.Names[t.Value]; - if (string.IsNullOrEmpty(adrWs)) - { - f.ws = name.Worksheet; - } - } - else - { - name = null; - } - - if (name != null) - { - - if (string.IsNullOrEmpty(name.NameFormula)) - { - if (name.NameValue == null) - { - f.iterator = new CellsStoreEnumerator<object>(f.ws._formulas, name.Start.Row, - name.Start.Column, name.End.Row, name.End.Column); - goto iterateCells; - } - } - else - { - var id = ExcelAddressBase.GetCellID(name.LocalSheetId, name.Index, 0); - - if (!depChain.index.ContainsKey(id)) - { - var rf = new FormulaCell() { SheetID = name.LocalSheetId, Row = name.Index, Column = 0 }; - rf.Formula = name.NameFormula; - rf.Tokens = name.LocalSheetId == -1 ? lexer.Tokenize(rf.Formula).ToList() : lexer.Tokenize(rf.Formula, wb.Worksheets.GetBySheetID(name.LocalSheetId).Name).ToList(); - - depChain.Add(rf); - stack.Push(f); - f = rf; - goto iterateToken; - } - else - { - if (stack.Count > 0) - { - //Check for circular references - foreach (var par in stack) - { - if (ExcelAddressBase.GetCellID(par.SheetID, par.Row, par.Column) == id) - { - throw (new CircularReferenceException(string.Format("Circular Reference in name {0}", name.Name))); - } - } - } - } - } - } - } - f.tokenIx++; - } - depChain.CalcOrder.Add(f.Index); - if (stack.Count > 0) - { - f = stack.Pop(); - goto iterateCells; - } - return; - iterateCells: - - while (f.iterator != null && f.iterator.Next()) - { - var v = f.iterator.Value; - if (v == null || v.ToString().Trim() == "") continue; - var id = ExcelAddressBase.GetCellID(f.ws.SheetID, f.iterator.Row, f.iterator.Column); - if (!depChain.index.ContainsKey(id)) - { - var rf = new FormulaCell() { SheetID = f.ws.SheetID, Row = f.iterator.Row, Column = f.iterator.Column }; - if (f.iterator.Value is int) - { - rf.Formula = f.ws._sharedFormulas[(int)v].GetFormula(f.iterator.Row, f.iterator.Column, ws.Name); - } - else - { - rf.Formula = v.ToString(); - } - rf.ws = f.ws; - rf.Tokens = lexer.Tokenize(rf.Formula, f.ws.Name).ToList(); - ws._formulaTokens.SetValue(rf.Row, rf.Column, rf.Tokens); - depChain.Add(rf); - stack.Push(f); - f = rf; - goto iterateToken; - } - else - { - if (stack.Count > 0) - { - //Check for circular references - foreach (var par in stack) - { - if (ExcelAddressBase.GetCellID(par.ws.SheetID, par.iterator.Row, par.iterator.Column) == id) - { - if (options.AllowCirculareReferences == false) - { - throw (new CircularReferenceException(string.Format("Circular Reference in cell {0}!{1}", par.ws.Name, ExcelAddress.GetAddress(f.Row, f.Column)))); - } - else - { - f = stack.Pop(); - goto iterateCells; - } - } - } - } - } - } - f.tokenIx++; - goto iterateToken; - } +internal static class DependencyChainFactory { + internal static DependencyChain Create(ExcelWorkbook wb, ExcelCalculationOption options) { + var depChain = new DependencyChain(); + foreach (var ws in wb.Worksheets) { + if (!(ws is ExcelChartsheet)) { + GetChain(depChain, wb.FormulaParser.Lexer, ws.Cells, options); + GetWorksheetNames(ws, depChain, options); + } } + foreach (var name in wb.Names) { + if (name.NameValue == null) { + GetChain(depChain, wb.FormulaParser.Lexer, name, options); + } + } + return depChain; + } + + internal static DependencyChain Create(ExcelWorksheet ws, ExcelCalculationOption options) { + ws.CheckSheetType(); + var depChain = new DependencyChain(); + + GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws.Cells, options); + + GetWorksheetNames(ws, depChain, options); + + return depChain; + } + + internal static DependencyChain Create( + ExcelWorksheet ws, + string formula, + ExcelCalculationOption options) { + ws.CheckSheetType(); + var depChain = new DependencyChain(); + + GetChain(depChain, ws.Workbook.FormulaParser.Lexer, ws, formula, options); + + return depChain; + } + + private static void GetWorksheetNames( + ExcelWorksheet ws, + DependencyChain depChain, + ExcelCalculationOption options) { + foreach (var name in ws.Names) { + if (!string.IsNullOrEmpty(name.NameFormula)) { + GetChain(depChain, ws.Workbook.FormulaParser.Lexer, name, options); + } + } + } + + internal static DependencyChain Create(ExcelRangeBase range, ExcelCalculationOption options) { + var depChain = new DependencyChain(); + + GetChain(depChain, range.Worksheet.Workbook.FormulaParser.Lexer, range, options); + + return depChain; + } + + private static void GetChain( + DependencyChain depChain, + ILexer lexer, + ExcelNamedRange name, + ExcelCalculationOption options) { + var ws = name.Worksheet; + var id = ExcelCellBase.GetCellId(ws == null ? 0 : ws.SheetID, name.Index, 0); + if (!depChain.index.ContainsKey(id)) { + var f = new FormulaCell { + SheetID = ws == null ? 0 : ws.SheetID, + Row = name.Index, + Column = 0, + Formula = name.NameFormula, + }; + if (!string.IsNullOrEmpty(f.Formula)) { + f.Tokens = lexer.Tokenize(f.Formula, (ws == null ? null : ws.Name)).ToList(); + if (ws == null) { + name._workbook._formulaTokens.SetValue(name.Index, 0, f.Tokens); + } else { + ws._formulaTokens.SetValue(name.Index, 0, f.Tokens); + } + depChain.Add(f); + FollowChain(depChain, lexer, name._workbook, ws, f, options); + } + } + } + + private static void GetChain( + DependencyChain depChain, + ILexer lexer, + ExcelWorksheet ws, + string formula, + ExcelCalculationOption options) { + var f = new FormulaCell { + SheetID = ws.SheetID, + Row = -1, + Column = -1, + }; + f.Formula = formula; + if (!string.IsNullOrEmpty(f.Formula)) { + f.Tokens = lexer.Tokenize(f.Formula, ws.Name).ToList(); + depChain.Add(f); + FollowChain(depChain, lexer, ws.Workbook, ws, f, options); + } + } + + private static void GetChain( + DependencyChain depChain, + ILexer lexer, + ExcelRangeBase range, + ExcelCalculationOption options) { + var ws = range.Worksheet; + var fs = new CellsStoreEnumerator<object>( + ws._formulas, + range.Start.Row, + range.Start.Column, + range.End.Row, + range.End.Column); + while (fs.Next()) { + if (fs.Value == null || fs.Value.ToString().Trim() == "") { + continue; + } + var id = ExcelCellBase.GetCellId(ws.SheetID, fs.Row, fs.Column); + if (!depChain.index.ContainsKey(id)) { + var f = new FormulaCell { + SheetID = ws.SheetID, + Row = fs.Row, + Column = fs.Column, + }; + if (fs.Value is int) { + f.Formula = ws._sharedFormulas[(int)fs.Value].GetFormula(fs.Row, fs.Column, ws.Name); + } else { + f.Formula = fs.Value.ToString(); + } + if (!string.IsNullOrEmpty(f.Formula)) { + f.Tokens = lexer.Tokenize(f.Formula, range.Worksheet.Name).ToList(); + ws._formulaTokens.SetValue(fs.Row, fs.Column, f.Tokens); + depChain.Add(f); + FollowChain(depChain, lexer, ws.Workbook, ws, f, options); + } + } + } + } + + /// <summary> + /// This method follows the calculation chain to get the order of the calculation + /// Goto (!) is used internally to prevent stackoverflow on extremly larget dependency trees (that is, many recursive formulas). + /// </summary> + /// <param name="depChain">The dependency chain object</param> + /// <param name="lexer">The formula tokenizer</param> + /// <param name="wb">The workbook where the formula comes from</param> + /// <param name="ws">The worksheet where the formula comes from</param> + /// <param name="f">The cell function object</param> + /// <param name="options">Calcultaiton options</param> + private static void FollowChain( + DependencyChain depChain, + ILexer lexer, + ExcelWorkbook wb, + ExcelWorksheet ws, + FormulaCell f, + ExcelCalculationOption options) { + Stack<FormulaCell> stack = new Stack<FormulaCell>(); + iterateToken: + while (f.tokenIx < f.Tokens.Count) { + var t = f.Tokens[f.tokenIx]; + if (t.TokenType == TokenType.ExcelAddress) { + var adr = new ExcelFormulaAddress(t.Value); + if (adr.Table != null) { + adr.SetRcFromTable(ws._package, new(f.Row, f.Column, f.Row, f.Column)); + } + + if (adr.WorkSheet == null + && adr.Collide(new(f.Row, f.Column, f.Row, f.Column)) + != ExcelAddressBase.eAddressCollition.No) { + throw (new CircularReferenceException( + string.Format( + "Circular Reference in cell {0}", + ExcelCellBase.GetAddress(f.Row, f.Column)))); + } + + if (adr._fromRow > 0 && adr._fromCol > 0) { + if (string.IsNullOrEmpty(adr.WorkSheet)) { + if (f.ws == null) { + f.ws = ws; + } else if (f.ws.SheetID != f.SheetID) { + f.ws = wb.Worksheets.GetBySheetId(f.SheetID); + } + } else { + f.ws = wb.Worksheets[adr.WorkSheet]; + } + + if (f.ws != null) { + f.iterator = new( + f.ws._formulas, + adr.Start.Row, + adr.Start.Column, + adr.End.Row, + adr.End.Column); + goto iterateCells; + } + } + } else if (t.TokenType == TokenType.NameValue) { + string adrWb, + adrWs, + adrName; + ExcelNamedRange name; + ExcelAddressBase.SplitAddress( + t.Value, + out adrWb, + out adrWs, + out adrName, + f.ws == null ? "" : f.ws.Name); + if (!string.IsNullOrEmpty(adrWs)) { + if (f.ws == null) { + f.ws = wb.Worksheets[adrWs]; + } + if (f.ws.Names.ContainsKey(t.Value)) { + name = f.ws.Names[adrName]; + } else if (wb.Names.ContainsKey(adrName)) { + name = wb.Names[adrName]; + } else { + name = null; + } + if (name != null) { + f.ws = name.Worksheet; + } + } else if (wb.Names.ContainsKey(adrName)) { + name = wb.Names[t.Value]; + if (string.IsNullOrEmpty(adrWs)) { + f.ws = name.Worksheet; + } + } else { + name = null; + } + + if (name != null) { + if (string.IsNullOrEmpty(name.NameFormula)) { + if (name.NameValue == null) { + f.iterator = new( + f.ws._formulas, + name.Start.Row, + name.Start.Column, + name.End.Row, + name.End.Column); + goto iterateCells; + } + } else { + var id = ExcelCellBase.GetCellId(name.LocalSheetId, name.Index, 0); + + if (!depChain.index.ContainsKey(id)) { + var rf = new FormulaCell { + SheetID = name.LocalSheetId, + Row = name.Index, + Column = 0, + }; + rf.Formula = name.NameFormula; + rf.Tokens = + name.LocalSheetId == -1 + ? lexer.Tokenize(rf.Formula).ToList() + : lexer + .Tokenize(rf.Formula, wb.Worksheets.GetBySheetId(name.LocalSheetId).Name) + .ToList(); + + depChain.Add(rf); + stack.Push(f); + f = rf; + goto iterateToken; + } + if (stack.Count > 0) { + //Check for circular references + foreach (var par in stack) { + if (ExcelCellBase.GetCellId(par.SheetID, par.Row, par.Column) == id) { + throw (new CircularReferenceException( + string.Format("Circular Reference in name {0}", name.Name))); + } + } + } + } + } + } + f.tokenIx++; + } + depChain.CalcOrder.Add(f.Index); + if (stack.Count > 0) { + f = stack.Pop(); + goto iterateCells; + } + return; + iterateCells: + + while (f.iterator != null && f.iterator.Next()) { + var v = f.iterator.Value; + if (v == null || v.ToString().Trim() == "") { + continue; + } + var id = ExcelCellBase.GetCellId(f.ws.SheetID, f.iterator.Row, f.iterator.Column); + if (!depChain.index.ContainsKey(id)) { + var rf = new FormulaCell { + SheetID = f.ws.SheetID, + Row = f.iterator.Row, + Column = f.iterator.Column, + }; + if (f.iterator.Value is int) { + rf.Formula = f.ws._sharedFormulas[(int)v] + .GetFormula(f.iterator.Row, f.iterator.Column, ws.Name); + } else { + rf.Formula = v.ToString(); + } + rf.ws = f.ws; + rf.Tokens = lexer.Tokenize(rf.Formula, f.ws.Name).ToList(); + ws._formulaTokens.SetValue(rf.Row, rf.Column, rf.Tokens); + depChain.Add(rf); + stack.Push(f); + f = rf; + goto iterateToken; + } + if (stack.Count > 0) { + //Check for circular references + foreach (var par in stack) { + if (ExcelCellBase.GetCellId(par.ws.SheetID, par.iterator.Row, par.iterator.Column) + == id) { + if (options.AllowCirculareReferences == false) { + throw (new CircularReferenceException( + string.Format( + "Circular Reference in cell {0}!{1}", + par.ws.Name, + ExcelCellBase.GetAddress(f.Row, f.Column)))); + } + f = stack.Pop(); + goto iterateCells; + } + } + } + } + f.tokenIx++; + goto iterateToken; + } }
diff --git a/EPPlus/FormulaParsing/DependencyChain/FormulaCell.cs b/EPPlus/FormulaParsing/DependencyChain/FormulaCell.cs index da92828..2b96a7d 100644 --- a/EPPlus/FormulaParsing/DependencyChain/FormulaCell.cs +++ b/EPPlus/FormulaParsing/DependencyChain/FormulaCell.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan K�llman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,37 +7,42 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing -{ - internal class FormulaCell - { - internal int Index { get; set; } - internal int SheetID { get; set; } - internal int Row { get; set; } - internal int Column { get; set; } - internal string Formula { get; set; } - internal List<Token> Tokens { get; set; } - internal int tokenIx = 0; - internal int addressIx = 0; - internal CellsStoreEnumerator<object> iterator; - internal ExcelWorksheet ws; - } -} \ No newline at end of file +namespace OfficeOpenXml.FormulaParsing; + +internal class FormulaCell { + internal int Index { get; set; } + + internal int SheetID { get; set; } + + internal int Row { get; set; } + + internal int Column { get; set; } + + internal string Formula { get; set; } + + internal List<Token> Tokens { get; set; } + + internal int tokenIx = 0; + internal int addressIx = 0; + internal CellsStoreEnumerator<object> iterator; + internal ExcelWorksheet ws; +}
diff --git a/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs b/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs index 174f303..85d297a 100644 --- a/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs +++ b/EPPlus/FormulaParsing/EpplusExcelDataProvider.cs
@@ -1,480 +1,368 @@ -using System.Collections.Generic; +using System.Collections; +using System.Collections.Generic; using System.Linq; using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -using OfficeOpenXml.Utils; using OfficeOpenXml.Style.XmlAccess; +using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing -{ - public class EpplusExcelDataProvider : ExcelDataProvider - { - public class RangeInfo : IRangeInfo - { - internal ExcelWorksheet _ws; - CellsStoreEnumerator<object> _values = null; - int _fromRow, _toRow, _fromCol, _toCol; - int _cellCount = 0; - ExcelAddressBase _address; - ICellInfo _cell; +namespace OfficeOpenXml.FormulaParsing; - public RangeInfo(ExcelWorksheet ws, int fromRow, int fromCol, int toRow, int toCol) - { - _ws = ws; - _fromRow = fromRow; - _fromCol = fromCol; - _toRow = toRow; - _toCol = toCol; - _address = new ExcelAddressBase(_fromRow, _fromCol, _toRow, _toCol); - _address._ws = ws.Name; - _values = new CellsStoreEnumerator<object>(ws._values, _fromRow, _fromCol, _toRow, _toCol); - _cell = new CellInfo(_ws, _values); - } +public class EpplusExcelDataProvider : ExcelDataProvider { + public class RangeInfo : IRangeInfo { + internal ExcelWorksheet _ws; + private CellsStoreEnumerator<object> _values; + private int _fromRow, + _toRow, + _fromCol, + _toCol; + private int _cellCount; + private ExcelAddressBase _address; + private ICellInfo _cell; - public int GetNCells() - { - return ((_toRow - _fromRow) + 1) * ((_toCol - _fromCol) + 1); - } - - public bool IsEmpty - { - get - { - if (_cellCount > 0) - { - return false; - } - else if (_values.Next()) - { - _values.Reset(); - return false; - } - else - { - return true; - } - } - } - public bool IsMulti - { - get - { - if (_cellCount == 0) - { - if (_values.Next() && _values.Next()) - { - _values.Reset(); - return true; - } - else - { - _values.Reset(); - return false; - } - } - else if (_cellCount > 1) - { - return true; - } - return false; - } - } - - public ICellInfo Current - { - get { return _cell; } - } - - public ExcelWorksheet Worksheet - { - get { return _ws; } - } - - public void Dispose() - { - } - - object System.Collections.IEnumerator.Current - { - get - { - return this; - } - } - - public bool MoveNext() - { - _cellCount++; - return _values.MoveNext(); - } - - public void Reset() - { - _values.Init(); - } - - - public bool NextCell() - { - _cellCount++; - return _values.MoveNext(); - } - - public IEnumerator<ICellInfo> GetEnumerator() - { - Reset(); - return this; - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return this; - } - - public ExcelAddressBase Address - { - get { return _address; } - } - - public object GetValue(int row, int col) - { - return _ws.GetValue(row, col); - } - - public object GetOffset(int rowOffset, int colOffset) - { - if (_values.Row < _fromRow || _values.Column < _fromCol) - { - return _ws.GetValue(_fromRow + rowOffset, _fromCol + colOffset); - } - else - { - return _ws.GetValue(_values.Row + rowOffset, _values.Column + colOffset); - } - } - } - - public class CellInfo : ICellInfo - { - ExcelWorksheet _ws; - CellsStoreEnumerator<object> _values; - internal CellInfo(ExcelWorksheet ws, CellsStoreEnumerator<object> values) - { - _ws = ws; - _values = values; - } - public string Address - { - get { return _values.CellAddress; } - } - - public int Row - { - get { return _values.Row; } - } - - public int Column - { - get { return _values.Column; } - } - - public string Formula - { - get - { - return _ws.GetFormula(_values.Row, _values.Column); - } - } - - public object Value - { - get { return _values.Value; } - } - - public double ValueDouble - { - get { return ConvertUtil.GetValueDouble(_values.Value, true); } - } - public double ValueDoubleLogical - { - get { return ConvertUtil.GetValueDouble(_values.Value, false); } - } - public bool IsHiddenRow - { - get - { - var row=_ws._values.GetValue(_values.Row, 0) as RowInternal; - if(row != null) - { - return row.Hidden || row.Height==0; - } - else - { - return false; - } - } - } - - public bool IsExcelError - { - get { return ExcelErrorValue.Values.IsErrorValue(_values.Value); } - } - - public IList<Token> Tokens - { - get - { - return _ws._formulaTokens.GetValue(_values.Row, _values.Column); - } - } - - } - public class NameInfo : ExcelDataProvider.INameInfo - { - public ulong Id { get; set; } - public string Worksheet { get; set; } - public string Name { get; set; } - public string Formula { get; set; } - public IList<Token> Tokens { get; internal set; } - public object Value { get; set; } - } - - private readonly ExcelPackage _package; - private ExcelWorksheet _currentWorksheet; - private RangeAddressFactory _rangeAddressFactory; - private Dictionary<ulong, INameInfo> _names=new Dictionary<ulong,INameInfo>(); - - public EpplusExcelDataProvider(ExcelPackage package) - { - _package = package; - - _rangeAddressFactory = new RangeAddressFactory(this); - } - - public override ExcelNamedRangeCollection GetWorksheetNames(string worksheet) - { - var ws=_package.Workbook.Worksheets[worksheet]; - if (ws != null) - { - return ws.Names; - } - else - { - return null; - } - } - - public override ExcelNamedRangeCollection GetWorkbookNameValues() - { - return _package.Workbook.Names; - } - - public override IRangeInfo GetRange(string worksheet, int fromRow, int fromCol, int toRow, int toCol) - { - SetCurrentWorksheet(worksheet); - var wsName = string.IsNullOrEmpty(worksheet) ? _currentWorksheet.Name : worksheet; - var ws = _package.Workbook.Worksheets[wsName]; - return new RangeInfo(ws, fromRow, fromCol, toRow, toCol); - } - public override IRangeInfo GetRange(string worksheet, int row, int column, string address) - { - var addr = new ExcelAddress(worksheet, address); - if (addr.Table != null) - { - addr.SetRCFromTable(_package, new ExcelAddressBase(row, column, row, column)); - } - //SetCurrentWorksheet(addr.WorkSheet); - var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet; - var ws = _package.Workbook.Worksheets[wsName]; - //return new CellsStoreEnumerator<object>(ws._values, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol); - return new RangeInfo(ws, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol); - } - public override INameInfo GetName(string worksheet, string name) - { - ExcelNamedRange nameItem; - ulong id; - ExcelWorksheet ws; - if (string.IsNullOrEmpty(worksheet)) - { - if(_package.Workbook.Names.ContainsKey(name)) - { - nameItem = _package.Workbook.Names[name]; - } - else - { - return null; - } - ws = null; - } - else - { - ws = _package.Workbook.Worksheets[worksheet]; - if (ws !=null && ws.Names.ContainsKey(name)) - { - nameItem = ws.Names[name]; - } - else if (_package.Workbook.Names.ContainsKey(name)) - { - nameItem = _package.Workbook.Names[name]; - } - else - { - return null; - } - } - id = ExcelAddressBase.GetCellID(nameItem.LocalSheetId, nameItem.Index, 0); - - if (_names.ContainsKey(id)) - { - return _names[id]; - } - else - { - var ni = new NameInfo() - { - Id = id, - Name = name, - Worksheet = nameItem.Worksheet==null ? nameItem._ws : nameItem.Worksheet.Name, - Formula = nameItem.Formula - }; - if (nameItem._fromRow > 0) - { - ni.Value = new RangeInfo(nameItem.Worksheet ?? ws, nameItem._fromRow, nameItem._fromCol, nameItem._toRow, nameItem._toCol); - } - else - { - ni.Value = nameItem.Value; - } - _names.Add(id, ni); - return ni; - } - } - public override IEnumerable<object> GetRangeValues(string address) - { - SetCurrentWorksheet(ExcelAddressInfo.Parse(address)); - var addr = new ExcelAddress(address); - var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet; - var ws = _package.Workbook.Worksheets[wsName]; - return (new CellsStoreEnumerator<object>(ws._values, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol)); - } - - - public object GetValue(int row, int column) - { - return _currentWorksheet._values.GetValue(row, column); - } - - public bool IsMerged(int row, int column) - { - //return _currentWorksheet._flags.GetFlagValue(row, column, CellFlags.Merged); - return _currentWorksheet.MergedCells[row, column] != null; - } - - public bool IsHidden(int row, int column) - { - return _currentWorksheet.Column(column).Hidden || _currentWorksheet.Column(column).Width == 0 || - _currentWorksheet.Row(row).Hidden || _currentWorksheet.Row(column).Height == 0; - } - - public override object GetCellValue(string sheetName, int row, int col) - { - SetCurrentWorksheet(sheetName); - return _currentWorksheet._values.GetValue(row, col); - } - - public override ExcelCellAddress GetDimensionEnd(string worksheet) - { - ExcelCellAddress address = null; - try - { - address = _package.Workbook.Worksheets[worksheet].Dimension.End; - } - catch{} - - return address; - } - - private void SetCurrentWorksheet(ExcelAddressInfo addressInfo) - { - if (addressInfo.WorksheetIsSpecified) - { - _currentWorksheet = _package.Workbook.Worksheets[addressInfo.Worksheet]; - } - else if (_currentWorksheet == null) - { - _currentWorksheet = _package.Workbook.Worksheets.First(); - } - } - - private void SetCurrentWorksheet(string worksheetName) - { - if (!string.IsNullOrEmpty(worksheetName)) - { - _currentWorksheet = _package.Workbook.Worksheets[worksheetName]; - } - else - { - _currentWorksheet = _package.Workbook.Worksheets.First(); - } - - } - - public override int ExcelMaxColumns - { - get { return ExcelPackage.MaxColumns; } - } - - public override int ExcelMaxRows - { - get { return ExcelPackage.MaxRows; } - } - - public override string GetRangeFormula(string worksheetName, int row, int column) - { - SetCurrentWorksheet(worksheetName); - return _currentWorksheet.GetFormula(row, column); - } - - public override object GetRangeValue(string worksheetName, int row, int column) - { - SetCurrentWorksheet(worksheetName); - return _currentWorksheet.GetValue(row, column); - } - public override string GetFormat(object value, string format) - { - var styles = _package.Workbook.Styles; - ExcelNumberFormatXml.ExcelFormatTranslator ft=null; - foreach(var f in styles.NumberFormats) - { - if(f.Format==format) - { - ft=f.FormatTranslator; - break; - } - } - if(ft==null) - { - ft=new ExcelNumberFormatXml.ExcelFormatTranslator(format, -1); - } - return ExcelRangeBase.FormatValue(value, ft,format, ft.NetFormat); - } - public override List<LexicalAnalysis.Token> GetRangeFormulaTokens(string worksheetName, int row, int column) - { - return _package.Workbook.Worksheets[worksheetName]._formulaTokens.GetValue(row, column); - } - - public override bool IsRowHidden(string worksheetName, int row) - { - var b = _package.Workbook.Worksheets[worksheetName].Row(row).Height == 0 || - _package.Workbook.Worksheets[worksheetName].Row(row).Hidden; - - return b; - } - - public override void Reset() - { - _names = new Dictionary<ulong, INameInfo>(); //Reset name cache. - } + public RangeInfo(ExcelWorksheet ws, int fromRow, int fromCol, int toRow, int toCol) { + _ws = ws; + _fromRow = fromRow; + _fromCol = fromCol; + _toRow = toRow; + _toCol = toCol; + _address = new(_fromRow, _fromCol, _toRow, _toCol); + _address._ws = ws.Name; + _values = new(ws._values, _fromRow, _fromCol, _toRow, _toCol); + _cell = new CellInfo(_ws, _values); } + + public int GetNCells() { + return ((_toRow - _fromRow) + 1) * ((_toCol - _fromCol) + 1); + } + + public bool IsEmpty { + get { + if (_cellCount > 0) { + return false; + } + if (_values.Next()) { + _values.Reset(); + return false; + } + return true; + } + } + + public bool IsMulti { + get { + if (_cellCount == 0) { + if (_values.Next() && _values.Next()) { + _values.Reset(); + return true; + } + _values.Reset(); + return false; + } + if (_cellCount > 1) { + return true; + } + return false; + } + } + + public ICellInfo Current => _cell; + + public ExcelWorksheet Worksheet { + get { return _ws; } + } + + public void Dispose() {} + + object IEnumerator.Current { + get { return this; } + } + + public bool MoveNext() { + _cellCount++; + return _values.MoveNext(); + } + + public void Reset() { + _values.Init(); + } + + public bool NextCell() { + _cellCount++; + return _values.MoveNext(); + } + + public IEnumerator<ICellInfo> GetEnumerator() { + Reset(); + return this; + } + + IEnumerator IEnumerable.GetEnumerator() { + return this; + } + + public ExcelAddressBase Address { + get { return _address; } + } + + public object GetValue(int row, int col) { + return _ws.GetValue(row, col); + } + + public object GetOffset(int rowOffset, int colOffset) { + if (_values.Row < _fromRow || _values.Column < _fromCol) { + return _ws.GetValue(_fromRow + rowOffset, _fromCol + colOffset); + } + return _ws.GetValue(_values.Row + rowOffset, _values.Column + colOffset); + } + } + + public class CellInfo : ICellInfo { + private ExcelWorksheet _ws; + private CellsStoreEnumerator<object> _values; + + internal CellInfo(ExcelWorksheet ws, CellsStoreEnumerator<object> values) { + _ws = ws; + _values = values; + } + + public string Address => _values.CellAddress; + + public int Row => _values.Row; + + public int Column => _values.Column; + + public string Formula => _ws.GetFormula(_values.Row, _values.Column); + + public object Value => _values.Value; + + public double ValueDouble => ConvertUtil.GetValueDouble(_values.Value, true); + + public double ValueDoubleLogical => ConvertUtil.GetValueDouble(_values.Value); + + public bool IsHiddenRow { + get { + var row = _ws._values.GetValue(_values.Row, 0) as RowInternal; + if (row != null) { + return row.Hidden || row.Height == 0; + } + return false; + } + } + + public bool IsExcelError => ExcelErrorValue.Values.IsErrorValue(_values.Value); + + public IList<Token> Tokens => _ws._formulaTokens.GetValue(_values.Row, _values.Column); + } + + public class NameInfo : INameInfo { + public ulong Id { get; set; } + + public string Worksheet { get; set; } + + public string Name { get; set; } + + public string Formula { get; set; } + + public IList<Token> Tokens { get; internal set; } + + public object Value { get; set; } + } + + private readonly ExcelPackage _package; + private ExcelWorksheet _currentWorksheet; + private RangeAddressFactory _rangeAddressFactory; + private Dictionary<ulong, INameInfo> _names = new(); + + public EpplusExcelDataProvider(ExcelPackage package) { + _package = package; + + _rangeAddressFactory = new(this); + } + + public override ExcelNamedRangeCollection GetWorksheetNames(string worksheet) { + var ws = _package.Workbook.Worksheets[worksheet]; + if (ws != null) { + return ws.Names; + } + return null; + } + + public override ExcelNamedRangeCollection GetWorkbookNameValues() { + return _package.Workbook.Names; + } + + public override IRangeInfo GetRange( + string worksheet, + int fromRow, + int fromCol, + int toRow, + int toCol) { + SetCurrentWorksheet(worksheet); + var wsName = string.IsNullOrEmpty(worksheet) ? _currentWorksheet.Name : worksheet; + var ws = _package.Workbook.Worksheets[wsName]; + return new RangeInfo(ws, fromRow, fromCol, toRow, toCol); + } + + public override IRangeInfo GetRange(string worksheet, int row, int column, string address) { + var addr = new ExcelAddress(worksheet, address); + if (addr.Table != null) { + addr.SetRcFromTable(_package, new(row, column, row, column)); + } + //SetCurrentWorksheet(addr.WorkSheet); + var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet; + var ws = _package.Workbook.Worksheets[wsName]; + //return new CellsStoreEnumerator<object>(ws._values, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol); + return new RangeInfo(ws, addr._fromRow, addr._fromCol, addr._toRow, addr._toCol); + } + + public override INameInfo GetName(string worksheet, string name) { + ExcelNamedRange nameItem; + ulong id; + ExcelWorksheet ws; + if (string.IsNullOrEmpty(worksheet)) { + if (_package.Workbook.Names.ContainsKey(name)) { + nameItem = _package.Workbook.Names[name]; + } else { + return null; + } + ws = null; + } else { + ws = _package.Workbook.Worksheets[worksheet]; + if (ws != null && ws.Names.ContainsKey(name)) { + nameItem = ws.Names[name]; + } else if (_package.Workbook.Names.ContainsKey(name)) { + nameItem = _package.Workbook.Names[name]; + } else { + return null; + } + } + id = ExcelCellBase.GetCellId(nameItem.LocalSheetId, nameItem.Index, 0); + + if (_names.ContainsKey(id)) { + return _names[id]; + } + var ni = new NameInfo { + Id = id, + Name = name, + Worksheet = nameItem.Worksheet == null ? nameItem._ws : nameItem.Worksheet.Name, + Formula = nameItem.Formula, + }; + if (nameItem._fromRow > 0) { + ni.Value = new RangeInfo( + nameItem.Worksheet ?? ws, + nameItem._fromRow, + nameItem._fromCol, + nameItem._toRow, + nameItem._toCol); + } else { + ni.Value = nameItem.Value; + } + _names.Add(id, ni); + return ni; + } + + public override IEnumerable<object> GetRangeValues(string address) { + SetCurrentWorksheet(ExcelAddressInfo.Parse(address)); + var addr = new ExcelAddress(address); + var wsName = string.IsNullOrEmpty(addr.WorkSheet) ? _currentWorksheet.Name : addr.WorkSheet; + var ws = _package.Workbook.Worksheets[wsName]; + return (new CellsStoreEnumerator<object>( + ws._values, + addr._fromRow, + addr._fromCol, + addr._toRow, + addr._toCol)); + } + + public object GetValue(int row, int column) { + return _currentWorksheet._values.GetValue(row, column); + } + + public bool IsMerged(int row, int column) { + //return _currentWorksheet._flags.GetFlagValue(row, column, CellFlags.Merged); + return _currentWorksheet.MergedCells[row, column] != null; + } + + public bool IsHidden(int row, int column) { + return _currentWorksheet.Column(column).Hidden + || _currentWorksheet.Column(column).Width == 0 + || _currentWorksheet.Row(row).Hidden + || _currentWorksheet.Row(column).Height == 0; + } + + public override object GetCellValue(string sheetName, int row, int col) { + SetCurrentWorksheet(sheetName); + return _currentWorksheet._values.GetValue(row, col); + } + + public override ExcelCellAddress GetDimensionEnd(string worksheet) { + ExcelCellAddress address = null; + try { + address = _package.Workbook.Worksheets[worksheet].Dimension.End; + } catch {} + + return address; + } + + private void SetCurrentWorksheet(ExcelAddressInfo addressInfo) { + if (addressInfo.WorksheetIsSpecified) { + _currentWorksheet = _package.Workbook.Worksheets[addressInfo.Worksheet]; + } else if (_currentWorksheet == null) { + _currentWorksheet = _package.Workbook.Worksheets.First(); + } + } + + private void SetCurrentWorksheet(string worksheetName) { + if (!string.IsNullOrEmpty(worksheetName)) { + _currentWorksheet = _package.Workbook.Worksheets[worksheetName]; + } else { + _currentWorksheet = _package.Workbook.Worksheets.First(); + } + } + + public override int ExcelMaxColumns => ExcelPackage.MaxColumns; + + public override int ExcelMaxRows => ExcelPackage.MaxRows; + + public override string GetRangeFormula(string worksheetName, int row, int column) { + SetCurrentWorksheet(worksheetName); + return _currentWorksheet.GetFormula(row, column); + } + + public override object GetRangeValue(string worksheetName, int row, int column) { + SetCurrentWorksheet(worksheetName); + return _currentWorksheet.GetValue(row, column); + } + + public override string GetFormat(object value, string format) { + var styles = _package.Workbook.Styles; + ExcelNumberFormatXml.ExcelFormatTranslator ft = null; + foreach (var f in styles.NumberFormats) { + if (f.Format == format) { + ft = f.FormatTranslator; + break; + } + } + if (ft == null) { + ft = new(format, -1); + } + return ExcelRangeBase.FormatValue(value, ft, format, ft.NetFormat); + } + + public override List<Token> GetRangeFormulaTokens(string worksheetName, int row, int column) { + return _package.Workbook.Worksheets[worksheetName]._formulaTokens.GetValue(row, column); + } + + public override bool IsRowHidden(string worksheetName, int row) { + var b = + _package.Workbook.Worksheets[worksheetName].Row(row).Height == 0 + || _package.Workbook.Worksheets[worksheetName].Row(row).Hidden; + + return b; + } + + public override void Reset() { + _names = new(); //Reset name cache. + } } - \ No newline at end of file
diff --git a/EPPlus/FormulaParsing/EpplusNameValueProvider.cs b/EPPlus/FormulaParsing/EpplusNameValueProvider.cs index a40790e..60becec 100644 --- a/EPPlus/FormulaParsing/EpplusNameValueProvider.cs +++ b/EPPlus/FormulaParsing/EpplusNameValueProvider.cs
@@ -1,43 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing; +namespace OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing -{ - public class EpplusNameValueProvider : INameValueProvider - { - private ExcelDataProvider _excelDataProvider; - private ExcelNamedRangeCollection _values; +public class EpplusNameValueProvider : INameValueProvider { + private ExcelDataProvider _excelDataProvider; + private ExcelNamedRangeCollection _values; - public EpplusNameValueProvider(ExcelDataProvider excelDataProvider) - { - _excelDataProvider = excelDataProvider; - _values = _excelDataProvider.GetWorkbookNameValues(); - } + public EpplusNameValueProvider(ExcelDataProvider excelDataProvider) { + _excelDataProvider = excelDataProvider; + _values = _excelDataProvider.GetWorkbookNameValues(); + } - public virtual bool IsNamedValue(string key, string ws) - { - if(ws!=null) - { - var wsNames = _excelDataProvider.GetWorksheetNames(ws); - if(wsNames!=null && wsNames.ContainsKey(key)) - { - return true; - } - } - return _values != null && _values.ContainsKey(key); - } - - public virtual object GetNamedValue(string key) - { - return _values[key]; - } - - public virtual void Reload() - { - _values = _excelDataProvider.GetWorkbookNameValues(); - } + public virtual bool IsNamedValue(string key, string ws) { + if (ws != null) { + var wsNames = _excelDataProvider.GetWorksheetNames(ws); + if (wsNames != null && wsNames.ContainsKey(key)) { + return true; + } } + return _values != null && _values.ContainsKey(key); + } + + public virtual object GetNamedValue(string key) { + return _values[key]; + } + + public virtual void Reload() { + _values = _excelDataProvider.GetWorkbookNameValues(); + } }
diff --git a/EPPlus/FormulaParsing/Excel/ExcelCellState.cs b/EPPlus/FormulaParsing/Excel/ExcelCellState.cs index 7a6556d..3551b8a 100644 --- a/EPPlus/FormulaParsing/Excel/ExcelCellState.cs +++ b/EPPlus/FormulaParsing/Excel/ExcelCellState.cs
@@ -13,33 +13,29 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel -{ - [Flags] - public enum ExcelCellState - { - HiddenCell = 1, - ContainsError = 2, - IsResultOfSubtotal = 4 - } +using System; + +namespace OfficeOpenXml.FormulaParsing.Excel; + +[Flags] +public enum ExcelCellState { + HiddenCell = 1, + ContainsError = 2, + IsResultOfSubtotal = 4, }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs index 7375ecf..3abd514 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/ArgumentCollectionUtil.cs
@@ -13,73 +13,71 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class ArgumentCollectionUtil - { - private readonly DoubleEnumerableArgConverter _doubleEnumerableArgConverter; - private readonly ObjectEnumerableArgConverter _objectEnumerableArgConverter; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - public ArgumentCollectionUtil() - : this(new DoubleEnumerableArgConverter(), new ObjectEnumerableArgConverter()) - { +public class ArgumentCollectionUtil { + private readonly DoubleEnumerableArgConverter _doubleEnumerableArgConverter; + private readonly ObjectEnumerableArgConverter _objectEnumerableArgConverter; - } + public ArgumentCollectionUtil() + : this(new(), new()) {} - public ArgumentCollectionUtil( - DoubleEnumerableArgConverter doubleEnumerableArgConverter, - ObjectEnumerableArgConverter objectEnumerableArgConverter) - { - _doubleEnumerableArgConverter = doubleEnumerableArgConverter; - _objectEnumerableArgConverter = objectEnumerableArgConverter; - } + public ArgumentCollectionUtil( + DoubleEnumerableArgConverter doubleEnumerableArgConverter, + ObjectEnumerableArgConverter objectEnumerableArgConverter) { + _doubleEnumerableArgConverter = doubleEnumerableArgConverter; + _objectEnumerableArgConverter = objectEnumerableArgConverter; + } - public virtual IEnumerable<double> ArgsToDoubleEnumerable(bool ignoreHidden, bool ignoreErrors, IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return _doubleEnumerableArgConverter.ConvertArgs(ignoreHidden, ignoreErrors, arguments, context); - } + public virtual IEnumerable<double> ArgsToDoubleEnumerable( + bool ignoreHidden, + bool ignoreErrors, + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return _doubleEnumerableArgConverter.ConvertArgs( + ignoreHidden, + ignoreErrors, + arguments, + context); + } - public virtual IEnumerable<object> ArgsToObjectEnumerable(bool ignoreHidden, - IEnumerable<FunctionArgument> arguments, - ParsingContext context) - { - return _objectEnumerableArgConverter.ConvertArgs(ignoreHidden, arguments, context); - } + public virtual IEnumerable<object> ArgsToObjectEnumerable( + bool ignoreHidden, + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return _objectEnumerableArgConverter.ConvertArgs(ignoreHidden, arguments, context); + } - public virtual double CalculateCollection(IEnumerable<FunctionArgument> collection, double result, Func<FunctionArgument, double, double> action) - { - foreach (var item in collection) - { - if (item.Value is IEnumerable<FunctionArgument>) - { - result = CalculateCollection((IEnumerable<FunctionArgument>)item.Value, result, action); - } - else - { - result = action(item, result); - } - } - return result; - } + public virtual double CalculateCollection( + IEnumerable<FunctionArgument> collection, + double result, + Func<FunctionArgument, double, double> action) { + foreach (var item in collection) { + if (item.Value is IEnumerable<FunctionArgument>) { + result = CalculateCollection((IEnumerable<FunctionArgument>)item.Value, result, action); + } else { + result = action(item, result); + } } + return result; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParser.cs index cdad8b1..d198dea 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParser.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParser.cs
@@ -1,36 +1,30 @@ - /* Copyright (C) 2011 Jan Källman - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. +/* Copyright (C) 2011 Jan Källman +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU Lesser General Public License for more details. - * - * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php - * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html - * - * All code and executables are provided "as is" with no warranty either express or implied. - * The author accepts no liability for any damage or loss of business that this product may cause. - * - * Code change notes: - * - * Author Change Date - ******************************************************************************* - * Mats Alm Added 2013-12-03 - *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +* See the GNU Lesser General Public License for more details. +* +* The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php +* If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html +* +* All code and executables are provided "as is" with no warranty either express or implied. +* The author accepts no liability for any damage or loss of business that this product may cause. +* +* Code change notes: +* +* Author Change Date +******************************************************************************* +* Mats Alm Added 2013-12-03 +*******************************************************************************/ -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public abstract class ArgumentParser - { - public abstract object Parse(object obj); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public abstract class ArgumentParser { + public abstract object Parse(object obj); }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs index 997173d..817f85a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParserFactory.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,44 +7,38 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class ArgumentParserFactory - { - public virtual ArgumentParser CreateArgumentParser(DataType dataType) - { - switch (dataType) - { - case DataType.Integer: - return new IntArgumentParser(); - case DataType.Boolean: - return new BoolArgumentParser(); - case DataType.Decimal: - return new DoubleArgumentParser(); - default: - throw new InvalidOperationException("non supported argument parser type " + dataType.ToString()); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public class ArgumentParserFactory { + public virtual ArgumentParser CreateArgumentParser(DataType dataType) { + switch (dataType) { + case DataType.Integer: + return new IntArgumentParser(); + case DataType.Boolean: + return new BoolArgumentParser(); + case DataType.Decimal: + return new DoubleArgumentParser(); + default: + throw new InvalidOperationException("non supported argument parser type " + dataType); } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs index a8ca838..1c4d10e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/ArgumentParsers.cs
@@ -1,5 +1,4 @@ -using System; -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -8,60 +7,49 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class ArgumentParsers - { - private static object _syncRoot = new object(); - private readonly Dictionary<DataType, ArgumentParser> _parsers = new Dictionary<DataType, ArgumentParser>(); - private readonly ArgumentParserFactory _parserFactory; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - public ArgumentParsers() - : this(new ArgumentParserFactory()) - { +public class ArgumentParsers { + private static object _syncRoot = new(); + private readonly Dictionary<DataType, ArgumentParser> _parsers = new(); + private readonly ArgumentParserFactory _parserFactory; + public ArgumentParsers() + : this(new()) {} + + public ArgumentParsers(ArgumentParserFactory factory) { + Require.That(factory).Named("argumentParserfactory").IsNotNull(); + _parserFactory = factory; + } + + public ArgumentParser GetParser(DataType dataType) { + if (!_parsers.ContainsKey(dataType)) { + lock (_syncRoot) { + if (!_parsers.ContainsKey(dataType)) { + _parsers.Add(dataType, _parserFactory.CreateArgumentParser(dataType)); } - - public ArgumentParsers(ArgumentParserFactory factory) - { - Require.That(factory).Named("argumentParserfactory").IsNotNull(); - _parserFactory = factory; - } - - public ArgumentParser GetParser(DataType dataType) - { - if (!_parsers.ContainsKey(dataType)) - { - lock (_syncRoot) - { - if (!_parsers.ContainsKey(dataType)) - { - _parsers.Add(dataType, _parserFactory.CreateArgumentParser(dataType)); - } - } - } - return _parsers[dataType]; - } + } } + return _parsers[dataType]; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs index 03e6dad..f492580 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/BoolArgumentParser.cs
@@ -7,47 +7,47 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class BoolArgumentParser : ArgumentParser - { - public override object Parse(object obj) - { - if (obj is ExcelDataProvider.IRangeInfo) - { - var r = ((ExcelDataProvider.IRangeInfo)obj).FirstOrDefault(); - obj = (r == null ? null : r.Value); - } - if (obj == null) return false; - if (obj is bool) return (bool)obj; - if (obj.IsNumeric()) return Convert.ToBoolean(obj); - bool result; - if (bool.TryParse(obj.ToString(), out result)) - { - return result; - } - return result; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public class BoolArgumentParser : ArgumentParser { + public override object Parse(object obj) { + if (obj is ExcelDataProvider.IRangeInfo) { + var r = ((ExcelDataProvider.IRangeInfo)obj).FirstOrDefault(); + obj = (r == null ? null : r.Value); } + if (obj == null) { + return false; + } + if (obj is bool) { + return (bool)obj; + } + if (obj.IsNumeric()) { + return Convert.ToBoolean(obj); + } + bool result; + if (bool.TryParse(obj.ToString(), out result)) { + return result; + } + return result; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs b/EPPlus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs index aa4bcb1..c7d56b2 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/BuiltInFunctions.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,188 +7,196 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using OfficeOpenXml.FormulaParsing.Excel.Functions.Database; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Information; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; using OfficeOpenXml.FormulaParsing.Excel.Functions.Numeric; using OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Information; +using OfficeOpenXml.FormulaParsing.Excel.Functions.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class BuiltInFunctions : FunctionsModule - { - public BuiltInFunctions() - { - // Text - Functions["len"] = new Len(); - Functions["lower"] = new Lower(); - Functions["upper"] = new Upper(); - Functions["left"] = new Left(); - Functions["right"] = new Right(); - Functions["mid"] = new Mid(); - Functions["replace"] = new Replace(); - Functions["rept"] = new Rept(); - Functions["substitute"] = new Substitute(); - Functions["concatenate"] = new Concatenate(); - Functions["char"] = new CharFunction(); - Functions["exact"] = new Exact(); - Functions["find"] = new Find(); - Functions["fixed"] = new Fixed(); - Functions["proper"] = new Proper(); - Functions["text"] = new Text.Text(); - Functions["t"] = new T(); - Functions["hyperlink"] = new Hyperlink(); - // Numbers - Functions["int"] = new CInt(); - // Math - Functions["abs"] = new Abs(); - Functions["asin"] = new Asin(); - Functions["asinh"] = new Asinh(); - Functions["cos"] = new Cos(); - Functions["cosh"] = new Cosh(); - Functions["power"] = new Power(); - Functions["sign"] = new Sign(); - Functions["sqrt"] = new Sqrt(); - Functions["sqrtpi"] = new SqrtPi(); - Functions["pi"] = new Pi(); - Functions["product"] = new Product(); - Functions["ceiling"] = new Ceiling(); - Functions["count"] = new Count(); - Functions["counta"] = new CountA(); - Functions["countblank"] = new CountBlank(); - Functions["countif"] = new CountIf(); - Functions["countifs"] = new CountIfs(); - Functions["fact"] = new Fact(); - Functions["floor"] = new Floor(); - Functions["sin"] = new Sin(); - Functions["sinh"] = new Sinh(); - Functions["sum"] = new Sum(); - Functions["sumif"] = new SumIf(); - Functions["sumifs"] = new SumIfs(); - Functions["sumproduct"] = new SumProduct(); - Functions["sumsq"] = new Sumsq(); - Functions["stdev"] = new Stdev(); - Functions["stdevp"] = new StdevP(); - Functions["stdev.s"] = new Stdev(); - Functions["stdev.p"] = new StdevP(); - Functions["subtotal"] = new Subtotal(); - Functions["exp"] = new Exp(); - Functions["log"] = new Log(); - Functions["log10"] = new Log10(); - Functions["ln"] = new Ln(); - Functions["max"] = new Max(); - Functions["maxa"] = new Maxa(); - Functions["median"] = new Median(); - Functions["min"] = new Min(); - Functions["mina"] = new Mina(); - Functions["mod"] = new Mod(); - Functions["average"] = new Average(); - Functions["averagea"] = new AverageA(); - Functions["averageif"] = new AverageIf(); - Functions["averageifs"] = new AverageIfs(); - Functions["round"] = new Round(); - Functions["rounddown"] = new Rounddown(); - Functions["roundup"] = new Roundup(); - Functions["rand"] = new Rand(); - Functions["randbetween"] = new RandBetween(); - Functions["quotient"] = new Quotient(); - Functions["trunc"] = new Trunc(); - Functions["tan"] = new Tan(); - Functions["tanh"] = new Tanh(); - Functions["atan"] = new Atan(); - Functions["atan2"] = new Atan2(); - Functions["atanh"] = new Atanh(); - Functions["acos"] = new Acos(); - Functions["acosh"] = new Acosh(); - Functions["var"] = new Var(); - Functions["varp"] = new VarP(); - Functions["large"] = new Large(); - Functions["small"] = new Small(); - Functions["degrees"] = new Degrees(); - // Information - Functions["isblank"] = new IsBlank(); - Functions["isnumber"] = new IsNumber(); - Functions["istext"] = new IsText(); - Functions["isnontext"] = new IsNonText(); - Functions["iserror"] = new IsError(); - Functions["iserr"] = new IsErr(); - Functions["error.type"] = new ErrorType(); - Functions["iseven"] = new IsEven(); - Functions["isodd"] = new IsOdd(); - Functions["islogical"] = new IsLogical(); - Functions["isna"] = new IsNa(); - Functions["na"] = new Na(); - Functions["n"] = new N(); - // Logical - Functions["if"] = new If(); - Functions["iferror"] = new IfError(); - Functions["ifna"] = new IfNa(); - Functions["not"] = new Not(); - Functions["and"] = new And(); - Functions["or"] = new Or(); - Functions["true"] = new True(); - Functions["false"] = new False(); - // Reference and lookup - Functions["address"] = new Address(); - Functions["hlookup"] = new HLookup(); - Functions["vlookup"] = new VLookup(); - Functions["lookup"] = new Lookup(); - Functions["match"] = new Match(); - Functions["row"] = new Row(){SkipArgumentEvaluation = true}; - Functions["rows"] = new Rows(){SkipArgumentEvaluation = true}; - Functions["column"] = new Column(){SkipArgumentEvaluation = true}; - Functions["columns"] = new Columns(){SkipArgumentEvaluation = true}; - Functions["choose"] = new Choose(); - Functions["index"] = new Index(); - Functions["indirect"] = new Indirect(); - Functions["offset"] = new Offset(){SkipArgumentEvaluation = true}; - // Date - Functions["date"] = new Date(); - Functions["today"] = new Today(); - Functions["now"] = new Now(); - Functions["day"] = new Day(); - Functions["month"] = new Month(); - Functions["year"] = new Year(); - Functions["time"] = new Time(); - Functions["hour"] = new Hour(); - Functions["minute"] = new Minute(); - Functions["second"] = new Second(); - Functions["weeknum"] = new Weeknum(); - Functions["weekday"] = new Weekday(); - Functions["days360"] = new Days360(); - Functions["yearfrac"] = new Yearfrac(); - Functions["edate"] = new Edate(); - Functions["eomonth"] = new Eomonth(); - Functions["isoweeknum"] = new IsoWeekNum(); - Functions["workday"] = new Workday(); - // Database - Functions["dget"] = new Dget(); - Functions["dcount"] = new Dcount(); - Functions["dcounta"] = new DcountA(); - Functions["dmax"] = new Dmax(); - Functions["dmin"] = new Dmin(); - Functions["dsum"] = new Dsum(); - Functions["daverage"] = new Daverage(); - Functions["dvar"] = new Dvar(); - Functions["dvarp"] = new Dvarp(); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public class BuiltInFunctions : FunctionsModule { + public BuiltInFunctions() { + // Text + Functions["len"] = new Len(); + Functions["lower"] = new Lower(); + Functions["upper"] = new Upper(); + Functions["left"] = new Left(); + Functions["right"] = new Right(); + Functions["mid"] = new Mid(); + Functions["replace"] = new Replace(); + Functions["rept"] = new Rept(); + Functions["substitute"] = new Substitute(); + Functions["concatenate"] = new Concatenate(); + Functions["char"] = new CharFunction(); + Functions["exact"] = new Exact(); + Functions["find"] = new Find(); + Functions["fixed"] = new Fixed(); + Functions["proper"] = new Proper(); + Functions["text"] = new Text.Text(); + Functions["t"] = new T(); + Functions["hyperlink"] = new Hyperlink(); + // Numbers + Functions["int"] = new CInt(); + // Math + Functions["abs"] = new Abs(); + Functions["asin"] = new Asin(); + Functions["asinh"] = new Asinh(); + Functions["cos"] = new Cos(); + Functions["cosh"] = new Cosh(); + Functions["power"] = new Power(); + Functions["sign"] = new Sign(); + Functions["sqrt"] = new Sqrt(); + Functions["sqrtpi"] = new SqrtPi(); + Functions["pi"] = new Pi(); + Functions["product"] = new Product(); + Functions["ceiling"] = new Ceiling(); + Functions["count"] = new Count(); + Functions["counta"] = new CountA(); + Functions["countblank"] = new CountBlank(); + Functions["countif"] = new CountIf(); + Functions["countifs"] = new CountIfs(); + Functions["fact"] = new Fact(); + Functions["floor"] = new Floor(); + Functions["sin"] = new Sin(); + Functions["sinh"] = new Sinh(); + Functions["sum"] = new Sum(); + Functions["sumif"] = new SumIf(); + Functions["sumifs"] = new SumIfs(); + Functions["sumproduct"] = new SumProduct(); + Functions["sumsq"] = new Sumsq(); + Functions["stdev"] = new Stdev(); + Functions["stdevp"] = new StdevP(); + Functions["stdev.s"] = new Stdev(); + Functions["stdev.p"] = new StdevP(); + Functions["subtotal"] = new Subtotal(); + Functions["exp"] = new Exp(); + Functions["log"] = new Log(); + Functions["log10"] = new Log10(); + Functions["ln"] = new Ln(); + Functions["max"] = new Max(); + Functions["maxa"] = new Maxa(); + Functions["median"] = new Median(); + Functions["min"] = new Min(); + Functions["mina"] = new Mina(); + Functions["mod"] = new Mod(); + Functions["average"] = new Average(); + Functions["averagea"] = new AverageA(); + Functions["averageif"] = new AverageIf(); + Functions["averageifs"] = new AverageIfs(); + Functions["round"] = new Round(); + Functions["rounddown"] = new Rounddown(); + Functions["roundup"] = new Roundup(); + Functions["rand"] = new Rand(); + Functions["randbetween"] = new RandBetween(); + Functions["quotient"] = new Quotient(); + Functions["trunc"] = new Trunc(); + Functions["tan"] = new Tan(); + Functions["tanh"] = new Tanh(); + Functions["atan"] = new Atan(); + Functions["atan2"] = new Atan2(); + Functions["atanh"] = new Atanh(); + Functions["acos"] = new Acos(); + Functions["acosh"] = new Acosh(); + Functions["var"] = new Var(); + Functions["varp"] = new VarP(); + Functions["large"] = new Large(); + Functions["small"] = new Small(); + Functions["degrees"] = new Degrees(); + // Information + Functions["isblank"] = new IsBlank(); + Functions["isnumber"] = new IsNumber(); + Functions["istext"] = new IsText(); + Functions["isnontext"] = new IsNonText(); + Functions["iserror"] = new IsError(); + Functions["iserr"] = new IsErr(); + Functions["error.type"] = new ErrorType(); + Functions["iseven"] = new IsEven(); + Functions["isodd"] = new IsOdd(); + Functions["islogical"] = new IsLogical(); + Functions["isna"] = new IsNa(); + Functions["na"] = new Na(); + Functions["n"] = new N(); + // Logical + Functions["if"] = new If(); + Functions["iferror"] = new IfError(); + Functions["ifna"] = new IfNa(); + Functions["not"] = new Not(); + Functions["and"] = new And(); + Functions["or"] = new Or(); + Functions["true"] = new True(); + Functions["false"] = new False(); + // Reference and lookup + Functions["address"] = new Address(); + Functions["hlookup"] = new HLookup(); + Functions["vlookup"] = new VLookup(); + Functions["lookup"] = new Lookup(); + Functions["match"] = new Match(); + Functions["row"] = new Row { + SkipArgumentEvaluation = true, + }; + Functions["rows"] = new Rows { + SkipArgumentEvaluation = true, + }; + Functions["column"] = new Column { + SkipArgumentEvaluation = true, + }; + Functions["columns"] = new Columns { + SkipArgumentEvaluation = true, + }; + Functions["choose"] = new Choose(); + Functions["index"] = new Index(); + Functions["indirect"] = new Indirect(); + Functions["offset"] = new Offset { + SkipArgumentEvaluation = true, + }; + // Date + Functions["date"] = new Date(); + Functions["today"] = new Today(); + Functions["now"] = new Now(); + Functions["day"] = new Day(); + Functions["month"] = new Month(); + Functions["year"] = new Year(); + Functions["time"] = new Time(); + Functions["hour"] = new Hour(); + Functions["minute"] = new Minute(); + Functions["second"] = new Second(); + Functions["weeknum"] = new Weeknum(); + Functions["weekday"] = new Weekday(); + Functions["days360"] = new Days360(); + Functions["yearfrac"] = new Yearfrac(); + Functions["edate"] = new Edate(); + Functions["eomonth"] = new Eomonth(); + Functions["isoweeknum"] = new IsoWeekNum(); + Functions["workday"] = new Workday(); + // Database + Functions["dget"] = new Dget(); + Functions["dcount"] = new Dcount(); + Functions["dcounta"] = new DcountA(); + Functions["dmax"] = new Dmax(); + Functions["dmin"] = new Dmin(); + Functions["dsum"] = new Dsum(); + Functions["daverage"] = new Daverage(); + Functions["dvar"] = new Dvar(); + Functions["dvarp"] = new Dvarp(); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CellStateHelper.cs b/EPPlus/FormulaParsing/Excel/Functions/CellStateHelper.cs index 1af20ca..e461919 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/CellStateHelper.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/CellStateHelper.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,46 +7,51 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Linq; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - internal static class CellStateHelper - { - private static bool IsSubTotal(ExcelDataProvider.ICellInfo c) - { - var tokens = c.Tokens; - if (tokens == null) return false; - return c.Tokens.Any(token => - token.TokenType == LexicalAnalysis.TokenType.Function - && token.Value.Equals("SUBTOTAL", StringComparison.InvariantCultureIgnoreCase) - ); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - internal static bool ShouldIgnore(bool ignoreHiddenValues, ExcelDataProvider.ICellInfo c, ParsingContext context) - { - return (ignoreHiddenValues && c.IsHiddenRow) || (context.Scopes.Current.IsSubtotal && IsSubTotal(c)); - } - - internal static bool ShouldIgnore(bool ignoreHiddenValues, FunctionArgument arg, ParsingContext context) - { - return (ignoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)); - } +internal static class CellStateHelper { + private static bool IsSubTotal(ExcelDataProvider.ICellInfo c) { + var tokens = c.Tokens; + if (tokens == null) { + return false; } + return c.Tokens.Any(token => + token.TokenType == TokenType.Function + && token.Value.Equals("SUBTOTAL", StringComparison.InvariantCultureIgnoreCase)); + } + + internal static bool ShouldIgnore( + bool ignoreHiddenValues, + ExcelDataProvider.ICellInfo c, + ParsingContext context) { + return (ignoreHiddenValues && c.IsHiddenRow) + || (context.Scopes.Current.IsSubtotal && IsSubTotal(c)); + } + + internal static bool ShouldIgnore( + bool ignoreHiddenValues, + FunctionArgument arg, + ParsingContext context) { + return (ignoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CollectionFlattener.cs b/EPPlus/FormulaParsing/Excel/Functions/CollectionFlattener.cs index c13d759..04eeab3 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/CollectionFlattener.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/CollectionFlattener.cs
@@ -7,50 +7,46 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public abstract class CollectionFlattener<T> - { - public virtual IEnumerable<T> FuncArgsToFlatEnumerable(IEnumerable<FunctionArgument> arguments, Action<FunctionArgument, IList<T>> convertFunc) - { - var argList = new List<T>(); - FuncArgsToFlatEnumerable(arguments, argList, convertFunc); - return argList; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - private void FuncArgsToFlatEnumerable(IEnumerable<FunctionArgument> arguments, List<T> argList, Action<FunctionArgument, IList<T>> convertFunc) - { - foreach (var arg in arguments) - { - if (arg.Value is IEnumerable<FunctionArgument>) - { - FuncArgsToFlatEnumerable((IEnumerable<FunctionArgument>)arg.Value, argList, convertFunc); - } - else - { - convertFunc(arg, argList); - } - } - } +public abstract class CollectionFlattener<T> { + public virtual IEnumerable<T> FuncArgsToFlatEnumerable( + IEnumerable<FunctionArgument> arguments, + Action<FunctionArgument, IList<T>> convertFunc) { + var argList = new List<T>(); + FuncArgsToFlatEnumerable(arguments, argList, convertFunc); + return argList; + } + + private void FuncArgsToFlatEnumerable( + IEnumerable<FunctionArgument> arguments, + List<T> argList, + Action<FunctionArgument, IList<T>> convertFunc) { + foreach (var arg in arguments) { + if (arg.Value is IEnumerable<FunctionArgument>) { + FuncArgsToFlatEnumerable((IEnumerable<FunctionArgument>)arg.Value, argList, convertFunc); + } else { + convertFunc(arg, argList); + } } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidator.cs b/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidator.cs index 2582f80..e936798 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidator.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidator.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,40 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-26 *******************************************************************************/ -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public abstract class CompileResultValidator - { - public abstract void Validate(object obj); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - private static CompileResultValidator _empty; - public static CompileResultValidator Empty - { - get { return _empty ?? (_empty = new EmptyCompileResultValidator()); } - } - } +public abstract class CompileResultValidator { + public abstract void Validate(object obj); - internal class EmptyCompileResultValidator : CompileResultValidator - { - public override void Validate(object obj) - { - // empty validator - do nothing - } - } + private static CompileResultValidator _empty; + + public static CompileResultValidator Empty => + _empty ?? (_empty = new EmptyCompileResultValidator()); +} + +internal class EmptyCompileResultValidator : CompileResultValidator { + public override void Validate(object obj) { + // empty validator - do nothing + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidators.cs b/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidators.cs index 82dccbf..40f74c5 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidators.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/CompileResultValidators.cs
@@ -7,49 +7,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-26 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class CompileResultValidators - { - private readonly Dictionary<DataType, CompileResultValidator> _validators = new Dictionary<DataType, CompileResultValidator>(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - private CompileResultValidator CreateOrGet(DataType dataType) - { - if (_validators.ContainsKey(dataType)) - { - return _validators[dataType]; - } - if (dataType == DataType.Decimal) - { - return _validators[DataType.Decimal] = new DecimalCompileResultValidator(); - } - return CompileResultValidator.Empty; - } +public class CompileResultValidators { + private readonly Dictionary<DataType, CompileResultValidator> _validators = new(); - public CompileResultValidator GetValidator(DataType dataType) - { - return CreateOrGet(dataType); - } + private CompileResultValidator CreateOrGet(DataType dataType) { + if (_validators.ContainsKey(dataType)) { + return _validators[dataType]; } + if (dataType == DataType.Decimal) { + return _validators[DataType.Decimal] = new DecimalCompileResultValidator(); + } + return CompileResultValidator.Empty; + } + + public CompileResultValidator GetValidator(DataType dataType) { + return CreateOrGet(dataType); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/DSum.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/DSum.cs index f604253..5522539 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/DSum.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/DSum.cs
@@ -7,48 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Dsum : DatabaseFunction - { - public Dsum() - : this(new RowMatcher()) - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - } +public class Dsum : DatabaseFunction { + public Dsum() + : this(new()) {} - public Dsum(RowMatcher rowMatcher) - : base(rowMatcher) - { + public Dsum(RowMatcher rowMatcher) + : base(rowMatcher) {} - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var values = GetMatchingValues(arguments, context); - if (!values.Any()) return CreateResult(0d, DataType.Integer); - return CreateResult(values.Sum(), DataType.Integer); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var values = GetMatchingValues(arguments, context); + if (!values.Any()) { + return CreateResult(0d, DataType.Integer); } + return CreateResult(values.Sum(), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs index 8e74635..f686f8e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/DatabaseFunction.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,67 +7,63 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public abstract class DatabaseFunction : ExcelFunction - { - protected RowMatcher RowMatcher { get; private set; } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public DatabaseFunction() - : this(new RowMatcher()) - { - - } +public abstract class DatabaseFunction : ExcelFunction { + protected RowMatcher RowMatcher { get; private set; } - public DatabaseFunction(RowMatcher rowMatcher) - { - RowMatcher = rowMatcher; - } + public DatabaseFunction() + : this(new()) {} - protected IEnumerable<double> GetMatchingValues(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; - //var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); - var field = arguments.ElementAt(1).Value; - var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; + public DatabaseFunction(RowMatcher rowMatcher) { + RowMatcher = rowMatcher; + } - var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); - var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); - var values = new List<double>(); + protected IEnumerable<double> GetMatchingValues( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; + //var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); + var field = arguments.ElementAt(1).Value; + var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; - while (db.HasMoreRows) - { - var dataRow = db.Read(); - if (!RowMatcher.IsMatch(dataRow, criteria)) continue; - var candidate = ConvertUtil.IsNumeric(field) ? dataRow[(int)ConvertUtil.GetValueDouble(field)] : dataRow[field.ToString().ToLower(CultureInfo.InvariantCulture)]; - if (ConvertUtil.IsNumeric(candidate)) - { - values.Add(ConvertUtil.GetValueDouble(candidate)); - } - } - return values; - } + var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); + var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); + var values = new List<double>(); + + while (db.HasMoreRows) { + var dataRow = db.Read(); + if (!RowMatcher.IsMatch(dataRow, criteria)) { + continue; + } + var candidate = ConvertUtil.IsNumeric(field) + ? dataRow[(int)ConvertUtil.GetValueDouble(field)] + : dataRow[field.ToString().ToLower(CultureInfo.InvariantCulture)]; + if (ConvertUtil.IsNumeric(candidate)) { + values.Add(ConvertUtil.GetValueDouble(candidate)); + } } + return values; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Daverage.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Daverage.cs index a32de6c..21a890a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/Daverage.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/Daverage.cs
@@ -7,48 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Daverage : DatabaseFunction - { - public Daverage() - : this(new RowMatcher()) - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - } +public class Daverage : DatabaseFunction { + public Daverage() + : this(new()) {} - public Daverage(RowMatcher rowMatcher) - : base(rowMatcher) - { + public Daverage(RowMatcher rowMatcher) + : base(rowMatcher) {} - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var values = GetMatchingValues(arguments, context); - if (!values.Any()) return CreateResult(0d, DataType.Integer); - return CreateResult(values.Average(), DataType.Integer); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var values = GetMatchingValues(arguments, context); + if (!values.Any()) { + return CreateResult(0d, DataType.Integer); } + return CreateResult(values.Average(), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dcount.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dcount.cs index a354af4..2ad31fa 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dcount.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/Dcount.cs
@@ -7,88 +7,73 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-06 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Dcount : ExcelFunction - { - private readonly RowMatcher _rowMatcher; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public Dcount() - : this(new RowMatcher()) - { - - } +public class Dcount : ExcelFunction { + private readonly RowMatcher _rowMatcher; - public Dcount(RowMatcher rowMatcher) - { - _rowMatcher = rowMatcher; - } + public Dcount() + : this(new()) {} - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; - string field = null; - string criteriaRange = null; - if (arguments.Count() == 2) - { - criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address; - } - else - { - field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); - criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; - } - var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); - var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); + public Dcount(RowMatcher rowMatcher) { + _rowMatcher = rowMatcher; + } - var nHits = 0; - while (db.HasMoreRows) - { - var dataRow = db.Read(); - if (_rowMatcher.IsMatch(dataRow, criteria)) - { - // if a fieldname is supplied, count only this row if the value - // of the supplied field is numeric. - if (!string.IsNullOrEmpty(field)) - { - var candidate = dataRow[field]; - if (ConvertUtil.IsNumeric(candidate)) - { - nHits++; - } - } - else - { - // no fieldname was supplied, always count matching row. - nHits++; - } - } - } - return CreateResult(nHits, DataType.Integer); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; + string field = null; + string criteriaRange = null; + if (arguments.Count() == 2) { + criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address; + } else { + field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); + criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; } + var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); + var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); + + var nHits = 0; + while (db.HasMoreRows) { + var dataRow = db.Read(); + if (_rowMatcher.IsMatch(dataRow, criteria)) { + // if a fieldname is supplied, count only this row if the value + // of the supplied field is numeric. + if (!string.IsNullOrEmpty(field)) { + var candidate = dataRow[field]; + if (ConvertUtil.IsNumeric(candidate)) { + nHits++; + } + } else { + // no fieldname was supplied, always count matching row. + nHits++; + } + } + } + return CreateResult(nHits, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs index b90a5b5..0316950 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/DcountA.cs
@@ -7,94 +7,76 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-06 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class DcountA : DatabaseFunction - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public DcountA() - : this(new RowMatcher()) - { +public class DcountA : DatabaseFunction { + public DcountA() + : this(new()) {} - } + public DcountA(RowMatcher rowMatcher) + : base(rowMatcher) {} - public DcountA(RowMatcher rowMatcher) - : base(rowMatcher) - { - - } - - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; - string field = null; - string criteriaRange = null; - if (arguments.Count() == 2) - { - criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address; - } - else - { - field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); - criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; - } - var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); - var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); - - var nHits = 0; - while (db.HasMoreRows) - { - var dataRow = db.Read(); - if (RowMatcher.IsMatch(dataRow, criteria)) - { - // if a fieldname is supplied, count only this row if the value - // of the supplied field is not blank. - if (!string.IsNullOrEmpty(field)) - { - var candidate = dataRow[field]; - if (ShouldCount(candidate)) - { - nHits++; - } - } - else - { - // no fieldname was supplied, always count matching row. - nHits++; - } - } - } - return CreateResult(nHits, DataType.Integer); - } - - private bool ShouldCount(object value) - { - if (value == null) return false; - return (!string.IsNullOrEmpty(value.ToString())); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; + string field = null; + string criteriaRange = null; + if (arguments.Count() == 2) { + criteriaRange = arguments.ElementAt(1).ValueAsRangeInfo.Address.Address; + } else { + field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); + criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; } + var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); + var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); + + var nHits = 0; + while (db.HasMoreRows) { + var dataRow = db.Read(); + if (RowMatcher.IsMatch(dataRow, criteria)) { + // if a fieldname is supplied, count only this row if the value + // of the supplied field is not blank. + if (!string.IsNullOrEmpty(field)) { + var candidate = dataRow[field]; + if (ShouldCount(candidate)) { + nHits++; + } + } else { + // no fieldname was supplied, always count matching row. + nHits++; + } + } + } + return CreateResult(nHits, DataType.Integer); + } + + private bool ShouldCount(object value) { + if (value == null) { + return false; + } + return (!string.IsNullOrEmpty(value.ToString())); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dget.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dget.cs index a351374..e8aa790 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dget.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/Dget.cs
@@ -7,65 +7,59 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-06 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Dget : DatabaseFunction - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public Dget() - : this(new RowMatcher()) - { - - } +public class Dget : DatabaseFunction { + public Dget() + : this(new()) {} - public Dget(RowMatcher rowMatcher) - : base(rowMatcher) - { + public Dget(RowMatcher rowMatcher) + : base(rowMatcher) {} - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; + var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); + var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var dbAddress = arguments.ElementAt(0).ValueAsRangeInfo.Address.Address; - var field = ArgToString(arguments, 1).ToLower(CultureInfo.InvariantCulture); - var criteriaRange = arguments.ElementAt(2).ValueAsRangeInfo.Address.Address; + var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); + var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); - var db = new ExcelDatabase(context.ExcelDataProvider, dbAddress); - var criteria = new ExcelDatabaseCriteria(context.ExcelDataProvider, criteriaRange); - - var nHits = 0; - object retVal = null; - while (db.HasMoreRows) - { - var dataRow = db.Read(); - if (!RowMatcher.IsMatch(dataRow, criteria)) continue; - if(++nHits > 1) return CreateResult(ExcelErrorValue.Values.Num, DataType.ExcelError); - retVal = dataRow[field]; - } - return new CompileResultFactory().Create(retVal); - } + var nHits = 0; + object retVal = null; + while (db.HasMoreRows) { + var dataRow = db.Read(); + if (!RowMatcher.IsMatch(dataRow, criteria)) { + continue; + } + if (++nHits > 1) { + return CreateResult(ExcelErrorValue.Values.Num, DataType.ExcelError); + } + retVal = dataRow[field]; } + return new CompileResultFactory().Create(retVal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmax.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dmax.cs index b817b9d..62f7d1c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmax.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/Dmax.cs
@@ -7,48 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Dmax : DatabaseFunction - { - public Dmax() - : this(new RowMatcher()) - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - } +public class Dmax : DatabaseFunction { + public Dmax() + : this(new()) {} - public Dmax(RowMatcher rowMatcher) - : base(rowMatcher) - { + public Dmax(RowMatcher rowMatcher) + : base(rowMatcher) {} - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var values = GetMatchingValues(arguments, context); - if (!values.Any()) return CreateResult(0d, DataType.Integer); - return CreateResult(values.Max(), DataType.Integer); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var values = GetMatchingValues(arguments, context); + if (!values.Any()) { + return CreateResult(0d, DataType.Integer); } + return CreateResult(values.Max(), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmin.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dmin.cs index 53b983b..8203884 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dmin.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/Dmin.cs
@@ -7,48 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Dmin : DatabaseFunction - { - public Dmin() - : this(new RowMatcher()) - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - } +public class Dmin : DatabaseFunction { + public Dmin() + : this(new()) {} - public Dmin(RowMatcher rowMatcher) - : base(rowMatcher) - { + public Dmin(RowMatcher rowMatcher) + : base(rowMatcher) {} - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var values = GetMatchingValues(arguments, context); - if (!values.Any()) return CreateResult(0d, DataType.Integer); - return CreateResult(values.Min(), DataType.Integer); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var values = GetMatchingValues(arguments, context); + if (!values.Any()) { + return CreateResult(0d, DataType.Integer); } + return CreateResult(values.Min(), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvar.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dvar.cs index bd6b09c..d961b82 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvar.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/Dvar.cs
@@ -7,50 +7,44 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Dvar : DatabaseFunction - { - public Dvar() - : this(new RowMatcher()) - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - } +public class Dvar : DatabaseFunction { + public Dvar() + : this(new()) {} - public Dvar(RowMatcher rowMatcher) - : base(rowMatcher) - { + public Dvar(RowMatcher rowMatcher) + : base(rowMatcher) {} - } - - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var values = GetMatchingValues(arguments, context); - if (!values.Any()) return CreateResult(0d, DataType.Integer); - return CreateResult(VarMethods.Var(values), DataType.Integer); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var values = GetMatchingValues(arguments, context); + if (!values.Any()) { + return CreateResult(0d, DataType.Integer); } + return CreateResult(VarMethods.Var(values), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvarp.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/Dvarp.cs index 8607f6e..7c43e88 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/Dvarp.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/Dvarp.cs
@@ -7,50 +7,44 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class Dvarp : DatabaseFunction - { - public Dvarp() - : this(new RowMatcher()) - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - } +public class Dvarp : DatabaseFunction { + public Dvarp() + : this(new()) {} - public Dvarp(RowMatcher rowMatcher) - : base(rowMatcher) - { + public Dvarp(RowMatcher rowMatcher) + : base(rowMatcher) {} - } - - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var values = GetMatchingValues(arguments, context); - if (!values.Any()) return CreateResult(0d, DataType.Integer); - return CreateResult(VarMethods.VarP(values), DataType.Integer); - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var values = GetMatchingValues(arguments, context); + if (!values.Any()) { + return CreateResult(0d, DataType.Integer); } + return CreateResult(VarMethods.VarP(values), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs index 231d870..90e3f97 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabase.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,90 +7,75 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-06 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class ExcelDatabase - { - private readonly ExcelDataProvider _dataProvider; - private readonly int _fromCol; - private readonly int _toCol; - private readonly int _fieldRow; - private readonly int _endRow; - private readonly string _worksheet; - private int _rowIndex; - private readonly List<ExcelDatabaseField> _fields = new List<ExcelDatabaseField>(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public IEnumerable<ExcelDatabaseField> Fields - { - get { return _fields; } - } +public class ExcelDatabase { + private readonly ExcelDataProvider _dataProvider; + private readonly int _fromCol; + private readonly int _toCol; + private readonly int _fieldRow; + private readonly int _endRow; + private readonly string _worksheet; + private int _rowIndex; + private readonly List<ExcelDatabaseField> _fields = new(); - public ExcelDatabase(ExcelDataProvider dataProvider, string range) - { - _dataProvider = dataProvider; - var address = new ExcelAddressBase(range); - _fromCol = address._fromCol; - _toCol = address._toCol; - _fieldRow = address._fromRow; - _endRow = address._toRow; - _worksheet = address.WorkSheet; - _rowIndex = _fieldRow; - Initialize(); - } + public IEnumerable<ExcelDatabaseField> Fields => _fields; - private void Initialize() - { - var fieldIx = 0; - for (var colIndex = _fromCol; colIndex <= _toCol; colIndex++) - { - var nameObj = GetCellValue(_fieldRow, colIndex); - var name = nameObj != null ? nameObj.ToString().ToLower(CultureInfo.InvariantCulture) : string.Empty; - _fields.Add(new ExcelDatabaseField(name, fieldIx++)); - } - } + public ExcelDatabase(ExcelDataProvider dataProvider, string range) { + _dataProvider = dataProvider; + var address = new ExcelAddressBase(range); + _fromCol = address._fromCol; + _toCol = address._toCol; + _fieldRow = address._fromRow; + _endRow = address._toRow; + _worksheet = address.WorkSheet; + _rowIndex = _fieldRow; + Initialize(); + } - private object GetCellValue(int row, int col) - { - return _dataProvider.GetRangeValue(_worksheet, row, col); - } - - public bool HasMoreRows - { - get { return _rowIndex < _endRow; } - } - - public ExcelDatabaseRow Read() - { - var retVal = new ExcelDatabaseRow(); - _rowIndex++; - foreach (var field in Fields) - { - var colIndex = _fromCol + field.ColIndex; - var val = GetCellValue(_rowIndex, colIndex); - retVal[field.FieldName] = val; - } - return retVal; - } + private void Initialize() { + var fieldIx = 0; + for (var colIndex = _fromCol; colIndex <= _toCol; colIndex++) { + var nameObj = GetCellValue(_fieldRow, colIndex); + var name = + nameObj != null ? nameObj.ToString().ToLower(CultureInfo.InvariantCulture) : string.Empty; + _fields.Add(new(name, fieldIx++)); } + } + + private object GetCellValue(int row, int col) { + return _dataProvider.GetRangeValue(_worksheet, row, col); + } + + public bool HasMoreRows => _rowIndex < _endRow; + + public ExcelDatabaseRow Read() { + var retVal = new ExcelDatabaseRow(); + _rowIndex++; + foreach (var field in Fields) { + var colIndex = _fromCol + field.ColIndex; + var val = GetCellValue(_rowIndex, colIndex); + retVal[field.FieldName] = val; + } + return retVal; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs index 522e810..f8b8846 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteria.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,77 +7,62 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-06 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class ExcelDatabaseCriteria - { - private readonly ExcelDataProvider _dataProvider; - private readonly int _fromCol; - private readonly int _toCol; - private readonly string _worksheet; - private readonly int _fieldRow; - private readonly Dictionary<ExcelDatabaseCriteriaField, object> _criterias = new Dictionary<ExcelDatabaseCriteriaField, object>(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public ExcelDatabaseCriteria(ExcelDataProvider dataProvider, string range) - { - _dataProvider = dataProvider; - var address = new ExcelAddressBase(range); - _fromCol = address._fromCol; - _toCol = address._toCol; - _worksheet = address.WorkSheet; - _fieldRow = address._fromRow; - Initialize(); +public class ExcelDatabaseCriteria { + private readonly ExcelDataProvider _dataProvider; + private readonly int _fromCol; + private readonly int _toCol; + private readonly string _worksheet; + private readonly int _fieldRow; + private readonly Dictionary<ExcelDatabaseCriteriaField, object> _criterias = new(); + + public ExcelDatabaseCriteria(ExcelDataProvider dataProvider, string range) { + _dataProvider = dataProvider; + var address = new ExcelAddressBase(range); + _fromCol = address._fromCol; + _toCol = address._toCol; + _worksheet = address.WorkSheet; + _fieldRow = address._fromRow; + Initialize(); + } + + private void Initialize() { + for (var x = _fromCol; x <= _toCol; x++) { + var fieldObj = _dataProvider.GetCellValue(_worksheet, _fieldRow, x); + var val = _dataProvider.GetCellValue(_worksheet, _fieldRow + 1, x); + if (fieldObj != null && val != null) { + if (fieldObj is string) { + var field = new ExcelDatabaseCriteriaField( + fieldObj.ToString().ToLower(CultureInfo.InvariantCulture)); + _criterias.Add(field, val); + } else if (ConvertUtil.IsNumeric(fieldObj)) { + var field = new ExcelDatabaseCriteriaField((int)fieldObj); + _criterias.Add(field, val); } - - private void Initialize() - { - for (var x = _fromCol; x <= _toCol; x++) - { - var fieldObj = _dataProvider.GetCellValue(_worksheet, _fieldRow, x); - var val = _dataProvider.GetCellValue(_worksheet, _fieldRow + 1, x); - if (fieldObj != null && val != null) - { - if(fieldObj is string) - { - var field = new ExcelDatabaseCriteriaField(fieldObj.ToString().ToLower(CultureInfo.InvariantCulture)); - _criterias.Add(field, val); - } - else if (ConvertUtil.IsNumeric(fieldObj)) - { - var field = new ExcelDatabaseCriteriaField((int) fieldObj); - _criterias.Add(field, val); - } - - } - } - } - - public virtual IDictionary<ExcelDatabaseCriteriaField, object> Items - { - get { return _criterias; } - } + } } + } + + public virtual IDictionary<ExcelDatabaseCriteriaField, object> Items => _criterias; }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs index beb77d0..eec151c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseCriteriaField.cs
@@ -7,51 +7,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class ExcelDatabaseCriteriaField - { - public ExcelDatabaseCriteriaField(string fieldName) - { - FieldName = fieldName; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public ExcelDatabaseCriteriaField(int fieldIndex) - { - FieldIndex = fieldIndex; - } +public class ExcelDatabaseCriteriaField { + public ExcelDatabaseCriteriaField(string fieldName) { + FieldName = fieldName; + } - public override string ToString() - { - if (!string.IsNullOrEmpty(FieldName)) - { - return FieldName; - } - return base.ToString(); - } + public ExcelDatabaseCriteriaField(int fieldIndex) { + FieldIndex = fieldIndex; + } - public string FieldName { get; private set; } - - public int? FieldIndex { get; private set; } + public override string ToString() { + if (!string.IsNullOrEmpty(FieldName)) { + return FieldName; } + return base.ToString(); + } + + public string FieldName { get; private set; } + + public int? FieldIndex { get; private set; } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs index 9687b3c..9578486 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseField.cs
@@ -7,38 +7,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-06 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class ExcelDatabaseField - { - - public string FieldName { get; private set; } - public int ColIndex { get; private set; } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public ExcelDatabaseField(string fieldName, int colIndex) - { - FieldName = fieldName; - ColIndex = colIndex; - } - } +public class ExcelDatabaseField { + public string FieldName { get; private set; } + + public int ColIndex { get; private set; } + + public ExcelDatabaseField(string fieldName, int colIndex) { + FieldName = fieldName; + ColIndex = colIndex; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs index 0a216db..7b694cf 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/ExcelDatabaseRow.cs
@@ -7,54 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel.Operators; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class ExcelDatabaseRow - { - private Dictionary<int, string> _fieldIndexes = new Dictionary<int, string>(); - private readonly Dictionary<string, object> _items = new Dictionary<string, object>(); - private int _colIndex = 1; - public object this[string field] - { - get { return _items[field]; } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - set - { - _items[field] = value; - _fieldIndexes[_colIndex++] = field; - } - } +public class ExcelDatabaseRow { + private Dictionary<int, string> _fieldIndexes = new(); + private readonly Dictionary<string, object> _items = new(); + private int _colIndex = 1; - public object this[int index] - { - get - { - var field = _fieldIndexes[index]; - return _items[field]; - } - } - - + public object this[string field] { + get => _items[field]; + set { + _items[field] = value; + _fieldIndexes[_colIndex++] = field; } + } + + public object this[int index] { + get { + var field = _fieldIndexes[index]; + return _items[field]; + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs b/EPPlus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs index e0b32d7..3493872 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Database/RowMatcher.cs
@@ -7,84 +7,76 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-06 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database -{ - public class RowMatcher - { - private readonly WildCardValueMatcher _wildCardValueMatcher; - private readonly NumericExpressionEvaluator _numericExpressionEvaluator; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Database; - public RowMatcher() - : this(new WildCardValueMatcher(), new NumericExpressionEvaluator()) - { - - } +public class RowMatcher { + private readonly WildCardValueMatcher _wildCardValueMatcher; + private readonly NumericExpressionEvaluator _numericExpressionEvaluator; - public RowMatcher(WildCardValueMatcher wildCardValueMatcher, NumericExpressionEvaluator numericExpressionEvaluator) - { - _wildCardValueMatcher = wildCardValueMatcher; - _numericExpressionEvaluator = numericExpressionEvaluator; - } + public RowMatcher() + : this(new(), new()) {} - public bool IsMatch(ExcelDatabaseRow row, ExcelDatabaseCriteria criteria) - { - var retVal = true; - foreach (var c in criteria.Items) - { - var candidate = c.Key.FieldIndex.HasValue ? row[c.Key.FieldIndex.Value] : row[c.Key.FieldName]; - var crit = c.Value; - if (candidate.IsNumeric() && crit.IsNumeric()) - { - if(System.Math.Abs(ConvertUtil.GetValueDouble(candidate) - ConvertUtil.GetValueDouble(crit)) > double.Epsilon) return false; - } - else - { - var criteriaString = crit.ToString(); - if (!Evaluate(candidate, criteriaString)) - { - return false; - } - } - } - return retVal; - } + public RowMatcher( + WildCardValueMatcher wildCardValueMatcher, + NumericExpressionEvaluator numericExpressionEvaluator) { + _wildCardValueMatcher = wildCardValueMatcher; + _numericExpressionEvaluator = numericExpressionEvaluator; + } - private bool Evaluate(object obj, string expression) - { - if (obj == null) return false; - double? candidate = default(double?); - if (ConvertUtil.IsNumeric(obj)) - { - candidate = ConvertUtil.GetValueDouble(obj); - } - if (candidate.HasValue) - { - return _numericExpressionEvaluator.Evaluate(candidate.Value, expression); - } - return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; + public bool IsMatch(ExcelDatabaseRow row, ExcelDatabaseCriteria criteria) { + var retVal = true; + foreach (var c in criteria.Items) { + var candidate = c.Key.FieldIndex.HasValue + ? row[c.Key.FieldIndex.Value] + : row[c.Key.FieldName]; + var crit = c.Value; + if (candidate.IsNumeric() && crit.IsNumeric()) { + if (System.Math.Abs( + ConvertUtil.GetValueDouble(candidate) - ConvertUtil.GetValueDouble(crit)) + > double.Epsilon) { + return false; } + } else { + var criteriaString = crit.ToString(); + if (!Evaluate(candidate, criteriaString)) { + return false; + } + } } + return retVal; + } + + private bool Evaluate(object obj, string expression) { + if (obj == null) { + return false; + } + double? candidate = default(double?); + if (ConvertUtil.IsNumeric(obj)) { + candidate = ConvertUtil.GetValueDouble(obj); + } + if (candidate.HasValue) { + return _numericExpressionEvaluator.Evaluate(candidate.Value, expression); + } + return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Date.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Date.cs index aa5233e..e2e8ad9 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Date.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Date.cs
@@ -7,42 +7,39 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Date : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var year = ArgToInt(arguments, 0); - var month = ArgToInt(arguments, 1); - var day = ArgToInt(arguments, 2); - var date = new System.DateTime(year, 1, 1); - month -= 1; - date = date.AddMonths(month); - date = date.AddDays((double)(day - 1)); - return CreateResult(date.ToOADate(), DataType.Date); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Date : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var year = ArgToInt(arguments, 0); + var month = ArgToInt(arguments, 1); + var day = ArgToInt(arguments, 2); + var date = new System.DateTime(year, 1, 1); + month -= 1; + date = date.AddMonths(month); + date = date.AddDays(day - 1); + return CreateResult(date.ToOADate(), DataType.Date); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs index 1756686..fbac43c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateParsingFunction.cs
@@ -1,26 +1,17 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public abstract class DateParsingFunction : ExcelFunction - { - protected System.DateTime ParseDate(IEnumerable<FunctionArgument> arguments, object dateObj) - { - System.DateTime date = System.DateTime.MinValue; - if (dateObj is string) - { - date = System.DateTime.Parse(dateObj.ToString(), CultureInfo.InvariantCulture); - } - else - { - var d = ArgToDecimal(arguments, 0); - date = System.DateTime.FromOADate(d); - } - return date; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public abstract class DateParsingFunction : ExcelFunction { + protected System.DateTime ParseDate(IEnumerable<FunctionArgument> arguments, object dateObj) { + System.DateTime date = System.DateTime.MinValue; + if (dateObj is string) { + date = System.DateTime.Parse(dateObj.ToString(), CultureInfo.InvariantCulture); + } else { + var d = ArgToDecimal(arguments, 0); + date = System.DateTime.FromOADate(d); } + return date; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs index 3310d64..74860bf 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateStringParser.cs
@@ -7,29 +7,22 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class DateStringParser - { - } -} +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class DateStringParser {}
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs index 2840c49..0b5f372 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/DateValue.cs
@@ -1,32 +1,26 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - /// <summary> - /// Simple implementation of DateValue function, just using .NET built-in - /// function System.DateTime.TryParse, based on current culture - /// </summary> - public class DateValue : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateString = ArgToString(arguments, 0); - return Execute(dateString); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - internal CompileResult Execute(string dateString) - { - System.DateTime result; - System.DateTime.TryParse(dateString, out result); - return result != System.DateTime.MinValue ? - CreateResult(result.ToOADate(), DataType.Date) : - CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); - } - } +/// <summary> +/// Simple implementation of DateValue function, just using .NET built-in +/// function System.DateTime.TryParse, based on current culture +/// </summary> +public class DateValue : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateString = ArgToString(arguments, 0); + return Execute(dateString); + } + + internal CompileResult Execute(string dateString) { + System.DateTime result; + System.DateTime.TryParse(dateString, out result); + return result != System.DateTime.MinValue + ? CreateResult(result.ToOADate(), DataType.Date) + : CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Day.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Day.cs index 48bb47a..dc4d39c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Day.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Day.cs
@@ -7,38 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Day : DateParsingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateObj = GetFirstValue(arguments); - var date = ParseDate(arguments, dateObj); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - return CreateResult(date.Day, DataType.Integer); - } - } +public class Day : DateParsingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateObj = GetFirstValue(arguments); + var date = ParseDate(arguments, dateObj); + + return CreateResult(date.Day, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Days360.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Days360.cs index 9b3b9ac..20810ef 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Days360.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Days360.cs
@@ -1,81 +1,77 @@ -using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Days360 : ExcelFunction - { - private enum Days360Calctype - { - European, - Us - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var numDate1 = ArgToDecimal(arguments, 0); - var numDate2 = ArgToDecimal(arguments, 1); - var dt1 = System.DateTime.FromOADate(numDate1); - var dt2 = System.DateTime.FromOADate(numDate2); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - var calcType = Days360Calctype.Us; - if (arguments.Count() > 2) - { - var european = ArgToBool(arguments, 2); - if(european) calcType = Days360Calctype.European; - } +public class Days360 : ExcelFunction { + private enum Days360Calctype { + European, + Us, + } - var startYear = dt1.Year; - var startMonth = dt1.Month; - var startDay = dt1.Day; - var endYear = dt2.Year; - var endMonth = dt2.Month; - var endDay = dt2.Day; + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var numDate1 = ArgToDecimal(arguments, 0); + var numDate2 = ArgToDecimal(arguments, 1); + var dt1 = System.DateTime.FromOADate(numDate1); + var dt2 = System.DateTime.FromOADate(numDate2); - if (calcType == Days360Calctype.European) - { - if (startDay == 31) startDay = 30; - if (endDay == 31) endDay = 30; - } - else - { - var calendar = new GregorianCalendar(); - var nDaysInFeb = calendar.IsLeapYear(dt1.Year) ? 29 : 28; - - // If the investment is EOM and (Date1 is the last day of February) and (Date2 is the last day of February), then change D2 to 30. - if (startMonth == 2 && startDay == nDaysInFeb && endMonth == 2 && endDay == nDaysInFeb) - { - endDay = 30; - } - // If the investment is EOM and (Date1 is the last day of February), then change D1 to 30. - if (startMonth == 2 && startDay == nDaysInFeb) - { - startDay = 30; - } - // If D2 is 31 and D1 is 30 or 31, then change D2 to 30. - if (endDay == 31 && (startDay == 30 || startDay == 31)) - { - endDay = 30; - } - // If D1 is 31, then change D1 to 30. - if (startDay == 31) - { - startDay = 30; - } - } - var result = (endYear*12*30 + endMonth*30 + endDay) - (startYear*12*30 + startMonth*30 + startDay); - return CreateResult(result, DataType.Integer); - } - - private int GetNumWholeMonths(System.DateTime dt1, System.DateTime dt2) - { - var startDate = new System.DateTime(dt1.Year, dt1.Month, 1).AddMonths(1); - var endDate = new System.DateTime(dt2.Year, dt2.Month, 1); - return ((endDate.Year - startDate.Year)*12) + (endDate.Month - startDate.Month); - } + var calcType = Days360Calctype.Us; + if (arguments.Count() > 2) { + var european = ArgToBool(arguments, 2); + if (european) { + calcType = Days360Calctype.European; + } } + + var startYear = dt1.Year; + var startMonth = dt1.Month; + var startDay = dt1.Day; + var endYear = dt2.Year; + var endMonth = dt2.Month; + var endDay = dt2.Day; + + if (calcType == Days360Calctype.European) { + if (startDay == 31) { + startDay = 30; + } + if (endDay == 31) { + endDay = 30; + } + } else { + var calendar = new GregorianCalendar(); + var nDaysInFeb = calendar.IsLeapYear(dt1.Year) ? 29 : 28; + + // If the investment is EOM and (Date1 is the last day of February) and (Date2 is the last day of February), then change D2 to 30. + if (startMonth == 2 && startDay == nDaysInFeb && endMonth == 2 && endDay == nDaysInFeb) { + endDay = 30; + } + // If the investment is EOM and (Date1 is the last day of February), then change D1 to 30. + if (startMonth == 2 && startDay == nDaysInFeb) { + startDay = 30; + } + // If D2 is 31 and D1 is 30 or 31, then change D2 to 30. + if (endDay == 31 && (startDay == 30 || startDay == 31)) { + endDay = 30; + } + // If D1 is 31, then change D1 to 30. + if (startDay == 31) { + startDay = 30; + } + } + var result = + (endYear * 12 * 30 + endMonth * 30 + endDay) + - (startYear * 12 * 30 + startMonth * 30 + startDay); + return CreateResult(result, DataType.Integer); + } + + private int GetNumWholeMonths(System.DateTime dt1, System.DateTime dt2) { + var startDate = new System.DateTime(dt1.Year, dt1.Month, 1).AddMonths(1); + var endDate = new System.DateTime(dt2.Year, dt2.Month, 1); + return ((endDate.Year - startDate.Year) * 12) + (endDate.Month - startDate.Month); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Edate.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Edate.cs index ad6dae2..7a1af10 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Edate.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Edate.cs
@@ -1,21 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Edate : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2, eErrorType.Value); - var dateSerial = ArgToDecimal(arguments, 0); - var date = System.DateTime.FromOADate(dateSerial); - var nMonthsToAdd = ArgToInt(arguments, 1); - var resultDate = date.AddMonths(nMonthsToAdd); - return CreateResult(resultDate.ToOADate(), DataType.Date); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Edate : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2, eErrorType.Value); + var dateSerial = ArgToDecimal(arguments, 0); + var date = System.DateTime.FromOADate(dateSerial); + var nMonthsToAdd = ArgToInt(arguments, 1); + var resultDate = date.AddMonths(nMonthsToAdd); + return CreateResult(resultDate.ToOADate(), DataType.Date); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs index f056a9e..33454da 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Eomonth.cs
@@ -1,20 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Eomonth : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var date = System.DateTime.FromOADate(ArgToDecimal(arguments, 0)); - var monthsToAdd = ArgToInt(arguments, 1); - var resultDate = new System.DateTime(date.Year, date.Month, 1).AddMonths(monthsToAdd + 1).AddDays(-1); - return CreateResult(resultDate.ToOADate(), DataType.Date); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Eomonth : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var date = System.DateTime.FromOADate(ArgToDecimal(arguments, 0)); + var monthsToAdd = ArgToInt(arguments, 1); + var resultDate = new System.DateTime(date.Year, date.Month, 1) + .AddMonths(monthsToAdd + 1) + .AddDays(-1); + return CreateResult(resultDate.ToOADate(), DataType.Date); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Hour.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Hour.cs index 0215aa3..5509889 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Hour.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Hour.cs
@@ -1,5 +1,4 @@ - -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -8,39 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System.Globalization; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Hour : DateParsingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateObj = arguments.ElementAt(0).Value; - var date = ParseDate(arguments, dateObj); - return CreateResult(date.Hour, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - } +public class Hour : DateParsingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateObj = arguments.ElementAt(0).Value; + var date = ParseDate(arguments, dateObj); + return CreateResult(date.Hour, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs index f42483e..45b838b 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/IsoWeekNum.cs
@@ -1,50 +1,47 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class IsoWeekNum : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateInt = ArgToInt(arguments, 0); - var date = System.DateTime.FromOADate(dateInt); - return CreateResult(WeekNumber(date), DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - /// <summary> - /// This implementation was found on http://stackoverflow.com/questions/1285191/get-week-of-date-from-linq-query - /// </summary> - /// <param name="fromDate"></param> - /// <returns></returns> - private int WeekNumber(System.DateTime fromDate) - { - // Get jan 1st of the year - var startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1); - // Get dec 31st of the year - var endOfYear = startOfYear.AddYears(1).AddDays(-1); - // ISO 8601 weeks start with Monday - // The first week of a year includes the first Thursday - // DayOfWeek returns 0 for sunday up to 6 for saterday - int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 }; - int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek]; - int wk = nds / 7; - switch (wk) - { - case 0: - // Return weeknumber of dec 31st of the previous year - return WeekNumber(startOfYear.AddDays(-1)); - case 53: - // If dec 31st falls before thursday it is week 01 of next year - if (endOfYear.DayOfWeek < DayOfWeek.Thursday) - return 1; - return wk; - default: return wk; - } +public class IsoWeekNum : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateInt = ArgToInt(arguments, 0); + var date = System.DateTime.FromOADate(dateInt); + return CreateResult(WeekNumber(date), DataType.Integer); + } + + /// <summary> + /// This implementation was found on http://stackoverflow.com/questions/1285191/get-week-of-date-from-linq-query + /// </summary> + /// <param name="fromDate"></param> + /// <returns></returns> + private int WeekNumber(System.DateTime fromDate) { + // Get jan 1st of the year + var startOfYear = fromDate.AddDays(-fromDate.Day + 1).AddMonths(-fromDate.Month + 1); + // Get dec 31st of the year + var endOfYear = startOfYear.AddYears(1).AddDays(-1); + // ISO 8601 weeks start with Monday + // The first week of a year includes the first Thursday + // DayOfWeek returns 0 for sunday up to 6 for saterday + int[] iso8601Correction = { 6, 7, 8, 9, 10, 4, 5 }; + int nds = fromDate.Subtract(startOfYear).Days + iso8601Correction[(int)startOfYear.DayOfWeek]; + int wk = nds / 7; + switch (wk) { + case 0: + // Return weeknumber of dec 31st of the previous year + return WeekNumber(startOfYear.AddDays(-1)); + case 53: + // If dec 31st falls before thursday it is week 01 of next year + if (endOfYear.DayOfWeek < DayOfWeek.Thursday) { + return 1; } + return wk; + default: + return wk; } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs index 4ca338d..57426d0 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Minute.cs
@@ -7,46 +7,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Minute : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateObj = arguments.ElementAt(0).Value; - System.DateTime date = System.DateTime.MinValue; - if (dateObj is string) - { - date = System.DateTime.Parse(dateObj.ToString()); - } - else - { - var d = ArgToDecimal(arguments, 0); - date = System.DateTime.FromOADate(d); - } - return CreateResult(date.Minute, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Minute : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateObj = arguments.ElementAt(0).Value; + System.DateTime date = System.DateTime.MinValue; + if (dateObj is string) { + date = System.DateTime.Parse(dateObj.ToString()); + } else { + var d = ArgToDecimal(arguments, 0); + date = System.DateTime.FromOADate(d); } + return CreateResult(date.Minute, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Month.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Month.cs index 1118b0a..c6aaba4 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Month.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Month.cs
@@ -7,37 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Month : DateParsingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateObj = arguments.ElementAt(0).Value; - var date = ParseDate(arguments, dateObj); - return CreateResult(date.Month, DataType.Integer); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Month : DateParsingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateObj = arguments.ElementAt(0).Value; + var date = ParseDate(arguments, dateObj); + return CreateResult(date.Month, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs index 762cab3..93e419e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Networkdays.cs
@@ -1,28 +1,24 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Networkdays : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 2); - var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0)); - var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1)); - var calculator = new WorkdayCalculator(); - var result = calculator.CalculateNumberOfWorkdays(startDate, endDate); - if (functionArguments.Length > 2) - { - result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[2]); - } - - return new CompileResult(result.NumberOfWorkdays, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Networkdays : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 2); + var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0)); + var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1)); + var calculator = new WorkdayCalculator(); + var result = calculator.CalculateNumberOfWorkdays(startDate, endDate); + if (functionArguments.Length > 2) { + result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[2]); } + + return new(result.NumberOfWorkdays, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs index ac1c80c..e3e1891 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/NetworkdaysIntl.cs
@@ -1,46 +1,37 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class NetworkdaysIntl : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 2); - var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0)); - var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1)); - WorkdayCalculator calculator = new WorkdayCalculator(); - var weekdayFactory = new HolidayWeekdaysFactory(); - if (functionArguments.Length > 2) - { - var holidayArg = functionArguments[2].Value; - if (Regex.IsMatch(holidayArg.ToString(), "^[01]{7}")) - { - calculator = new WorkdayCalculator(weekdayFactory.Create(holidayArg.ToString())); - } - else if (IsNumeric(holidayArg)) - { - var holidayCode = Convert.ToInt32(holidayArg); - calculator = new WorkdayCalculator(weekdayFactory.Create(holidayCode)); - } - else - { - return new CompileResult(eErrorType.Value); - } - } - var result = calculator.CalculateNumberOfWorkdays(startDate, endDate); - if (functionArguments.Length > 3) - { - result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[3]); - } - return new CompileResult(result.NumberOfWorkdays, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class NetworkdaysIntl : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 2); + var startDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 0)); + var endDate = System.DateTime.FromOADate(ArgToInt(functionArguments, 1)); + WorkdayCalculator calculator = new WorkdayCalculator(); + var weekdayFactory = new HolidayWeekdaysFactory(); + if (functionArguments.Length > 2) { + var holidayArg = functionArguments[2].Value; + if (Regex.IsMatch(holidayArg.ToString(), "^[01]{7}")) { + calculator = new(weekdayFactory.Create(holidayArg.ToString())); + } else if (IsNumeric(holidayArg)) { + var holidayCode = Convert.ToInt32(holidayArg); + calculator = new(weekdayFactory.Create(holidayCode)); + } else { + return new(eErrorType.Value); + } } + var result = calculator.CalculateNumberOfWorkdays(startDate, endDate); + if (functionArguments.Length > 3) { + result = calculator.ReduceWorkdaysWithHolidays(result, functionArguments[3]); + } + return new(result.NumberOfWorkdays, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Now.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Now.cs index b93048e..b4bd17d 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Now.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Now.cs
@@ -7,34 +7,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Now : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return CreateResult(System.DateTime.Now.ToOADate(), DataType.Date); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Now : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return CreateResult(System.DateTime.Now.ToOADate(), DataType.Date); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Second.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Second.cs index 137ea1d..443e913 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Second.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Second.cs
@@ -7,37 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Second : DateParsingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateObj = arguments.ElementAt(0).Value; - System.DateTime date = ParseDate(arguments, dateObj); - return CreateResult(date.Second, DataType.Integer); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Second : DateParsingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateObj = arguments.ElementAt(0).Value; + System.DateTime date = ParseDate(arguments, dateObj); + return CreateResult(date.Second, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Time.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Time.cs index c781317..fb1144e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Time.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Time.cs
@@ -7,58 +7,48 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Time : TimeBaseFunction - { - public Time() - : base() - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - } - - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var firstArg = arguments.ElementAt(0).Value.ToString(); - if(arguments.Count() == 1 && TimeStringParser.CanParse(firstArg)) - { - var result = TimeStringParser.Parse(firstArg); - return new CompileResult(result, DataType.Time); - } - ValidateArguments(arguments, 3); - var hour = ArgToInt(arguments, 0); - var min = ArgToInt(arguments, 1); - var sec = ArgToInt(arguments, 2); - - ThrowArgumentExceptionIf(() => sec < 0 || sec > 59, "Invalid second: " + sec); - ThrowArgumentExceptionIf(() => min < 0 || min > 59, "Invalid minute: " + min); - ThrowArgumentExceptionIf(() => min < 0 || hour > 23, "Invalid hour: " + hour); - - - var secondsOfThisTime = (double)(hour * 60 * 60 + min * 60 + sec); - return CreateResult(GetTimeSerialNumber(secondsOfThisTime), DataType.Time); - } +public class Time : TimeBaseFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var firstArg = arguments.ElementAt(0).Value.ToString(); + if (arguments.Count() == 1 && TimeStringParser.CanParse(firstArg)) { + var result = TimeStringParser.Parse(firstArg); + return new(result, DataType.Time); } + ValidateArguments(arguments, 3); + var hour = ArgToInt(arguments, 0); + var min = ArgToInt(arguments, 1); + var sec = ArgToInt(arguments, 2); + + ThrowArgumentExceptionIf(() => sec < 0 || sec > 59, "Invalid second: " + sec); + ThrowArgumentExceptionIf(() => min < 0 || min > 59, "Invalid minute: " + min); + ThrowArgumentExceptionIf(() => min < 0 || hour > 23, "Invalid hour: " + hour); + + var secondsOfThisTime = (double)(hour * 60 * 60 + min * 60 + sec); + return CreateResult(GetTimeSerialNumber(secondsOfThisTime), DataType.Time); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs index 59382d3..879fc64 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeBaseFunction.cs
@@ -7,85 +7,62 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public abstract class TimeBaseFunction : ExcelFunction - { - public TimeBaseFunction() - { - TimeStringParser = new TimeStringParser(); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - protected TimeStringParser TimeStringParser - { - get; - private set; - } +public abstract class TimeBaseFunction : ExcelFunction { + public TimeBaseFunction() { + TimeStringParser = new(); + } - protected double SerialNumber - { - get; - private set; - } + protected TimeStringParser TimeStringParser { get; private set; } - public void ValidateAndInitSerialNumber(IEnumerable<FunctionArgument> arguments) - { - ValidateArguments(arguments, 1); - SerialNumber = (double)ArgToDecimal(arguments, 0); - } + protected double SerialNumber { get; private set; } - protected double SecondsInADay - { - get{ return 24 * 60 * 60; } - } + public void ValidateAndInitSerialNumber(IEnumerable<FunctionArgument> arguments) { + ValidateArguments(arguments, 1); + SerialNumber = ArgToDecimal(arguments, 0); + } - protected double GetTimeSerialNumber(double seconds) - { - return seconds / SecondsInADay; - } + protected double SecondsInADay => 24 * 60 * 60; - protected double GetSeconds(double serialNumber) - { - return serialNumber * SecondsInADay; - } + protected double GetTimeSerialNumber(double seconds) { + return seconds / SecondsInADay; + } - protected double GetHour(double serialNumber) - { - var seconds = GetSeconds(serialNumber); - return (int)seconds / (60 * 60); - } + protected double GetSeconds(double serialNumber) { + return serialNumber * SecondsInADay; + } - protected double GetMinute(double serialNumber) - { - var seconds = GetSeconds(serialNumber); - seconds -= GetHour(serialNumber) * 60 * 60; - return (seconds - (seconds % 60)) / 60; - } + protected double GetHour(double serialNumber) { + var seconds = GetSeconds(serialNumber); + return (int)seconds / (60 * 60); + } - protected double GetSecond(double serialNumber) - { - return GetSeconds(serialNumber) % 60; - } - } + protected double GetMinute(double serialNumber) { + var seconds = GetSeconds(serialNumber); + seconds -= GetHour(serialNumber) * 60 * 60; + return (seconds - (seconds % 60)) / 60; + } + + protected double GetSecond(double serialNumber) { + return GetSeconds(serialNumber) % 60; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs index f9c213d..4a76f6f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeStringParser.cs
@@ -7,122 +7,111 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Text.RegularExpressions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class TimeStringParser - { - private const string RegEx24 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}$"; - private const string RegEx12 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}( PM| AM)$"; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - private double GetSerialNumber(int hour, int minute, int second) - { - var secondsInADay = 24d * 60d * 60d; - return ((double)hour * 60 * 60 + (double)minute * 60 + (double)second) / secondsInADay; - } +public class TimeStringParser { + private const string _regEx24 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}$"; + private const string _regEx12 = @"^[0-9]{1,2}(\:[0-9]{1,2}){0,2}( PM| AM)$"; - private void ValidateValues(int hour, int minute, int second) - { - if (second < 0 || second > 59) - { - throw new FormatException("Illegal value for second: " + second); - } - if (minute < 0 || minute > 59) - { - throw new FormatException("Illegal value for minute: " + minute); - } - } + private double GetSerialNumber(int hour, int minute, int second) { + var secondsInADay = 24d * 60d * 60d; + return ((double)hour * 60 * 60 + (double)minute * 60 + second) / secondsInADay; + } - public virtual double Parse(string input) - { - return InternalParse(input); - } - - public virtual bool CanParse(string input) - { - System.DateTime dt; - return Regex.IsMatch(input, RegEx24) || Regex.IsMatch(input, RegEx12) || System.DateTime.TryParse(input, out dt); - } - - private double InternalParse(string input) - { - if (Regex.IsMatch(input, RegEx24)) - { - return Parse24HourTimeString(input); - } - if (Regex.IsMatch(input, RegEx12)) - { - return Parse12HourTimeString(input); - } - System.DateTime dateTime; - if (System.DateTime.TryParse(input, out dateTime)) - { - return GetSerialNumber(dateTime.Hour, dateTime.Minute, dateTime.Second); - } - return -1; - } - - private double Parse12HourTimeString(string input) - { - string dayPart = string.Empty; - dayPart = input.Substring(input.Length - 2, 2); - int hour; - int minute; - int second; - GetValuesFromString(input, out hour, out minute, out second); - if (dayPart == "PM") hour += 12; - ValidateValues(hour, minute, second); - return GetSerialNumber(hour, minute, second); - } - - private double Parse24HourTimeString(string input) - { - int hour; - int minute; - int second; - GetValuesFromString(input, out hour, out minute, out second); - ValidateValues(hour, minute, second); - return GetSerialNumber(hour, minute, second); - } - - private static void GetValuesFromString(string input, out int hour, out int minute, out int second) - { - hour = 0; - minute = 0; - second = 0; - - var items = input.Split(':'); - hour = int.Parse(items[0]); - if (items.Length > 1) - { - minute = int.Parse(items[1]); - } - if (items.Length > 2) - { - var val = items[2]; - val = Regex.Replace(val, "[^0-9]+$", string.Empty); - second = int.Parse(val); - } - } + private void ValidateValues(int hour, int minute, int second) { + if (second < 0 || second > 59) { + throw new FormatException("Illegal value for second: " + second); } + if (minute < 0 || minute > 59) { + throw new FormatException("Illegal value for minute: " + minute); + } + } + + public virtual double Parse(string input) { + return InternalParse(input); + } + + public virtual bool CanParse(string input) { + System.DateTime dt; + return Regex.IsMatch(input, _regEx24) + || Regex.IsMatch(input, _regEx12) + || System.DateTime.TryParse(input, out dt); + } + + private double InternalParse(string input) { + if (Regex.IsMatch(input, _regEx24)) { + return Parse24HourTimeString(input); + } + if (Regex.IsMatch(input, _regEx12)) { + return Parse12HourTimeString(input); + } + System.DateTime dateTime; + if (System.DateTime.TryParse(input, out dateTime)) { + return GetSerialNumber(dateTime.Hour, dateTime.Minute, dateTime.Second); + } + return -1; + } + + private double Parse12HourTimeString(string input) { + string dayPart = string.Empty; + dayPart = input.Substring(input.Length - 2, 2); + int hour; + int minute; + int second; + GetValuesFromString(input, out hour, out minute, out second); + if (dayPart == "PM") { + hour += 12; + } + ValidateValues(hour, minute, second); + return GetSerialNumber(hour, minute, second); + } + + private double Parse24HourTimeString(string input) { + int hour; + int minute; + int second; + GetValuesFromString(input, out hour, out minute, out second); + ValidateValues(hour, minute, second); + return GetSerialNumber(hour, minute, second); + } + + private static void GetValuesFromString( + string input, + out int hour, + out int minute, + out int second) { + hour = 0; + minute = 0; + second = 0; + + var items = input.Split(':'); + hour = int.Parse(items[0]); + if (items.Length > 1) { + minute = int.Parse(items[1]); + } + if (items.Length > 2) { + var val = items[2]; + val = Regex.Replace(val, "[^0-9]+$", string.Empty); + second = int.Parse(val); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs index 89a6017..ac259b8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/TimeValue.cs
@@ -1,36 +1,32 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - /// <summary> - /// Simple implementation of TimeValue function, just using .NET built-in - /// function System.DateTime.TryParse, based on current culture - /// </summary> - public class TimeValue : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateString = ArgToString(arguments, 0); - return Execute(dateString); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - internal CompileResult Execute(string dateString) - { - System.DateTime result; - System.DateTime.TryParse(dateString, out result); - return result != System.DateTime.MinValue ? - CreateResult(GetTimeValue(result), DataType.Date) : - CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); - } +/// <summary> +/// Simple implementation of TimeValue function, just using .NET built-in +/// function System.DateTime.TryParse, based on current culture +/// </summary> +public class TimeValue : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateString = ArgToString(arguments, 0); + return Execute(dateString); + } - private double GetTimeValue(System.DateTime result) - { - return (int)result.TimeOfDay.TotalSeconds == 0 ? 0d : result.TimeOfDay.TotalSeconds/ (3600 * 24); - } - } + internal CompileResult Execute(string dateString) { + System.DateTime result; + System.DateTime.TryParse(dateString, out result); + return result != System.DateTime.MinValue + ? CreateResult(GetTimeValue(result), DataType.Date) + : CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); + } + + private double GetTimeValue(System.DateTime result) { + return (int)result.TimeOfDay.TotalSeconds == 0 + ? 0d + : result.TimeOfDay.TotalSeconds / (3600 * 24); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Today.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Today.cs index 1727e51..e6ff48f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Today.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Today.cs
@@ -7,34 +7,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Today : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return CreateResult(System.DateTime.Today.ToOADate(), DataType.Date); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Today : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return CreateResult(System.DateTime.Today.ToOADate(), DataType.Date); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs index f9ba7d4..533ce2a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weekday.cs
@@ -7,58 +7,56 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Weekday : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var serialNumber = ArgToDecimal(arguments, 0); - var returnType = arguments.Count() > 1 ? ArgToInt(arguments, 1) : 1; - return CreateResult(CalculateDayOfWeek(System.DateTime.FromOADate(serialNumber), returnType), DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - private static List<int> _oneBasedStartOnSunday = new List<int> { 1, 2, 3, 4, 5, 6, 7 }; - private static List<int> _oneBasedStartOnMonday = new List<int> { 7, 1, 2, 3, 4, 5, 6 }; - private static List<int> _zeroBasedStartOnSunday = new List<int> { 6, 0, 1, 2, 3, 4, 5 }; +public class Weekday : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var serialNumber = ArgToDecimal(arguments, 0); + var returnType = arguments.Count() > 1 ? ArgToInt(arguments, 1) : 1; + return CreateResult( + CalculateDayOfWeek(System.DateTime.FromOADate(serialNumber), returnType), + DataType.Integer); + } - private int CalculateDayOfWeek(System.DateTime dateTime, int returnType) - { - var dayIx = (int)dateTime.DayOfWeek; - switch (returnType) - { - case 1: - return _oneBasedStartOnSunday[dayIx]; - case 2: - return _oneBasedStartOnMonday[dayIx]; - case 3: - return _zeroBasedStartOnSunday[dayIx]; - default: - throw new ExcelErrorValueException(eErrorType.Num); - } - } + private static List<int> _oneBasedStartOnSunday = new() { 1, 2, 3, 4, 5, 6, 7 }; + private static List<int> _oneBasedStartOnMonday = new() { 7, 1, 2, 3, 4, 5, 6 }; + private static List<int> _zeroBasedStartOnSunday = new() { 6, 0, 1, 2, 3, 4, 5 }; + + private int CalculateDayOfWeek(System.DateTime dateTime, int returnType) { + var dayIx = (int)dateTime.DayOfWeek; + switch (returnType) { + case 1: + return _oneBasedStartOnSunday[dayIx]; + case 2: + return _oneBasedStartOnMonday[dayIx]; + case 3: + return _zeroBasedStartOnSunday[dayIx]; + default: + throw new ExcelErrorValueException(eErrorType.Num); } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs index 84b6629..f5c1b05 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Weeknum.cs
@@ -2,62 +2,57 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Weeknum : ExcelFunction - { - public override ExpressionGraph.CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1, eErrorType.Value); - var dateSerial = ArgToDecimal(arguments, 0); - var date = System.DateTime.FromOADate(dateSerial); - var startDay = DayOfWeek.Sunday; - if (arguments.Count() > 1) - { - var argStartDay = ArgToInt(arguments, 1); - switch (argStartDay) - { - case 1: - startDay = DayOfWeek.Sunday; - break; - case 2: - case 11: - startDay = DayOfWeek.Monday; - break; - case 12: - startDay = DayOfWeek.Tuesday; - break; - case 13: - startDay = DayOfWeek.Wednesday; - break; - case 14: - startDay = DayOfWeek.Thursday; - break; - case 15: - startDay = DayOfWeek.Friday; - break; - case 16: - startDay = DayOfWeek.Saturday; - break; - default: - // Not supported - ThrowExcelErrorValueException(eErrorType.Num); - break; - } - } - if (DateTimeFormatInfo.CurrentInfo == null) - { - throw new InvalidOperationException( - "Could not execute Weeknum function because DateTimeFormatInfo.CurrentInfo was null"); - } - var week = DateTimeFormatInfo.CurrentInfo.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstDay, - startDay); - return CreateResult(week, DataType.Integer); - } - - +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Weeknum : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1, eErrorType.Value); + var dateSerial = ArgToDecimal(arguments, 0); + var date = System.DateTime.FromOADate(dateSerial); + var startDay = DayOfWeek.Sunday; + if (arguments.Count() > 1) { + var argStartDay = ArgToInt(arguments, 1); + switch (argStartDay) { + case 1: + startDay = DayOfWeek.Sunday; + break; + case 2: + case 11: + startDay = DayOfWeek.Monday; + break; + case 12: + startDay = DayOfWeek.Tuesday; + break; + case 13: + startDay = DayOfWeek.Wednesday; + break; + case 14: + startDay = DayOfWeek.Thursday; + break; + case 15: + startDay = DayOfWeek.Friday; + break; + case 16: + startDay = DayOfWeek.Saturday; + break; + default: + // Not supported + ThrowExcelErrorValueException(eErrorType.Num); + break; + } } + if (DateTimeFormatInfo.CurrentInfo == null) { + throw new InvalidOperationException( + "Could not execute Weeknum function because DateTimeFormatInfo.CurrentInfo was null"); + } + var week = DateTimeFormatInfo.CurrentInfo.Calendar.GetWeekOfYear( + date, + CalendarWeekRule.FirstDay, + startDay); + return CreateResult(week, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workday.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workday.cs index 429191e..947bc3e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workday.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workday.cs
@@ -1,88 +1,79 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Workday : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var startDate = System.DateTime.FromOADate(ArgToInt(arguments, 0)); - var nWorkDays = ArgToInt(arguments, 1); - var resultDate = System.DateTime.MinValue; - var workdaysCounted = 0; - var tmpDate = startDate; - // first move forward to the first monday - while (tmpDate.DayOfWeek != DayOfWeek.Monday && (nWorkDays - workdaysCounted) > 0) - { - if (!IsHoliday(tmpDate)) workdaysCounted++; - tmpDate = tmpDate.AddDays(1); - } - // then calculate whole weeks - var nWholeWeeks = (nWorkDays - workdaysCounted) / 5; - tmpDate = tmpDate.AddDays(nWholeWeeks * 7); - workdaysCounted += nWholeWeeks * 5; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; - // calculate the rest - while (workdaysCounted < nWorkDays) - { - tmpDate = tmpDate.AddDays(1); - if (!IsHoliday(tmpDate)) workdaysCounted++; - } - resultDate = AdjustResultWithHolidays(tmpDate, arguments); - return CreateResult(resultDate.ToOADate(), DataType.Date); - } - - private System.DateTime AdjustResultWithHolidays(System.DateTime resultDate, - IEnumerable<FunctionArgument> arguments) - { - if (arguments.Count() == 2) return resultDate; - var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>; - if (holidays != null) - { - foreach (var arg in holidays) - { - if (ConvertUtil.IsNumeric(arg.Value)) - { - var dateSerial = ConvertUtil.GetValueDouble(arg.Value); - var holidayDate = System.DateTime.FromOADate(dateSerial); - if (!IsHoliday(holidayDate)) - { - resultDate = resultDate.AddDays(1); - } - } - } - } - else - { - var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; - if (range != null) - { - foreach (var cell in range) - { - if (ConvertUtil.IsNumeric(cell.Value)) - { - var dateSerial = ConvertUtil.GetValueDouble(cell.Value); - var holidayDate = System.DateTime.FromOADate(dateSerial); - if (!IsHoliday(holidayDate)) - { - resultDate = resultDate.AddDays(1); - } - } - } - } - } - return resultDate; - } - - private bool IsHoliday(System.DateTime date) - { - return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday; - } +public class Workday : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var startDate = System.DateTime.FromOADate(ArgToInt(arguments, 0)); + var nWorkDays = ArgToInt(arguments, 1); + var resultDate = System.DateTime.MinValue; + var workdaysCounted = 0; + var tmpDate = startDate; + // first move forward to the first monday + while (tmpDate.DayOfWeek != DayOfWeek.Monday && (nWorkDays - workdaysCounted) > 0) { + if (!IsHoliday(tmpDate)) { + workdaysCounted++; + } + tmpDate = tmpDate.AddDays(1); } + // then calculate whole weeks + var nWholeWeeks = (nWorkDays - workdaysCounted) / 5; + tmpDate = tmpDate.AddDays(nWholeWeeks * 7); + workdaysCounted += nWholeWeeks * 5; + + // calculate the rest + while (workdaysCounted < nWorkDays) { + tmpDate = tmpDate.AddDays(1); + if (!IsHoliday(tmpDate)) { + workdaysCounted++; + } + } + resultDate = AdjustResultWithHolidays(tmpDate, arguments); + return CreateResult(resultDate.ToOADate(), DataType.Date); + } + + private System.DateTime AdjustResultWithHolidays( + System.DateTime resultDate, + IEnumerable<FunctionArgument> arguments) { + if (arguments.Count() == 2) { + return resultDate; + } + var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>; + if (holidays != null) { + foreach (var arg in holidays) { + if (ConvertUtil.IsNumeric(arg.Value)) { + var dateSerial = ConvertUtil.GetValueDouble(arg.Value); + var holidayDate = System.DateTime.FromOADate(dateSerial); + if (!IsHoliday(holidayDate)) { + resultDate = resultDate.AddDays(1); + } + } + } + } else { + var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; + if (range != null) { + foreach (var cell in range) { + if (ConvertUtil.IsNumeric(cell.Value)) { + var dateSerial = ConvertUtil.GetValueDouble(cell.Value); + var holidayDate = System.DateTime.FromOADate(dateSerial); + if (!IsHoliday(holidayDate)) { + resultDate = resultDate.AddDays(1); + } + } + } + } + } + return resultDate; + } + + private bool IsHoliday(System.DateTime date) { + return date.DayOfWeek == DayOfWeek.Saturday || date.DayOfWeek == DayOfWeek.Sunday; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs index 9f89b3e..38bd021 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/AdditionalHolidayDays.cs
@@ -1,46 +1,41 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays -{ - public class AdditionalHolidayDays - { - private readonly FunctionArgument _holidayArg; - private readonly List<System.DateTime> _holidayDates = new List<System.DateTime>(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; - public AdditionalHolidayDays(FunctionArgument holidayArg) - { - _holidayArg = holidayArg; - Initialize(); - } +public class AdditionalHolidayDays { + private readonly FunctionArgument _holidayArg; + private readonly List<System.DateTime> _holidayDates = new(); - public IEnumerable<System.DateTime> AdditionalDates => _holidayDates; + public AdditionalHolidayDays(FunctionArgument holidayArg) { + _holidayArg = holidayArg; + Initialize(); + } - private void Initialize() - { - var holidays = _holidayArg.Value as IEnumerable<FunctionArgument>; - if (holidays != null) - { - foreach (var holidayDate in from arg in holidays where ConvertUtil.IsNumeric(arg.Value) select ConvertUtil.GetValueDouble(arg.Value) into dateSerial select System.DateTime.FromOADate(dateSerial)) - { - _holidayDates.Add(holidayDate); - } - } - var range = _holidayArg.Value as ExcelDataProvider.IRangeInfo; - if (range != null) - { - foreach (var holidayDate in from cell in range where ConvertUtil.IsNumeric(cell.Value) select ConvertUtil.GetValueDouble(cell.Value) into dateSerial select System.DateTime.FromOADate(dateSerial)) - { - _holidayDates.Add(holidayDate); - } - } - if (ConvertUtil.IsNumeric(_holidayArg.Value)) - { - _holidayDates.Add(System.DateTime.FromOADate(ConvertUtil.GetValueDouble(_holidayArg.Value))); - } - } + public IEnumerable<System.DateTime> AdditionalDates => _holidayDates; + + private void Initialize() { + var holidays = _holidayArg.Value as IEnumerable<FunctionArgument>; + if (holidays != null) { + foreach (var holidayDate in from arg in holidays + where ConvertUtil.IsNumeric(arg.Value) + select ConvertUtil.GetValueDouble(arg.Value) into dateSerial + select System.DateTime.FromOADate(dateSerial)) { + _holidayDates.Add(holidayDate); + } } + var range = _holidayArg.Value as ExcelDataProvider.IRangeInfo; + if (range != null) { + foreach (var holidayDate in from cell in range + where ConvertUtil.IsNumeric(cell.Value) + select ConvertUtil.GetValueDouble(cell.Value) into dateSerial + select System.DateTime.FromOADate(dateSerial)) { + _holidayDates.Add(holidayDate); + } + } + if (ConvertUtil.IsNumeric(_holidayArg.Value)) { + _holidayDates.Add(System.DateTime.FromOADate(ConvertUtil.GetValueDouble(_holidayArg.Value))); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs index de18cd7..3e866b0 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdays.cs
@@ -1,87 +1,70 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays -{ - public class HolidayWeekdays - { - private readonly List<DayOfWeek> _holidayDays = new List<DayOfWeek>(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; - public HolidayWeekdays() - :this(DayOfWeek.Saturday, DayOfWeek.Sunday) - { - - } +public class HolidayWeekdays { + private readonly List<DayOfWeek> _holidayDays = new(); - public int NumberOfWorkdaysPerWeek => 7 - _holidayDays.Count; + public HolidayWeekdays() + : this(DayOfWeek.Saturday, DayOfWeek.Sunday) {} - public HolidayWeekdays(params DayOfWeek[] holidayDays) - { - foreach (var dayOfWeek in holidayDays) - { - _holidayDays.Add(dayOfWeek); - } - } + public int NumberOfWorkdaysPerWeek => 7 - _holidayDays.Count; - public bool IsHolidayWeekday(System.DateTime dateTime) - { - return _holidayDays.Contains(dateTime.DayOfWeek); - } - - public System.DateTime AdjustResultWithHolidays(System.DateTime resultDate, - IEnumerable<FunctionArgument> arguments) - { - if (arguments.Count() == 2) return resultDate; - var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>; - if (holidays != null) - { - foreach (var arg in holidays) - { - if (ConvertUtil.IsNumeric(arg.Value)) - { - var dateSerial = ConvertUtil.GetValueDouble(arg.Value); - var holidayDate = System.DateTime.FromOADate(dateSerial); - if (!IsHolidayWeekday(holidayDate)) - { - resultDate = resultDate.AddDays(1); - } - } - } - } - else - { - var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; - if (range != null) - { - foreach (var cell in range) - { - if (ConvertUtil.IsNumeric(cell.Value)) - { - var dateSerial = ConvertUtil.GetValueDouble(cell.Value); - var holidayDate = System.DateTime.FromOADate(dateSerial); - if (!IsHolidayWeekday(holidayDate)) - { - resultDate = resultDate.AddDays(1); - } - } - } - } - } - return resultDate; - } - - public System.DateTime GetNextWorkday(System.DateTime date, WorkdayCalculationDirection direction = WorkdayCalculationDirection.Forward) - { - var changeParam = (int)direction; - var tmpDate = date.AddDays(changeParam); - while (IsHolidayWeekday(tmpDate)) - { - tmpDate = tmpDate.AddDays(changeParam); - } - return tmpDate; - } + public HolidayWeekdays(params DayOfWeek[] holidayDays) { + foreach (var dayOfWeek in holidayDays) { + _holidayDays.Add(dayOfWeek); } + } + + public bool IsHolidayWeekday(System.DateTime dateTime) { + return _holidayDays.Contains(dateTime.DayOfWeek); + } + + public System.DateTime AdjustResultWithHolidays( + System.DateTime resultDate, + IEnumerable<FunctionArgument> arguments) { + if (arguments.Count() == 2) { + return resultDate; + } + var holidays = arguments.ElementAt(2).Value as IEnumerable<FunctionArgument>; + if (holidays != null) { + foreach (var arg in holidays) { + if (ConvertUtil.IsNumeric(arg.Value)) { + var dateSerial = ConvertUtil.GetValueDouble(arg.Value); + var holidayDate = System.DateTime.FromOADate(dateSerial); + if (!IsHolidayWeekday(holidayDate)) { + resultDate = resultDate.AddDays(1); + } + } + } + } else { + var range = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; + if (range != null) { + foreach (var cell in range) { + if (ConvertUtil.IsNumeric(cell.Value)) { + var dateSerial = ConvertUtil.GetValueDouble(cell.Value); + var holidayDate = System.DateTime.FromOADate(dateSerial); + if (!IsHolidayWeekday(holidayDate)) { + resultDate = resultDate.AddDays(1); + } + } + } + } + } + return resultDate; + } + + public System.DateTime GetNextWorkday( + System.DateTime date, + WorkdayCalculationDirection direction = WorkdayCalculationDirection.Forward) { + var changeParam = (int)direction; + var tmpDate = date.AddDays(changeParam); + while (IsHolidayWeekday(tmpDate)) { + tmpDate = tmpDate.AddDays(changeParam); + } + return tmpDate; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs index 2a94e0f..cf17962 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/HolidayWeekdaysFactory.cs
@@ -1,76 +1,67 @@ -using System; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays -{ - public class HolidayWeekdaysFactory - { - private readonly DayOfWeek[] _dayOfWeekArray = new DayOfWeek[] - { - DayOfWeek.Monday, - DayOfWeek.Tuesday, - DayOfWeek.Wednesday, - DayOfWeek.Thursday, - DayOfWeek.Friday, - DayOfWeek.Saturday, - DayOfWeek.Sunday - }; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; - public HolidayWeekdays Create(string weekdays) - { - if(string.IsNullOrEmpty(weekdays) || weekdays.Length != 7) - throw new ArgumentException("Illegal weekday string", nameof(Weekday)); +public class HolidayWeekdaysFactory { + private readonly DayOfWeek[] _dayOfWeekArray = { + DayOfWeek.Monday, + DayOfWeek.Tuesday, + DayOfWeek.Wednesday, + DayOfWeek.Thursday, + DayOfWeek.Friday, + DayOfWeek.Saturday, + DayOfWeek.Sunday, + }; - var retVal = new List<DayOfWeek>(); - var arr = weekdays.ToCharArray(); - for(var i = 0; i < arr.Length;i++) - { - var ch = arr[i]; - if (ch == '1') - { - retVal.Add(_dayOfWeekArray[i]); - } - } - return new HolidayWeekdays(retVal.ToArray()); - } - - public HolidayWeekdays Create(int code) - { - switch (code) - { - case 1: - return new HolidayWeekdays(DayOfWeek.Saturday, DayOfWeek.Sunday); - case 2: - return new HolidayWeekdays(DayOfWeek.Sunday, DayOfWeek.Monday); - case 3: - return new HolidayWeekdays(DayOfWeek.Monday, DayOfWeek.Tuesday); - case 4: - return new HolidayWeekdays(DayOfWeek.Tuesday, DayOfWeek.Wednesday); - case 5: - return new HolidayWeekdays(DayOfWeek.Wednesday, DayOfWeek.Thursday); - case 6: - return new HolidayWeekdays(DayOfWeek.Thursday, DayOfWeek.Friday); - case 7: - return new HolidayWeekdays(DayOfWeek.Friday, DayOfWeek.Saturday); - case 11: - return new HolidayWeekdays(DayOfWeek.Sunday); - case 12: - return new HolidayWeekdays(DayOfWeek.Monday); - case 13: - return new HolidayWeekdays(DayOfWeek.Tuesday); - case 14: - return new HolidayWeekdays(DayOfWeek.Wednesday); - case 15: - return new HolidayWeekdays(DayOfWeek.Thursday); - case 16: - return new HolidayWeekdays(DayOfWeek.Friday); - case 17: - return new HolidayWeekdays(DayOfWeek.Saturday); - default: - throw new ArgumentException("Invalid code supplied to HolidayWeekdaysFactory: " + code); - } - } + public HolidayWeekdays Create(string weekdays) { + if (string.IsNullOrEmpty(weekdays) || weekdays.Length != 7) { + throw new ArgumentException("Illegal weekday string", nameof(Weekday)); } + + var retVal = new List<DayOfWeek>(); + var arr = weekdays.ToCharArray(); + for (var i = 0; i < arr.Length; i++) { + var ch = arr[i]; + if (ch == '1') { + retVal.Add(_dayOfWeekArray[i]); + } + } + return new(retVal.ToArray()); + } + + public HolidayWeekdays Create(int code) { + switch (code) { + case 1: + return new(DayOfWeek.Saturday, DayOfWeek.Sunday); + case 2: + return new(DayOfWeek.Sunday, DayOfWeek.Monday); + case 3: + return new(DayOfWeek.Monday, DayOfWeek.Tuesday); + case 4: + return new(DayOfWeek.Tuesday, DayOfWeek.Wednesday); + case 5: + return new(DayOfWeek.Wednesday, DayOfWeek.Thursday); + case 6: + return new(DayOfWeek.Thursday, DayOfWeek.Friday); + case 7: + return new(DayOfWeek.Friday, DayOfWeek.Saturday); + case 11: + return new(DayOfWeek.Sunday); + case 12: + return new(DayOfWeek.Monday); + case 13: + return new(DayOfWeek.Tuesday); + case 14: + return new(DayOfWeek.Wednesday); + case 15: + return new(DayOfWeek.Thursday); + case 16: + return new(DayOfWeek.Friday); + case 17: + return new(DayOfWeek.Saturday); + default: + throw new ArgumentException("Invalid code supplied to HolidayWeekdaysFactory: " + code); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs index ee10b65..c0f56b4 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculationDirection.cs
@@ -1,14 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Runtime.CompilerServices; -using System.Text; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays -{ - public enum WorkdayCalculationDirection - { - Forward = 1, - Backward = -1 - } +public enum WorkdayCalculationDirection { + Forward = 1, + Backward = -1, }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs index cbff556..e09e7ba 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculator.cs
@@ -1,128 +1,123 @@ -using System; -using System.Collections.Generic; using System.Linq; -using System.Security.Cryptography; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; -using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays -{ - public class WorkdayCalculator - { - private readonly HolidayWeekdays _holidayWeekdays; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; - public WorkdayCalculator() - : this(new HolidayWeekdays()) - {} +public class WorkdayCalculator { + private readonly HolidayWeekdays _holidayWeekdays; - public WorkdayCalculator(HolidayWeekdays holidayWeekdays) - { - _holidayWeekdays = holidayWeekdays; - } + public WorkdayCalculator() + : this(new()) {} - public WorkdayCalculatorResult CalculateNumberOfWorkdays(System.DateTime startDate, System.DateTime endDate) - { - var calcDirection = startDate < endDate - ? WorkdayCalculationDirection.Forward - : WorkdayCalculationDirection.Backward; - System.DateTime calcStartDate; - System.DateTime calcEndDate; - if (calcDirection == WorkdayCalculationDirection.Forward) - { - calcStartDate = startDate.Date; - calcEndDate = endDate.Date; - } - else - { - calcStartDate = endDate.Date; - calcEndDate = startDate.Date; - } - var nWholeWeeks = (int)calcEndDate.Subtract(calcStartDate).TotalDays/7; - var workdaysCounted = nWholeWeeks*_holidayWeekdays.NumberOfWorkdaysPerWeek; - if (!_holidayWeekdays.IsHolidayWeekday(calcStartDate)) - { - workdaysCounted++; - } - var tmpDate = calcStartDate.AddDays(nWholeWeeks*7); - while (tmpDate < calcEndDate) - { - tmpDate = tmpDate.AddDays(1); - if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) - { - workdaysCounted++; - } - } - return new WorkdayCalculatorResult(workdaysCounted, startDate, endDate, calcDirection); - } + public WorkdayCalculator(HolidayWeekdays holidayWeekdays) { + _holidayWeekdays = holidayWeekdays; + } - public WorkdayCalculatorResult CalculateWorkday(System.DateTime startDate, int nWorkDays) - { - var calcDirection = nWorkDays > 0 ? WorkdayCalculationDirection.Forward : WorkdayCalculationDirection.Backward; - var direction = (int) calcDirection; - nWorkDays *= direction; - var workdaysCounted = 0; - var tmpDate = startDate; - - // calculate whole weeks - var nWholeWeeks = nWorkDays / _holidayWeekdays.NumberOfWorkdaysPerWeek; - tmpDate = tmpDate.AddDays(nWholeWeeks * 7 * direction); - workdaysCounted += nWholeWeeks * _holidayWeekdays.NumberOfWorkdaysPerWeek; - - // calculate the rest - while (workdaysCounted < nWorkDays) - { - tmpDate = tmpDate.AddDays(direction); - if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) workdaysCounted++; - } - return new WorkdayCalculatorResult(workdaysCounted, startDate, tmpDate, calcDirection); - } - - public WorkdayCalculatorResult ReduceWorkdaysWithHolidays(WorkdayCalculatorResult calculatedResult, - FunctionArgument holidayArgument) - { - var startDate = calculatedResult.StartDate; - var endDate = calculatedResult.EndDate; - var additionalDays = new AdditionalHolidayDays(holidayArgument); - System.DateTime calcStartDate; - System.DateTime calcEndDate; - if (startDate < endDate) - { - calcStartDate = startDate; - calcEndDate = endDate; - } - else - { - calcStartDate = endDate; - calcEndDate = startDate; - } - var nAdditionalHolidayDays = additionalDays.AdditionalDates.Count(x => x >= calcStartDate && x <= calcEndDate && !_holidayWeekdays.IsHolidayWeekday(x)); - return new WorkdayCalculatorResult(calculatedResult.NumberOfWorkdays - nAdditionalHolidayDays, startDate, endDate, calculatedResult.Direction); - } - - public WorkdayCalculatorResult AdjustResultWithHolidays(WorkdayCalculatorResult calculatedResult, - FunctionArgument holidayArgument) - { - var startDate = calculatedResult.StartDate; - var endDate = calculatedResult.EndDate; - var direction = calculatedResult.Direction; - var workdaysCounted = calculatedResult.NumberOfWorkdays; - var additionalDays = new AdditionalHolidayDays(holidayArgument); - foreach (var date in additionalDays.AdditionalDates) - { - if (direction == WorkdayCalculationDirection.Forward && (date < startDate || date > endDate)) continue; - if (direction == WorkdayCalculationDirection.Backward && (date > startDate || date < endDate)) continue; - if (_holidayWeekdays.IsHolidayWeekday(date)) continue; - var tmpDate = _holidayWeekdays.GetNextWorkday(endDate, direction); - while (additionalDays.AdditionalDates.Contains(tmpDate)) - { - tmpDate = _holidayWeekdays.GetNextWorkday(tmpDate, direction); - } - workdaysCounted++; - endDate = tmpDate; - } - - return new WorkdayCalculatorResult(workdaysCounted, calculatedResult.StartDate, endDate, direction); - } + public WorkdayCalculatorResult CalculateNumberOfWorkdays( + System.DateTime startDate, + System.DateTime endDate) { + var calcDirection = + startDate < endDate + ? WorkdayCalculationDirection.Forward + : WorkdayCalculationDirection.Backward; + System.DateTime calcStartDate; + System.DateTime calcEndDate; + if (calcDirection == WorkdayCalculationDirection.Forward) { + calcStartDate = startDate.Date; + calcEndDate = endDate.Date; + } else { + calcStartDate = endDate.Date; + calcEndDate = startDate.Date; } + var nWholeWeeks = (int)calcEndDate.Subtract(calcStartDate).TotalDays / 7; + var workdaysCounted = nWholeWeeks * _holidayWeekdays.NumberOfWorkdaysPerWeek; + if (!_holidayWeekdays.IsHolidayWeekday(calcStartDate)) { + workdaysCounted++; + } + var tmpDate = calcStartDate.AddDays(nWholeWeeks * 7); + while (tmpDate < calcEndDate) { + tmpDate = tmpDate.AddDays(1); + if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) { + workdaysCounted++; + } + } + return new(workdaysCounted, startDate, endDate, calcDirection); + } + + public WorkdayCalculatorResult CalculateWorkday(System.DateTime startDate, int nWorkDays) { + var calcDirection = + nWorkDays > 0 ? WorkdayCalculationDirection.Forward : WorkdayCalculationDirection.Backward; + var direction = (int)calcDirection; + nWorkDays *= direction; + var workdaysCounted = 0; + var tmpDate = startDate; + + // calculate whole weeks + var nWholeWeeks = nWorkDays / _holidayWeekdays.NumberOfWorkdaysPerWeek; + tmpDate = tmpDate.AddDays(nWholeWeeks * 7 * direction); + workdaysCounted += nWholeWeeks * _holidayWeekdays.NumberOfWorkdaysPerWeek; + + // calculate the rest + while (workdaysCounted < nWorkDays) { + tmpDate = tmpDate.AddDays(direction); + if (!_holidayWeekdays.IsHolidayWeekday(tmpDate)) { + workdaysCounted++; + } + } + return new(workdaysCounted, startDate, tmpDate, calcDirection); + } + + public WorkdayCalculatorResult ReduceWorkdaysWithHolidays( + WorkdayCalculatorResult calculatedResult, + FunctionArgument holidayArgument) { + var startDate = calculatedResult.StartDate; + var endDate = calculatedResult.EndDate; + var additionalDays = new AdditionalHolidayDays(holidayArgument); + System.DateTime calcStartDate; + System.DateTime calcEndDate; + if (startDate < endDate) { + calcStartDate = startDate; + calcEndDate = endDate; + } else { + calcStartDate = endDate; + calcEndDate = startDate; + } + var nAdditionalHolidayDays = additionalDays.AdditionalDates.Count(x => + x >= calcStartDate && x <= calcEndDate && !_holidayWeekdays.IsHolidayWeekday(x)); + return new( + calculatedResult.NumberOfWorkdays - nAdditionalHolidayDays, + startDate, + endDate, + calculatedResult.Direction); + } + + public WorkdayCalculatorResult AdjustResultWithHolidays( + WorkdayCalculatorResult calculatedResult, + FunctionArgument holidayArgument) { + var startDate = calculatedResult.StartDate; + var endDate = calculatedResult.EndDate; + var direction = calculatedResult.Direction; + var workdaysCounted = calculatedResult.NumberOfWorkdays; + var additionalDays = new AdditionalHolidayDays(holidayArgument); + foreach (var date in additionalDays.AdditionalDates) { + if (direction == WorkdayCalculationDirection.Forward + && (date < startDate || date > endDate)) { + continue; + } + if (direction == WorkdayCalculationDirection.Backward + && (date > startDate || date < endDate)) { + continue; + } + if (_holidayWeekdays.IsHolidayWeekday(date)) { + continue; + } + var tmpDate = _holidayWeekdays.GetNextWorkday(endDate, direction); + while (additionalDays.AdditionalDates.Contains(tmpDate)) { + tmpDate = _holidayWeekdays.GetNextWorkday(tmpDate, direction); + } + workdaysCounted++; + endDate = tmpDate; + } + + return new(workdaysCounted, calculatedResult.StartDate, endDate, direction); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs index 420c5d8..a61a05e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Workdays/WorkdayCalculatorResult.cs
@@ -1,26 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Security.Cryptography.X509Certificates; -using System.Text; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime.Workdays -{ - public class WorkdayCalculatorResult - { - public WorkdayCalculatorResult(int numberOfWorkdays, System.DateTime startDate, System.DateTime endDate, WorkdayCalculationDirection direction) - { - NumberOfWorkdays = numberOfWorkdays; - StartDate = startDate; - EndDate = endDate; - Direction = direction; - } +public class WorkdayCalculatorResult { + public WorkdayCalculatorResult( + int numberOfWorkdays, + System.DateTime startDate, + System.DateTime endDate, + WorkdayCalculationDirection direction) { + NumberOfWorkdays = numberOfWorkdays; + StartDate = startDate; + EndDate = endDate; + Direction = direction; + } - public int NumberOfWorkdays { get; } + public int NumberOfWorkdays { get; } - public System.DateTime StartDate { get; } + public System.DateTime StartDate { get; } - public System.DateTime EndDate { get; } - public WorkdayCalculationDirection Direction { get; set; } - } + public System.DateTime EndDate { get; } + + public WorkdayCalculationDirection Direction { get; set; } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Year.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Year.cs index 4bdb565..103c487 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Year.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Year.cs
@@ -7,47 +7,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Year : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var dateObj = arguments.ElementAt(0).Value; - System.DateTime date = System.DateTime.MinValue; - if (dateObj is string) - { - date = System.DateTime.Parse(dateObj.ToString()); - } - else - { - var d = ArgToDecimal(arguments, 0); - date = System.DateTime.FromOADate(d); - } - return CreateResult(date.Year, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Year : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var dateObj = arguments.ElementAt(0).Value; + System.DateTime date = System.DateTime.MinValue; + if (dateObj is string) { + date = System.DateTime.Parse(dateObj.ToString()); + } else { + var d = ArgToDecimal(arguments, 0); + date = System.DateTime.FromOADate(d); } + return CreateResult(date.Year, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs index fcf39b6..440c46a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DateTime/Yearfrac.cs
@@ -1,89 +1,85 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime -{ - public class Yearfrac : ExcelFunction +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; + +public class Yearfrac : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 2); + var date1Num = ArgToDecimal(functionArguments, 0); + var date2Num = ArgToDecimal(functionArguments, 1); + if (date1Num + > date2Num) //Switch to make date1 the lowest date { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 2); - var date1Num = ArgToDecimal(functionArguments, 0); - var date2Num = ArgToDecimal(functionArguments, 1); - if (date1Num > date2Num) //Switch to make date1 the lowest date - { - var t = date1Num; - date1Num = date2Num; - date2Num = t; - var fa = functionArguments[1]; - functionArguments[1] = functionArguments[0]; - functionArguments[0] = fa; - } - var date1 = System.DateTime.FromOADate(date1Num); - var date2 = System.DateTime.FromOADate(date2Num); - - var basis = 0; - if (functionArguments.Count() > 2) - { - basis = ArgToInt(functionArguments, 2); - ThrowExcelErrorValueExceptionIf(() => basis < 0 || basis > 4, eErrorType.Num); - } - var func = context.Configuration.FunctionRepository.GetFunction("days360"); - var calendar = new GregorianCalendar(); - switch (basis) - { - case 0: - var d360Result = System.Math.Abs(func.Execute(functionArguments, context).ResultNumeric); - // reproducing excels behaviour - if (date1.Month == 2 && date2.Day==31) - { - var daysInFeb = calendar.IsLeapYear(date1.Year) ? 29 : 28; - if (date1.Day == daysInFeb) d360Result++; - } - return CreateResult(d360Result / 360d, DataType.Decimal); - case 1: - return CreateResult(System.Math.Abs((date2 - date1).TotalDays / CalculateAcutalYear(date1, date2)), DataType.Decimal); - case 2: - return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 360d), DataType.Decimal); - case 3: - return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 365d), DataType.Decimal); - case 4: - var args = functionArguments.ToList(); - args.Add(new FunctionArgument(true)); - double? result = System.Math.Abs(func.Execute(args, context).ResultNumeric / 360d); - return CreateResult(result.Value, DataType.Decimal); - default: - return null; - } - } - - private double CalculateAcutalYear(System.DateTime dt1, System.DateTime dt2) - { - var calendar = new GregorianCalendar(); - var perYear = 0d; - var nYears = dt2.Year - dt1.Year + 1; - for (var y = dt1.Year; y <= dt2.Year; ++y) - { - perYear += calendar.IsLeapYear(y) ? 366 : 365; - } - if (new System.DateTime(dt1.Year + 1, dt1.Month, dt1.Day) >= dt2) - { - nYears = 1; - perYear = 365; - if (calendar.IsLeapYear(dt1.Year) && dt1.Month <= 2) - perYear = 366; - else if (calendar.IsLeapYear(dt2.Year) && dt2.Month > 2) - perYear = 366; - else if (dt2.Month == 2 && dt2.Day == 29) - perYear = 366; - } - return perYear/(double) nYears; - } + var t = date1Num; + date1Num = date2Num; + date2Num = t; + var fa = functionArguments[1]; + functionArguments[1] = functionArguments[0]; + functionArguments[0] = fa; } + var date1 = System.DateTime.FromOADate(date1Num); + var date2 = System.DateTime.FromOADate(date2Num); + + var basis = 0; + if (functionArguments.Count() > 2) { + basis = ArgToInt(functionArguments, 2); + ThrowExcelErrorValueExceptionIf(() => basis < 0 || basis > 4, eErrorType.Num); + } + var func = context.Configuration.FunctionRepository.GetFunction("days360"); + var calendar = new GregorianCalendar(); + switch (basis) { + case 0: + var d360Result = System.Math.Abs(func.Execute(functionArguments, context).ResultNumeric); + // reproducing excels behaviour + if (date1.Month == 2 && date2.Day == 31) { + var daysInFeb = calendar.IsLeapYear(date1.Year) ? 29 : 28; + if (date1.Day == daysInFeb) { + d360Result++; + } + } + return CreateResult(d360Result / 360d, DataType.Decimal); + case 1: + return CreateResult( + System.Math.Abs((date2 - date1).TotalDays / CalculateAcutalYear(date1, date2)), + DataType.Decimal); + case 2: + return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 360d), DataType.Decimal); + case 3: + return CreateResult(System.Math.Abs((date2 - date1).TotalDays / 365d), DataType.Decimal); + case 4: + var args = functionArguments.ToList(); + args.Add(new(true)); + double? result = System.Math.Abs(func.Execute(args, context).ResultNumeric / 360d); + return CreateResult(result.Value, DataType.Decimal); + default: + return null; + } + } + + private double CalculateAcutalYear(System.DateTime dt1, System.DateTime dt2) { + var calendar = new GregorianCalendar(); + var perYear = 0d; + var nYears = dt2.Year - dt1.Year + 1; + for (var y = dt1.Year; y <= dt2.Year; ++y) { + perYear += calendar.IsLeapYear(y) ? 366 : 365; + } + if (new System.DateTime(dt1.Year + 1, dt1.Month, dt1.Day) >= dt2) { + nYears = 1; + perYear = 365; + if (calendar.IsLeapYear(dt1.Year) && dt1.Month <= 2) { + perYear = 366; + } else if (calendar.IsLeapYear(dt2.Year) && dt2.Month > 2) { + perYear = 366; + } else if (dt2.Month == 2 && dt2.Day == 29) { + perYear = 366; + } + } + return perYear / nYears; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs b/EPPlus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs index 5ebf850..208cfa2 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DecimalCompileResultValidator.cs
@@ -7,39 +7,32 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-26 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class DecimalCompileResultValidator : CompileResultValidator - { - public override void Validate(object obj) - { - var num = ConvertUtil.GetValueDouble(obj); - if (double.IsNaN(num) || double.IsInfinity(num)) - { - throw new ExcelErrorValueException(eErrorType.Num); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public class DecimalCompileResultValidator : CompileResultValidator { + public override void Validate(object obj) { + var num = ConvertUtil.GetValueDouble(obj); + if (double.IsNaN(num) || double.IsInfinity(num)) { + throw new ExcelErrorValueException(eErrorType.Num); } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs index f614909..d987c85 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DoubleArgumentParser.cs
@@ -7,53 +7,49 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Globalization; -using OfficeOpenXml.FormulaParsing.Utilities; -using OfficeOpenXml.FormulaParsing.Exceptions; -using util=OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class DoubleArgumentParser : ArgumentParser - { - public override object Parse(object obj) - { - Require.That(obj).Named("argument").IsNotNull(); - if (obj is ExcelDataProvider.IRangeInfo) - { - var r=((ExcelDataProvider.IRangeInfo)obj).FirstOrDefault(); - return r == null ? 0 : r.ValueDouble; - } - if (obj is double) return obj; - if (obj.IsNumeric()) return util.ConvertUtil.GetValueDouble(obj); - var str = obj != null ? obj.ToString() : string.Empty; - try - { - return double.Parse(str,CultureInfo.InvariantCulture); - } - catch// (Exception e) - { - throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); - } - } +using System.Globalization; +using System.Linq; +using OfficeOpenXml.FormulaParsing.Exceptions; +using OfficeOpenXml.FormulaParsing.Utilities; +using util = OfficeOpenXml.Utils; + +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public class DoubleArgumentParser : ArgumentParser { + public override object Parse(object obj) { + Require.That(obj).Named("argument").IsNotNull(); + if (obj is ExcelDataProvider.IRangeInfo) { + var r = ((ExcelDataProvider.IRangeInfo)obj).FirstOrDefault(); + return r == null ? 0 : r.ValueDouble; } + if (obj is double) { + return obj; + } + if (obj.IsNumeric()) { + return util.ConvertUtil.GetValueDouble(obj); + } + var str = obj != null ? obj.ToString() : string.Empty; + try { + return double.Parse(str, CultureInfo.InvariantCulture); + } catch // (Exception e) + { + throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs b/EPPlus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs index 5d21b0c..2ff7a2c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/DoubleEnumerableArgConverter.cs
@@ -7,83 +7,78 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class DoubleEnumerableArgConverter : CollectionFlattener<double> - { - public virtual IEnumerable<double> ConvertArgs(bool ignoreHidden, bool ignoreErrors, IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return base.FuncArgsToFlatEnumerable(arguments, (arg, argList) => - { - if (arg.IsExcelRange) - { - foreach (var cell in arg.ValueAsRangeInfo) - { - if(!ignoreErrors && cell.IsExcelError) throw new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString())); - if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context) && ConvertUtil.IsNumeric(cell.Value)) - { - argList.Add(cell.ValueDouble); - } - } - } - else - { - if(!ignoreErrors && arg.ValueIsExcelError) throw new ExcelErrorValueException(arg.ValueAsExcelErrorValue); - if (ConvertUtil.IsNumeric(arg.Value) && !CellStateHelper.ShouldIgnore(ignoreHidden, arg, context)) - { - argList.Add(ConvertUtil.GetValueDouble(arg.Value)); - } - } - }); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - public virtual IEnumerable<double> ConvertArgsIncludingOtherTypes(IEnumerable<FunctionArgument> arguments) - { - return base.FuncArgsToFlatEnumerable(arguments, (arg, argList) => - { - //var cellInfo = arg.Value as EpplusExcelDataProvider.CellInfo; - //var value = cellInfo != null ? cellInfo.Value : arg.Value; - if (arg.Value is ExcelDataProvider.IRangeInfo) - { - foreach (var cell in (ExcelDataProvider.IRangeInfo)arg.Value) - { - argList.Add(cell.ValueDoubleLogical); - } - } - else - { - if (arg.Value is double || arg.Value is int || arg.Value is bool) - { - argList.Add(Convert.ToDouble(arg.Value)); - } - else if (arg.Value is string) - { - argList.Add(0d); - } - } - }); - } - } +public class DoubleEnumerableArgConverter : CollectionFlattener<double> { + public virtual IEnumerable<double> ConvertArgs( + bool ignoreHidden, + bool ignoreErrors, + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return base.FuncArgsToFlatEnumerable( + arguments, + (arg, argList) => { + if (arg.IsExcelRange) { + foreach (var cell in arg.ValueAsRangeInfo) { + if (!ignoreErrors && cell.IsExcelError) { + throw new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString())); + } + if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context) + && ConvertUtil.IsNumeric(cell.Value)) { + argList.Add(cell.ValueDouble); + } + } + } else { + if (!ignoreErrors && arg.ValueIsExcelError) { + throw new ExcelErrorValueException(arg.ValueAsExcelErrorValue); + } + if (ConvertUtil.IsNumeric(arg.Value) + && !CellStateHelper.ShouldIgnore(ignoreHidden, arg, context)) { + argList.Add(ConvertUtil.GetValueDouble(arg.Value)); + } + } + }); + } + + public virtual IEnumerable<double> ConvertArgsIncludingOtherTypes( + IEnumerable<FunctionArgument> arguments) { + return base.FuncArgsToFlatEnumerable( + arguments, + (arg, argList) => { + //var cellInfo = arg.Value as EpplusExcelDataProvider.CellInfo; + //var value = cellInfo != null ? cellInfo.Value : arg.Value; + if (arg.Value is ExcelDataProvider.IRangeInfo) { + foreach (var cell in (ExcelDataProvider.IRangeInfo)arg.Value) { + argList.Add(cell.ValueDoubleLogical); + } + } else { + if (arg.Value is double || arg.Value is int || arg.Value is bool) { + argList.Add(Convert.ToDouble(arg.Value)); + } else if (arg.Value is string) { + argList.Add(0d); + } + } + }); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs index bfc73ee..fb950a8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/ErrorHandlingFunction.cs
@@ -7,54 +7,42 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - /// <summary> - /// Base class for functions that handles an error that occurs during the - /// normal execution of the function. - /// If an exception occurs during the Execute-call that exception will be - /// caught by the compiler, then the HandleError-method will be called. - /// </summary> - public abstract class ErrorHandlingFunction : ExcelFunction - { - /// <summary> - /// Indicates that the function is an ErrorHandlingFunction. - /// </summary> - public override bool IsErrorHandlingFunction - { - get - { - return true; - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - /// <summary> - /// Method that should be implemented to handle the error. - /// </summary> - /// <param name="errorCode"></param> - /// <returns></returns> - public abstract CompileResult HandleError(string errorCode); - } +/// <summary> +/// Base class for functions that handles an error that occurs during the +/// normal execution of the function. +/// If an exception occurs during the Execute-call that exception will be +/// caught by the compiler, then the HandleError-method will be called. +/// </summary> +public abstract class ErrorHandlingFunction : ExcelFunction { + /// <summary> + /// Indicates that the function is an ErrorHandlingFunction. + /// </summary> + public override bool IsErrorHandlingFunction => true; + + /// <summary> + /// Method that should be implemented to handle the error. + /// </summary> + /// <param name="errorCode"></param> + /// <returns></returns> + public abstract CompileResult HandleError(string errorCode); }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs index 01e3568..ad03cae 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/ExcelFunction.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,447 +7,433 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System.Globalization; -using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.FormulaParsing.Exceptions; -using System.Collections; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; +using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - /// <summary> - /// Base class for Excel function implementations. - /// </summary> - public abstract class ExcelFunction - { - public ExcelFunction() - : this(new ArgumentCollectionUtil(), new ArgumentParsers(), new CompileResultValidators()) - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - } +/// <summary> +/// Base class for Excel function implementations. +/// </summary> +public abstract class ExcelFunction { + public ExcelFunction() + : this(new(), new(), new()) {} - public ExcelFunction( - ArgumentCollectionUtil argumentCollectionUtil, - ArgumentParsers argumentParsers, - CompileResultValidators compileResultValidators) - { - _argumentCollectionUtil = argumentCollectionUtil; - _argumentParsers = argumentParsers; - _compileResultValidators = compileResultValidators; - } + public ExcelFunction( + ArgumentCollectionUtil argumentCollectionUtil, + ArgumentParsers argumentParsers, + CompileResultValidators compileResultValidators) { + _argumentCollectionUtil = argumentCollectionUtil; + _argumentParsers = argumentParsers; + _compileResultValidators = compileResultValidators; + } - private readonly ArgumentCollectionUtil _argumentCollectionUtil; - private readonly ArgumentParsers _argumentParsers; - private readonly CompileResultValidators _compileResultValidators; + private readonly ArgumentCollectionUtil _argumentCollectionUtil; + private readonly ArgumentParsers _argumentParsers; + private readonly CompileResultValidators _compileResultValidators; - /// <summary> - /// - /// </summary> - /// <param name="arguments">Arguments to the function, each argument can contain primitive types, lists or <see cref="ExcelDataProvider.IRangeInfo">Excel ranges</see></param> - /// <param name="context">The <see cref="ParsingContext"/> contains various data that can be useful in functions.</param> - /// <returns>A <see cref="CompileResult"/> containing the calculated value</returns> - public abstract CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context); + /// <summary> + /// + /// </summary> + /// <param name="arguments">Arguments to the function, each argument can contain primitive types, lists or <see cref="ExcelDataProvider.IRangeInfo">Excel ranges</see></param> + /// <param name="context">The <see cref="ParsingContext"/> contains various data that can be useful in functions.</param> + /// <returns>A <see cref="CompileResult"/> containing the calculated value</returns> + public abstract CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context); - /// <summary> - /// If overridden, this method is called before Execute is called. - /// </summary> - /// <param name="context"></param> - public virtual void BeforeInvoke(ParsingContext context) { } + /// <summary> + /// If overridden, this method is called before Execute is called. + /// </summary> + /// <param name="context"></param> + public virtual void BeforeInvoke(ParsingContext context) {} - public virtual bool IsLookupFuction - { - get - { - return false; - } - } + public virtual bool IsLookupFuction => false; - public virtual bool IsErrorHandlingFunction - { - get - { - return false; - } - } - - /// <summary> - /// Used for some Lookupfunctions to indicate that function arguments should - /// not be compiled before the function is called. - /// </summary> - public bool SkipArgumentEvaluation { get; set; } - protected object GetFirstValue(IEnumerable<FunctionArgument> val) - { - var arg = ((IEnumerable<FunctionArgument>)val).FirstOrDefault(); - if(arg.Value is ExcelDataProvider.IRangeInfo) - { - //var r=((ExcelDataProvider.IRangeInfo)arg); - var r = arg.ValueAsRangeInfo; - return r.GetValue(r.Address._fromRow, r.Address._fromCol); - } - else - { - return arg==null?null:arg.Value; - } - } - /// <summary> - /// This functions validates that the supplied <paramref name="arguments"/> contains at least - /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an - /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in - /// that range will be counted as well. - /// </summary> - /// <param name="arguments"></param> - /// <param name="minLength"></param> - /// <param name="errorTypeToThrow">The <see cref="eErrorType"/> of the <see cref="ExcelErrorValueException"/> that will be thrown if <paramref name="minLength"/> is not met.</param> - protected void ValidateArguments(IEnumerable<FunctionArgument> arguments, int minLength, - eErrorType errorTypeToThrow) - { - Require.That(arguments).Named("arguments").IsNotNull(); - ThrowExcelErrorValueExceptionIf(() => - { - var nArgs = 0; - if (arguments.Any()) - { - foreach (var arg in arguments) - { - nArgs++; - if (nArgs >= minLength) return false; - if (arg.IsExcelRange) - { - nArgs += arg.ValueAsRangeInfo.GetNCells(); - if (nArgs >= minLength) return false; - } - } - } - return true; - }, errorTypeToThrow); - } + public virtual bool IsErrorHandlingFunction => false; - /// <summary> - /// This functions validates that the supplied <paramref name="arguments"/> contains at least - /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an - /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in - /// that range will be counted as well. - /// </summary> - /// <param name="arguments"></param> - /// <param name="minLength"></param> - /// <exception cref="ArgumentException"></exception> - protected void ValidateArguments(IEnumerable<FunctionArgument> arguments, int minLength) - { - Require.That(arguments).Named("arguments").IsNotNull(); - ThrowArgumentExceptionIf(() => - { - var nArgs = 0; - if (arguments.Any()) - { - foreach (var arg in arguments) - { - nArgs++; - if (nArgs >= minLength) return false; - if (arg.IsExcelRange) - { - nArgs += arg.ValueAsRangeInfo.GetNCells(); - if (nArgs >= minLength) return false; - } - } - } - return true; - }, "Expecting at least {0} arguments", minLength.ToString()); - } + /// <summary> + /// Used for some Lookupfunctions to indicate that function arguments should + /// not be compiled before the function is called. + /// </summary> + public bool SkipArgumentEvaluation { get; set; } - /// <summary> - /// Returns the value of the argument att the position of the 0-based - /// <paramref name="index"/> as an integer. - /// </summary> - /// <param name="arguments"></param> - /// <param name="index"></param> - /// <returns>Value of the argument as an integer.</returns> - /// <exception cref="ExcelErrorValueException"></exception> - protected int ArgToInt(IEnumerable<FunctionArgument> arguments, int index) - { - var val = arguments.ElementAt(index).ValueFirst; - return (int)_argumentParsers.GetParser(DataType.Integer).Parse(val); - } - - /// <summary> - /// Returns the value of the argument att the position of the 0-based - /// <paramref name="index"/> as a string. - /// </summary> - /// <param name="arguments"></param> - /// <param name="index"></param> - /// <returns>Value of the argument as a string.</returns> - protected string ArgToString(IEnumerable<FunctionArgument> arguments, int index) - { - var obj = arguments.ElementAt(index).ValueFirst; - return obj != null ? obj.ToString() : string.Empty; - } - - /// <summary> - /// Returns the value of the argument att the position of the 0-based - /// </summary> - /// <param name="obj"></param> - /// <returns>Value of the argument as a double.</returns> - /// <exception cref="ExcelErrorValueException"></exception> - protected double ArgToDecimal(object obj) - { - return (double)_argumentParsers.GetParser(DataType.Decimal).Parse(obj); - } - - /// <summary> - /// Returns the value of the argument att the position of the 0-based - /// <paramref name="index"/> as a <see cref="System.Double"/>. - /// </summary> - /// <param name="arguments"></param> - /// <param name="index"></param> - /// <returns>Value of the argument as an integer.</returns> - /// <exception cref="ExcelErrorValueException"></exception> - protected double ArgToDecimal(IEnumerable<FunctionArgument> arguments, int index) - { - return ArgToDecimal(arguments.ElementAt(index).Value); - } - - protected double Divide(double left, double right) - { - if (System.Math.Abs(right - 0d) < double.Epsilon) - { - throw new ExcelErrorValueException(eErrorType.Div0); - } - return left/right; - } - - protected bool IsNumericString(object value) - { - if (value == null || string.IsNullOrEmpty(value.ToString())) return false; - return Regex.IsMatch(value.ToString(), @"^[\d]+(\,[\d])?"); - } - - /// <summary> - /// If the argument is a boolean value its value will be returned. - /// If the argument is an integer value, true will be returned if its - /// value is not 0, otherwise false. - /// </summary> - /// <param name="arguments"></param> - /// <param name="index"></param> - /// <returns></returns> - protected bool ArgToBool(IEnumerable<FunctionArgument> arguments, int index) - { - var obj = arguments.ElementAt(index).Value ?? string.Empty; - return (bool)_argumentParsers.GetParser(DataType.Boolean).Parse(obj); - } - - /// <summary> - /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true. - /// </summary> - /// <param name="condition"></param> - /// <param name="message"></param> - /// <exception cref="ArgumentException"></exception> - protected void ThrowArgumentExceptionIf(Func<bool> condition, string message) - { - if (condition()) - { - throw new ArgumentException(message); - } - } - - /// <summary> - /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true. - /// </summary> - /// <param name="condition"></param> - /// <param name="message"></param> - /// <param name="formats">Formats to the message string.</param> - protected void ThrowArgumentExceptionIf(Func<bool> condition, string message, params object[] formats) - { - message = string.Format(message, formats); - ThrowArgumentExceptionIf(condition, message); - } - - /// <summary> - /// Throws an <see cref="ExcelErrorValueException"/> with the given <paramref name="errorType"/> set. - /// </summary> - /// <param name="errorType"></param> - protected void ThrowExcelErrorValueException(eErrorType errorType) - { - throw new ExcelErrorValueException("An excel function error occurred", ExcelErrorValue.Create(errorType)); - } - - /// <summary> - /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true. - /// </summary> - /// <param name="condition"></param> - /// <param name="errorType"></param> - /// <exception cref="ExcelErrorValueException"></exception> - protected void ThrowExcelErrorValueExceptionIf(Func<bool> condition, eErrorType errorType) - { - if (condition()) - { - throw new ExcelErrorValueException("An excel function error occurred", ExcelErrorValue.Create(errorType)); - } - } - - protected bool IsNumeric(object val) - { - if (val == null) return false; - return (val.GetType().IsPrimitive || val is double || val is decimal || val is System.DateTime || val is TimeSpan); - } - - //protected virtual bool IsNumber(object obj) - //{ - // if (obj == null) return false; - // return (obj is int || obj is double || obj is short || obj is decimal || obj is long); - //} - - /// <summary> - /// Helper method for comparison of two doubles. - /// </summary> - /// <param name="d1"></param> - /// <param name="d2"></param> - /// <returns></returns> - protected bool AreEqual(double d1, double d2) - { - return System.Math.Abs(d1 - d2) < double.Epsilon; - } - - /// <summary> - /// Will return the arguments as an enumerable of doubles. - /// </summary> - /// <param name="arguments"></param> - /// <param name="context"></param> - /// <returns></returns> - protected virtual IEnumerable<double> ArgsToDoubleEnumerable(IEnumerable<FunctionArgument> arguments, - ParsingContext context) - { - return ArgsToDoubleEnumerable(false, arguments, context); - } - - /// <summary> - /// Will return the arguments as an enumerable of doubles. - /// </summary> - /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param> - /// <param name="ignoreErrors">If a cell contains an error, that error will be ignored if this method is set to true</param> - /// <param name="arguments"></param> - /// <param name="context"></param> - /// <returns></returns> - protected virtual IEnumerable<double> ArgsToDoubleEnumerable(bool ignoreHiddenCells, bool ignoreErrors, IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return _argumentCollectionUtil.ArgsToDoubleEnumerable(ignoreHiddenCells, ignoreErrors, arguments, context); - } - - /// <summary> - /// Will return the arguments as an enumerable of doubles. - /// </summary> - /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param> - /// <param name="arguments"></param> - /// <param name="context"></param> - /// <returns></returns> - protected virtual IEnumerable<double> ArgsToDoubleEnumerable(bool ignoreHiddenCells, IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return ArgsToDoubleEnumerable(ignoreHiddenCells, true, arguments, context); - } - - /// <summary> - /// Will return the arguments as an enumerable of objects. - /// </summary> - /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param> - /// <param name="arguments"></param> - /// <param name="context"></param> - /// <returns></returns> - protected virtual IEnumerable<object> ArgsToObjectEnumerable(bool ignoreHiddenCells, IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return _argumentCollectionUtil.ArgsToObjectEnumerable(ignoreHiddenCells, arguments, context); - } - - /// <summary> - /// Use this method to create a result to return from Excel functions. - /// </summary> - /// <param name="result"></param> - /// <param name="dataType"></param> - /// <returns></returns> - protected CompileResult CreateResult(object result, DataType dataType) - { - var validator = _compileResultValidators.GetValidator(dataType); - validator.Validate(result); - return new CompileResult(result, dataType); - } - - /// <summary> - /// Use this method to apply a function on a collection of arguments. The <paramref name="result"/> - /// should be modifyed in the supplied <paramref name="action"/> and will contain the result - /// after this operation has been performed. - /// </summary> - /// <param name="collection"></param> - /// <param name="result"></param> - /// <param name="action"></param> - /// <returns></returns> - protected virtual double CalculateCollection(IEnumerable<FunctionArgument> collection, double result, Func<FunctionArgument,double,double> action) - { - return _argumentCollectionUtil.CalculateCollection(collection, result, action); - } - - /// <summary> - /// if the supplied <paramref name="arg">argument</paramref> contains an Excel error - /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown - /// </summary> - /// <param name="arg"></param> - /// <exception cref="ExcelErrorValueException"></exception> - protected void CheckForAndHandleExcelError(FunctionArgument arg) - { - if (arg.ValueIsExcelError) - { - throw (new ExcelErrorValueException(arg.ValueAsExcelErrorValue)); - } - } - - /// <summary> - /// If the supplied <paramref name="cell"/> contains an Excel error - /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown - /// </summary> - /// <param name="cell"></param> - protected void CheckForAndHandleExcelError(ExcelDataProvider.ICellInfo cell) - { - if (cell.IsExcelError) - { - throw (new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString()))); - } - } - - protected CompileResult GetResultByObject(object result) - { - if (IsNumeric(result)) - { - return CreateResult(result, DataType.Decimal); - } - if (result is string) - { - return CreateResult(result, DataType.String); - } - if (ExcelErrorValue.Values.IsErrorValue(result)) - { - return CreateResult(result, DataType.ExcelAddress); - } - if (result == null) - { - return CompileResult.Empty; - } - return CreateResult(result, DataType.Enumerable); - } + protected object GetFirstValue(IEnumerable<FunctionArgument> val) { + var arg = val.FirstOrDefault(); + if (arg.Value is ExcelDataProvider.IRangeInfo) { + //var r=((ExcelDataProvider.IRangeInfo)arg); + var r = arg.ValueAsRangeInfo; + return r.GetValue(r.Address._fromRow, r.Address._fromCol); } + return arg == null ? null : arg.Value; + } + + /// <summary> + /// This functions validates that the supplied <paramref name="arguments"/> contains at least + /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an + /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in + /// that range will be counted as well. + /// </summary> + /// <param name="arguments"></param> + /// <param name="minLength"></param> + /// <param name="errorTypeToThrow">The <see cref="eErrorType"/> of the <see cref="ExcelErrorValueException"/> that will be thrown if <paramref name="minLength"/> is not met.</param> + protected void ValidateArguments( + IEnumerable<FunctionArgument> arguments, + int minLength, + eErrorType errorTypeToThrow) { + Require.That(arguments).Named("arguments").IsNotNull(); + ThrowExcelErrorValueExceptionIf( + () => { + var nArgs = 0; + if (arguments.Any()) { + foreach (var arg in arguments) { + nArgs++; + if (nArgs >= minLength) { + return false; + } + if (arg.IsExcelRange) { + nArgs += arg.ValueAsRangeInfo.GetNCells(); + if (nArgs >= minLength) { + return false; + } + } + } + } + return true; + }, + errorTypeToThrow); + } + + /// <summary> + /// This functions validates that the supplied <paramref name="arguments"/> contains at least + /// (the value of) <paramref name="minLength"/> elements. If one of the arguments is an + /// <see cref="ExcelDataProvider.IRangeInfo">Excel range</see> the number of cells in + /// that range will be counted as well. + /// </summary> + /// <param name="arguments"></param> + /// <param name="minLength"></param> + /// <exception cref="ArgumentException"></exception> + protected void ValidateArguments(IEnumerable<FunctionArgument> arguments, int minLength) { + Require.That(arguments).Named("arguments").IsNotNull(); + ThrowArgumentExceptionIf( + () => { + var nArgs = 0; + if (arguments.Any()) { + foreach (var arg in arguments) { + nArgs++; + if (nArgs >= minLength) { + return false; + } + if (arg.IsExcelRange) { + nArgs += arg.ValueAsRangeInfo.GetNCells(); + if (nArgs >= minLength) { + return false; + } + } + } + } + return true; + }, + "Expecting at least {0} arguments", + minLength.ToString()); + } + + /// <summary> + /// Returns the value of the argument att the position of the 0-based + /// <paramref name="index"/> as an integer. + /// </summary> + /// <param name="arguments"></param> + /// <param name="index"></param> + /// <returns>Value of the argument as an integer.</returns> + /// <exception cref="ExcelErrorValueException"></exception> + protected int ArgToInt(IEnumerable<FunctionArgument> arguments, int index) { + var val = arguments.ElementAt(index).ValueFirst; + return (int)_argumentParsers.GetParser(DataType.Integer).Parse(val); + } + + /// <summary> + /// Returns the value of the argument att the position of the 0-based + /// <paramref name="index"/> as a string. + /// </summary> + /// <param name="arguments"></param> + /// <param name="index"></param> + /// <returns>Value of the argument as a string.</returns> + protected string ArgToString(IEnumerable<FunctionArgument> arguments, int index) { + var obj = arguments.ElementAt(index).ValueFirst; + return obj != null ? obj.ToString() : string.Empty; + } + + /// <summary> + /// Returns the value of the argument att the position of the 0-based + /// </summary> + /// <param name="obj"></param> + /// <returns>Value of the argument as a double.</returns> + /// <exception cref="ExcelErrorValueException"></exception> + protected double ArgToDecimal(object obj) { + return (double)_argumentParsers.GetParser(DataType.Decimal).Parse(obj); + } + + /// <summary> + /// Returns the value of the argument att the position of the 0-based + /// <paramref name="index"/> as a <see cref="System.Double"/>. + /// </summary> + /// <param name="arguments"></param> + /// <param name="index"></param> + /// <returns>Value of the argument as an integer.</returns> + /// <exception cref="ExcelErrorValueException"></exception> + protected double ArgToDecimal(IEnumerable<FunctionArgument> arguments, int index) { + return ArgToDecimal(arguments.ElementAt(index).Value); + } + + protected double Divide(double left, double right) { + if (System.Math.Abs(right - 0d) < double.Epsilon) { + throw new ExcelErrorValueException(eErrorType.Div0); + } + return left / right; + } + + protected bool IsNumericString(object value) { + if (value == null || string.IsNullOrEmpty(value.ToString())) { + return false; + } + return Regex.IsMatch(value.ToString(), @"^[\d]+(\,[\d])?"); + } + + /// <summary> + /// If the argument is a boolean value its value will be returned. + /// If the argument is an integer value, true will be returned if its + /// value is not 0, otherwise false. + /// </summary> + /// <param name="arguments"></param> + /// <param name="index"></param> + /// <returns></returns> + protected bool ArgToBool(IEnumerable<FunctionArgument> arguments, int index) { + var obj = arguments.ElementAt(index).Value ?? string.Empty; + return (bool)_argumentParsers.GetParser(DataType.Boolean).Parse(obj); + } + + /// <summary> + /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true. + /// </summary> + /// <param name="condition"></param> + /// <param name="message"></param> + /// <exception cref="ArgumentException"></exception> + protected void ThrowArgumentExceptionIf(Func<bool> condition, string message) { + if (condition()) { + throw new ArgumentException(message); + } + } + + /// <summary> + /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true. + /// </summary> + /// <param name="condition"></param> + /// <param name="message"></param> + /// <param name="formats">Formats to the message string.</param> + protected void ThrowArgumentExceptionIf( + Func<bool> condition, + string message, + params object[] formats) { + message = string.Format(message, formats); + ThrowArgumentExceptionIf(condition, message); + } + + /// <summary> + /// Throws an <see cref="ExcelErrorValueException"/> with the given <paramref name="errorType"/> set. + /// </summary> + /// <param name="errorType"></param> + protected void ThrowExcelErrorValueException(eErrorType errorType) { + throw new ExcelErrorValueException( + "An excel function error occurred", + ExcelErrorValue.Create(errorType)); + } + + /// <summary> + /// Throws an <see cref="ArgumentException"/> if <paramref name="condition"/> evaluates to true. + /// </summary> + /// <param name="condition"></param> + /// <param name="errorType"></param> + /// <exception cref="ExcelErrorValueException"></exception> + protected void ThrowExcelErrorValueExceptionIf(Func<bool> condition, eErrorType errorType) { + if (condition()) { + throw new ExcelErrorValueException( + "An excel function error occurred", + ExcelErrorValue.Create(errorType)); + } + } + + protected bool IsNumeric(object val) { + if (val == null) { + return false; + } + return (val.GetType().IsPrimitive + || val is double + || val is decimal + || val is System.DateTime + || val is TimeSpan); + } + + //protected virtual bool IsNumber(object obj) + //{ + // if (obj == null) return false; + // return (obj is int || obj is double || obj is short || obj is decimal || obj is long); + //} + + /// <summary> + /// Helper method for comparison of two doubles. + /// </summary> + /// <param name="d1"></param> + /// <param name="d2"></param> + /// <returns></returns> + protected bool AreEqual(double d1, double d2) { + return System.Math.Abs(d1 - d2) < double.Epsilon; + } + + /// <summary> + /// Will return the arguments as an enumerable of doubles. + /// </summary> + /// <param name="arguments"></param> + /// <param name="context"></param> + /// <returns></returns> + protected virtual IEnumerable<double> ArgsToDoubleEnumerable( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return ArgsToDoubleEnumerable(false, arguments, context); + } + + /// <summary> + /// Will return the arguments as an enumerable of doubles. + /// </summary> + /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param> + /// <param name="ignoreErrors">If a cell contains an error, that error will be ignored if this method is set to true</param> + /// <param name="arguments"></param> + /// <param name="context"></param> + /// <returns></returns> + protected virtual IEnumerable<double> ArgsToDoubleEnumerable( + bool ignoreHiddenCells, + bool ignoreErrors, + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return _argumentCollectionUtil.ArgsToDoubleEnumerable( + ignoreHiddenCells, + ignoreErrors, + arguments, + context); + } + + /// <summary> + /// Will return the arguments as an enumerable of doubles. + /// </summary> + /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param> + /// <param name="arguments"></param> + /// <param name="context"></param> + /// <returns></returns> + protected virtual IEnumerable<double> ArgsToDoubleEnumerable( + bool ignoreHiddenCells, + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return ArgsToDoubleEnumerable(ignoreHiddenCells, true, arguments, context); + } + + /// <summary> + /// Will return the arguments as an enumerable of objects. + /// </summary> + /// <param name="ignoreHiddenCells">If a cell is hidden and this value is true the value of that cell will be ignored</param> + /// <param name="arguments"></param> + /// <param name="context"></param> + /// <returns></returns> + protected virtual IEnumerable<object> ArgsToObjectEnumerable( + bool ignoreHiddenCells, + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return _argumentCollectionUtil.ArgsToObjectEnumerable(ignoreHiddenCells, arguments, context); + } + + /// <summary> + /// Use this method to create a result to return from Excel functions. + /// </summary> + /// <param name="result"></param> + /// <param name="dataType"></param> + /// <returns></returns> + protected CompileResult CreateResult(object result, DataType dataType) { + var validator = _compileResultValidators.GetValidator(dataType); + validator.Validate(result); + return new(result, dataType); + } + + /// <summary> + /// Use this method to apply a function on a collection of arguments. The <paramref name="result"/> + /// should be modifyed in the supplied <paramref name="action"/> and will contain the result + /// after this operation has been performed. + /// </summary> + /// <param name="collection"></param> + /// <param name="result"></param> + /// <param name="action"></param> + /// <returns></returns> + protected virtual double CalculateCollection( + IEnumerable<FunctionArgument> collection, + double result, + Func<FunctionArgument, double, double> action) { + return _argumentCollectionUtil.CalculateCollection(collection, result, action); + } + + /// <summary> + /// if the supplied <paramref name="arg">argument</paramref> contains an Excel error + /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown + /// </summary> + /// <param name="arg"></param> + /// <exception cref="ExcelErrorValueException"></exception> + protected void CheckForAndHandleExcelError(FunctionArgument arg) { + if (arg.ValueIsExcelError) { + throw (new ExcelErrorValueException(arg.ValueAsExcelErrorValue)); + } + } + + /// <summary> + /// If the supplied <paramref name="cell"/> contains an Excel error + /// an <see cref="ExcelErrorValueException"/> with that errorcode will be thrown + /// </summary> + /// <param name="cell"></param> + protected void CheckForAndHandleExcelError(ExcelDataProvider.ICellInfo cell) { + if (cell.IsExcelError) { + throw (new ExcelErrorValueException(ExcelErrorValue.Parse(cell.Value.ToString()))); + } + } + + protected CompileResult GetResultByObject(object result) { + if (IsNumeric(result)) { + return CreateResult(result, DataType.Decimal); + } + if (result is string) { + return CreateResult(result, DataType.String); + } + if (ExcelErrorValue.Values.IsErrorValue(result)) { + return CreateResult(result, DataType.ExcelAddress); + } + if (result == null) { + return CompileResult.Empty; + } + return CreateResult(result, DataType.Enumerable); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionArgument.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionArgument.cs index 7e22905..7dec4b3 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/FunctionArgument.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/FunctionArgument.cs
@@ -7,92 +7,63 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class FunctionArgument - { - public FunctionArgument(object val) - { - Value = val; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - private ExcelCellState _excelCellState; +public class FunctionArgument { + public FunctionArgument(object val) { + Value = val; + } - public void SetExcelStateFlag(ExcelCellState state) - { - _excelCellState |= state; - } + private ExcelCellState _excelCellState; - public bool ExcelStateFlagIsSet(ExcelCellState state) - { - return (_excelCellState & state) != 0; - } + public void SetExcelStateFlag(ExcelCellState state) { + _excelCellState |= state; + } - public object Value { get; private set; } + public bool ExcelStateFlagIsSet(ExcelCellState state) { + return (_excelCellState & state) != 0; + } - public Type Type - { - get { return Value != null ? Value.GetType() : null; } - } + public object Value { get; private set; } - public bool IsExcelRange - { - get { return Value != null && Value is EpplusExcelDataProvider.IRangeInfo; } - } + public Type Type => Value != null ? Value.GetType() : null; - public bool ValueIsExcelError - { - get { return ExcelErrorValue.Values.IsErrorValue(Value); } - } + public bool IsExcelRange => Value != null && Value is ExcelDataProvider.IRangeInfo; - public ExcelErrorValue ValueAsExcelErrorValue - { - get { return ExcelErrorValue.Parse(Value.ToString()); } - } + public bool ValueIsExcelError => ExcelErrorValue.Values.IsErrorValue(Value); - public EpplusExcelDataProvider.IRangeInfo ValueAsRangeInfo - { - get { return Value as EpplusExcelDataProvider.IRangeInfo; } - } - public object ValueFirst - { - get - { - if (Value is ExcelDataProvider.INameInfo) - { - Value = ((ExcelDataProvider.INameInfo)Value).Value; - } - var v = Value as ExcelDataProvider.IRangeInfo; - if (v==null) - { - return Value; - } - else - { - return v.GetValue(v.Address._fromRow, v.Address._fromCol); - } - } - } + public ExcelErrorValue ValueAsExcelErrorValue => ExcelErrorValue.Parse(Value.ToString()); + public ExcelDataProvider.IRangeInfo ValueAsRangeInfo => Value as ExcelDataProvider.IRangeInfo; + + public object ValueFirst { + get { + if (Value is ExcelDataProvider.INameInfo) { + Value = ((ExcelDataProvider.INameInfo)Value).Value; + } + var v = Value as ExcelDataProvider.IRangeInfo; + if (v == null) { + return Value; + } + return v.GetValue(v.Address._fromRow, v.Address._fromCol); } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs index 514cc65..012a7c7 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/FunctionNameProvider.cs
@@ -7,44 +7,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel.Functions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class FunctionNameProvider : IFunctionNameProvider - { - private FunctionNameProvider() - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - } +public class FunctionNameProvider : IFunctionNameProvider { + private FunctionNameProvider() {} - public static FunctionNameProvider Empty - { - get { return new FunctionNameProvider(); } - } + public static FunctionNameProvider Empty => new(); - public virtual bool IsFunctionName(string name) - { - return false; - } - } + public virtual bool IsFunctionName(string name) { + return false; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs index 818cc56..42d7f0b 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/FunctionRepository.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,138 +7,114 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Utilities; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - // Used to report the names of Excel functions that are not supported by EPPlus - public class FunctionException : SystemException - { - // Summary: - // Initializes a new instance of the System.FunctionException class. - public FunctionException() - : base() - { - } - // - // Summary: - // Initializes a new instance of the System.FunctionException class with a specified - // error message. - // - // Parameters: - // message: - // The message that describes the error. - public FunctionException(string message) - : base(message) - { - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +// Used to report the names of Excel functions that are not supported by EPPlus +public class FunctionException : SystemException { + // Summary: + // Initializes a new instance of the System.FunctionException class. + public FunctionException() {} + + // + // Summary: + // Initializes a new instance of the System.FunctionException class with a specified + // error message. + // + // Parameters: + // message: + // The message that describes the error. + public FunctionException(string message) + : base(message) {} +} + +/// <summary> +/// This class provides methods for accessing/modifying VBA Functions. +/// </summary> +public class FunctionRepository : IFunctionNameProvider { + private Dictionary<string, ExcelFunction> _functions = new(StringComparer.InvariantCulture); + + private FunctionRepository() {} + + public static FunctionRepository Create() { + var repo = new FunctionRepository(); + repo.LoadModule(new BuiltInFunctions()); + return repo; + } + + /// <summary> + /// Loads a module of <see cref="ExcelFunction"/>s to the function repository. + /// </summary> + /// <param name="module">A <see cref="IFunctionModule"/> that can be used for adding functions</param> + public virtual void LoadModule(IFunctionModule module) { + foreach (var key in module.Functions.Keys) { + var lowerKey = key.ToLower(CultureInfo.InvariantCulture); + _functions[lowerKey] = module.Functions[key]; } + } - /// <summary> - /// This class provides methods for accessing/modifying VBA Functions. - /// </summary> - public class FunctionRepository : IFunctionNameProvider - { - private Dictionary<string, ExcelFunction> _functions = new Dictionary<string, ExcelFunction>(StringComparer.InvariantCulture); - - private FunctionRepository() - { - - } - - public static FunctionRepository Create() - { - var repo = new FunctionRepository(); - repo.LoadModule(new BuiltInFunctions()); - return repo; - } - - /// <summary> - /// Loads a module of <see cref="ExcelFunction"/>s to the function repository. - /// </summary> - /// <param name="module">A <see cref="IFunctionModule"/> that can be used for adding functions</param> - public virtual void LoadModule(IFunctionModule module) - { - foreach (var key in module.Functions.Keys) - { - var lowerKey = key.ToLower(CultureInfo.InvariantCulture); - _functions[lowerKey] = module.Functions[key]; - } - } - - public virtual ExcelFunction GetFunction(string name) - { - if(!_functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture))) - { - // Report that Excel function is not supported by EPPlus - throw new FunctionException(string.Format("Excel function '{0}' is not supported in formulas.", name)); - } - return _functions[name.ToLower(CultureInfo.InvariantCulture)]; - } - - /// <summary> - /// Removes all functions from the repository - /// </summary> - public virtual void Clear() - { - _functions.Clear(); - } - - /// <summary> - /// Returns true if the the supplied <paramref name="name"/> exists in the repository. - /// </summary> - /// <param name="name"></param> - /// <returns></returns> - public bool IsFunctionName(string name) - { - return _functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture)); - } - - /// <summary> - /// Returns the names of all implemented functions. - /// </summary> - public IEnumerable<string> FunctionNames - { - get { return _functions.Keys; } - } - - /// <summary> - /// Adds or replaces a function. - /// </summary> - /// <param name="functionName"> Case-insensitive name of the function that should be added or replaced.</param> - /// <param name="functionImpl">An implementation of an <see cref="ExcelFunction"/>.</param> - public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) - { - Require.That(functionName).Named("functionName").IsNotNullOrEmpty(); - Require.That(functionImpl).Named("functionImpl").IsNotNull(); - var fName = functionName.ToLower(CultureInfo.InvariantCulture); - if (_functions.ContainsKey(fName)) - { - _functions.Remove(fName); - } - _functions[fName] = functionImpl; - } + public virtual ExcelFunction GetFunction(string name) { + if (!_functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture))) { + // Report that Excel function is not supported by EPPlus + throw new FunctionException( + string.Format("Excel function '{0}' is not supported in formulas.", name)); } + return _functions[name.ToLower(CultureInfo.InvariantCulture)]; + } + + /// <summary> + /// Removes all functions from the repository + /// </summary> + public virtual void Clear() { + _functions.Clear(); + } + + /// <summary> + /// Returns true if the the supplied <paramref name="name"/> exists in the repository. + /// </summary> + /// <param name="name"></param> + /// <returns></returns> + public bool IsFunctionName(string name) { + return _functions.ContainsKey(name.ToLower(CultureInfo.InvariantCulture)); + } + + /// <summary> + /// Returns the names of all implemented functions. + /// </summary> + public IEnumerable<string> FunctionNames => _functions.Keys; + + /// <summary> + /// Adds or replaces a function. + /// </summary> + /// <param name="functionName"> Case-insensitive name of the function that should be added or replaced.</param> + /// <param name="functionImpl">An implementation of an <see cref="ExcelFunction"/>.</param> + public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) { + Require.That(functionName).Named("functionName").IsNotNullOrEmpty(); + Require.That(functionImpl).Named("functionImpl").IsNotNull(); + var fName = functionName.ToLower(CultureInfo.InvariantCulture); + if (_functions.ContainsKey(fName)) { + _functions.Remove(fName); + } + _functions[fName] = functionImpl; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/FunctionsModule.cs b/EPPlus/FormulaParsing/Excel/Functions/FunctionsModule.cs index ff6d42b..522451a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/FunctionsModule.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/FunctionsModule.cs
@@ -7,38 +7,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - /// <summary> - /// Base class - /// </summary> - public abstract class FunctionsModule : IFunctionModule - { - private readonly Dictionary<string, ExcelFunction> _functions = new Dictionary<string, ExcelFunction>(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - public IDictionary<string, ExcelFunction> Functions - { - get { return _functions; } - } - } +/// <summary> +/// Base class +/// </summary> +public abstract class FunctionsModule : IFunctionModule { + private readonly Dictionary<string, ExcelFunction> _functions = new(); + + public IDictionary<string, ExcelFunction> Functions => _functions; }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs index 2c9f745..81b3cc8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/HiddenValuesHandlingFunction.cs
@@ -7,74 +7,64 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - /// <summary> - /// Base class for functions that needs to handle cells that is not visible. - /// </summary> - public abstract class HiddenValuesHandlingFunction : ExcelFunction - { - /// <summary> - /// Set to true or false to indicate whether the function should ignore hidden values. - /// </summary> - public bool IgnoreHiddenValues - { - get; - set; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - protected override IEnumerable<double> ArgsToDoubleEnumerable(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return ArgsToDoubleEnumerable(arguments, context, true); - } +/// <summary> +/// Base class for functions that needs to handle cells that is not visible. +/// </summary> +public abstract class HiddenValuesHandlingFunction : ExcelFunction { + /// <summary> + /// Set to true or false to indicate whether the function should ignore hidden values. + /// </summary> + public bool IgnoreHiddenValues { get; set; } - protected IEnumerable<double> ArgsToDoubleEnumerable(IEnumerable<FunctionArgument> arguments, ParsingContext context, bool ignoreErrors) - { - if (!arguments.Any()) - { - return Enumerable.Empty<double>(); - } - if (IgnoreHiddenValues) - { - var nonHidden = arguments.Where(x => !x.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)); - return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, nonHidden, context); - } - return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, ignoreErrors, arguments, context); - } + protected override IEnumerable<double> ArgsToDoubleEnumerable( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return ArgsToDoubleEnumerable(arguments, context, true); + } - protected bool ShouldIgnore(ExcelDataProvider.ICellInfo c, ParsingContext context) - { - return CellStateHelper.ShouldIgnore(IgnoreHiddenValues, c, context); - } - protected bool ShouldIgnore(FunctionArgument arg) - { - if (IgnoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)) - { - return true; - } - return false; - } - + protected IEnumerable<double> ArgsToDoubleEnumerable( + IEnumerable<FunctionArgument> arguments, + ParsingContext context, + bool ignoreErrors) { + if (!arguments.Any()) { + return Enumerable.Empty<double>(); } + if (IgnoreHiddenValues) { + var nonHidden = arguments.Where(x => !x.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)); + return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, nonHidden, context); + } + return base.ArgsToDoubleEnumerable(IgnoreHiddenValues, ignoreErrors, arguments, context); + } + + protected bool ShouldIgnore(ExcelDataProvider.ICellInfo c, ParsingContext context) { + return CellStateHelper.ShouldIgnore(IgnoreHiddenValues, c, context); + } + + protected bool ShouldIgnore(FunctionArgument arg) { + if (IgnoreHiddenValues && arg.ExcelStateFlagIsSet(ExcelCellState.HiddenCell)) { + return true; + } + return false; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs b/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs index 9e3762a..6ab248f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/IFunctionModule.cs
@@ -7,30 +7,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public interface IFunctionModule - { - IDictionary<string, ExcelFunction> Functions { get; } - } +using System.Collections.Generic; + +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public interface IFunctionModule { + IDictionary<string, ExcelFunction> Functions { get; } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs b/EPPlus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs index b5a9940..5722862 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/IFunctionNameProvider.cs
@@ -7,30 +7,24 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public interface IFunctionNameProvider - { - bool IsFunctionName(string name); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public interface IFunctionNameProvider { + bool IsFunctionName(string name); }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/ErrorType.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/ErrorType.cs index f361ee7..9c565cc 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/ErrorType.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/ErrorType.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,64 +7,60 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-15 *******************************************************************************/ -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class ErrorType : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var error = arguments.ElementAt(0); - var isErrorFunc = context.Configuration.FunctionRepository.GetFunction("iserror"); - var isErrorResult = isErrorFunc.Execute(arguments, context); - if (!(bool) isErrorResult.Result) - { - return CreateResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); - } - var errorType = error.ValueAsExcelErrorValue; - int retValue; - switch (errorType.Type) - { - case eErrorType.Null: - return CreateResult(1, DataType.Integer); - case eErrorType.Div0: - return CreateResult(2, DataType.Integer); - case eErrorType.Value: - return CreateResult(3, DataType.Integer); - case eErrorType.Ref: - return CreateResult(4, DataType.Integer); - case eErrorType.Name: - return CreateResult(5, DataType.Integer); - case eErrorType.Num: - return CreateResult(6, DataType.Integer); - case eErrorType.NA: - return CreateResult(7, DataType.Integer); - // Bug G0004 - case eErrorType.Error: - return CreateResult(8, DataType.Integer); - } - return CreateResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class ErrorType : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var error = arguments.ElementAt(0); + var isErrorFunc = context.Configuration.FunctionRepository.GetFunction("iserror"); + var isErrorResult = isErrorFunc.Execute(arguments, context); + if (!(bool)isErrorResult.Result) { + return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError); } + var errorType = error.ValueAsExcelErrorValue; + int retValue; + switch (errorType.Type) { + case eErrorType.Null: + return CreateResult(1, DataType.Integer); + case eErrorType.Div0: + return CreateResult(2, DataType.Integer); + case eErrorType.Value: + return CreateResult(3, DataType.Integer); + case eErrorType.Ref: + return CreateResult(4, DataType.Integer); + case eErrorType.Name: + return CreateResult(5, DataType.Integer); + case eErrorType.Num: + return CreateResult(6, DataType.Integer); + case eErrorType.Na: + return CreateResult(7, DataType.Integer); + // Bug G0004 + case eErrorType.Error: + return CreateResult(8, DataType.Integer); + } + return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsBlank.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsBlank.cs index bfca497..e231841 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsBlank.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsBlank.cs
@@ -7,58 +7,49 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsBlank : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - if (arguments == null || arguments.Count() == 0) - { - return CreateResult(true, DataType.Boolean); - } - var result = true; - foreach (var arg in arguments) - { - if (arg.Value is ExcelDataProvider.IRangeInfo) - { - var r=(ExcelDataProvider.IRangeInfo)arg.Value; - if (r.GetValue(r.Address._fromRow, r.Address._fromCol) != null) - { - result = false; - } - } - else - { - if (arg.Value != null && (arg.Value.ToString() != string.Empty)) - { - result = false; - break; - } - } - } - return CreateResult(result, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class IsBlank : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + if (arguments == null || arguments.Count() == 0) { + return CreateResult(true, DataType.Boolean); } + var result = true; + foreach (var arg in arguments) { + if (arg.Value is ExcelDataProvider.IRangeInfo) { + var r = (ExcelDataProvider.IRangeInfo)arg.Value; + if (r.GetValue(r.Address._fromRow, r.Address._fromCol) != null) { + result = false; + } + } else { + if (arg.Value != null && (arg.Value.ToString() != string.Empty)) { + result = false; + break; + } + } + } + return CreateResult(result, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsErr.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsErr.cs index 880a715..ef90818 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsErr.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsErr.cs
@@ -1,43 +1,32 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsErr : ErrorHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var isError = new IsError(); - var result = isError.Execute(arguments, context); - if ((bool) result.Result) - { - var arg = GetFirstValue(arguments); - if (arg is ExcelDataProvider.IRangeInfo) - { - var r = (ExcelDataProvider.IRangeInfo)arg; - var e=r.GetValue(r.Address._fromRow, r.Address._fromCol) as ExcelErrorValue; - if (e !=null && e.Type==eErrorType.NA) - { - return CreateResult(false, DataType.Boolean); - } - } - else - { - if (arg is ExcelErrorValue && ((ExcelErrorValue)arg).Type==eErrorType.NA) - { - return CreateResult(false, DataType.Boolean); - } - } - } - return result; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; - public override CompileResult HandleError(string errorCode) - { - return CreateResult(true, DataType.Boolean); +public class IsErr : ErrorHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var isError = new IsError(); + var result = isError.Execute(arguments, context); + if ((bool)result.Result) { + var arg = GetFirstValue(arguments); + if (arg is ExcelDataProvider.IRangeInfo) { + var r = (ExcelDataProvider.IRangeInfo)arg; + var e = r.GetValue(r.Address._fromRow, r.Address._fromCol) as ExcelErrorValue; + if (e != null && e.Type == eErrorType.Na) { + return CreateResult(false, DataType.Boolean); } + } else { + if (arg is ExcelErrorValue && ((ExcelErrorValue)arg).Type == eErrorType.Na) { + return CreateResult(false, DataType.Boolean); + } + } } + return result; + } + + public override CompileResult HandleError(string errorCode) { + return CreateResult(true, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsError.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsError.cs index da883f6..d9802cf 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsError.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsError.cs
@@ -7,62 +7,52 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsError : ErrorHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - if (arguments == null || arguments.Count() == 0) - { - return CreateResult(false, DataType.Boolean); - } - foreach (var argument in arguments) - { - if (argument.Value is ExcelDataProvider.IRangeInfo) - { - var r = (ExcelDataProvider.IRangeInfo)argument.Value; - if (ExcelErrorValue.Values.IsErrorValue(r.GetValue(r.Address._fromRow, r.Address._fromCol))) - { - return CreateResult(true, DataType.Boolean); - } - } - else - { - if (ExcelErrorValue.Values.IsErrorValue(argument.Value)) - { - return CreateResult(true, DataType.Boolean); - } - } - } - return CreateResult(false, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; - public override CompileResult HandleError(string errorCode) - { - return CreateResult(true, DataType.Boolean); - } +public class IsError : ErrorHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + if (arguments == null || arguments.Count() == 0) { + return CreateResult(false, DataType.Boolean); } + foreach (var argument in arguments) { + if (argument.Value is ExcelDataProvider.IRangeInfo) { + var r = (ExcelDataProvider.IRangeInfo)argument.Value; + if (ExcelErrorValue.Values.IsErrorValue( + r.GetValue(r.Address._fromRow, r.Address._fromCol))) { + return CreateResult(true, DataType.Boolean); + } + } else { + if (ExcelErrorValue.Values.IsErrorValue(argument.Value)) { + return CreateResult(true, DataType.Boolean); + } + } + } + return CreateResult(false, DataType.Boolean); + } + + public override CompileResult HandleError(string errorCode) { + return CreateResult(true, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsEven.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsEven.cs index 883e5aa..af8bf4e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsEven.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsEven.cs
@@ -1,24 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsEven : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg1 = GetFirstValue(arguments);//arguments.ElementAt(0); - if (!ConvertUtil.IsNumeric(arg1)) - { - ThrowExcelErrorValueException(eErrorType.Value); - } - var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1)); - return CreateResult(number % 2 == 0, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class IsEven : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg1 = GetFirstValue(arguments); //arguments.ElementAt(0); + if (!ConvertUtil.IsNumeric(arg1)) { + ThrowExcelErrorValueException(eErrorType.Value); } + var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1)); + return CreateResult(number % 2 == 0, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsLogical.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsLogical.cs index 156669d..fbda5d6 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsLogical.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsLogical.cs
@@ -1,19 +1,16 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsLogical : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 1); - var v = GetFirstValue(arguments); - return CreateResult(v is bool, DataType.Boolean); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class IsLogical : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 1); + var v = GetFirstValue(arguments); + return CreateResult(v is bool, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNa.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNa.cs index 7e83f2e..82adcfe 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNa.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNa.cs
@@ -7,45 +7,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-15 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsNa : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - if (arguments == null || arguments.Count() == 0) - { - return CreateResult(false, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; - var v = GetFirstValue(arguments); - - if (v is ExcelErrorValue && ((ExcelErrorValue)v).Type==eErrorType.NA) - { - return CreateResult(true, DataType.Boolean); - } - return CreateResult(false, DataType.Boolean); - } +public class IsNa : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + if (arguments == null || arguments.Count() == 0) { + return CreateResult(false, DataType.Boolean); } + + var v = GetFirstValue(arguments); + + if (v is ExcelErrorValue && ((ExcelErrorValue)v).Type == eErrorType.Na) { + return CreateResult(true, DataType.Boolean); + } + return CreateResult(false, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNonText.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNonText.cs index e61eb94..c84008d 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNonText.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNonText.cs
@@ -7,37 +7,37 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-15 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsNonText : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var firstArg = arguments.ElementAt(0); - if (firstArg.Value == null || firstArg.ValueIsExcelError) return CreateResult(false, DataType.Boolean); - return CreateResult(!(firstArg.Value is string), DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class IsNonText : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var firstArg = arguments.ElementAt(0); + if (firstArg.Value == null || firstArg.ValueIsExcelError) { + return CreateResult(false, DataType.Boolean); } + return CreateResult(!(firstArg.Value is string), DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNumber.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNumber.cs index 2ddf31c..eac8fdd 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsNumber.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsNumber.cs
@@ -1,5 +1,4 @@ -using System; -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -8,35 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsNumber : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = GetFirstValue(arguments); - return CreateResult(IsNumeric(arg), DataType.Boolean); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class IsNumber : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = GetFirstValue(arguments); + return CreateResult(IsNumeric(arg), DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsOdd.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsOdd.cs index 9b345d0..1e1af7f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsOdd.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsOdd.cs
@@ -7,42 +7,38 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-15 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsOdd : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg1 = GetFirstValue(arguments);//arguments.ElementAt(0); - if (!ConvertUtil.IsNumeric(arg1)) - { - ThrowExcelErrorValueException(eErrorType.Value); - } - var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1)); - return CreateResult(number % 2 == 1, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class IsOdd : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg1 = GetFirstValue(arguments); //arguments.ElementAt(0); + if (!ConvertUtil.IsNumeric(arg1)) { + ThrowExcelErrorValueException(eErrorType.Value); } + var number = (int)System.Math.Floor(ConvertUtil.GetValueDouble(arg1)); + return CreateResult(number % 2 == 1, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/IsText.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/IsText.cs index dae2c3a..b2d288b 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/IsText.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/IsText.cs
@@ -7,39 +7,36 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class IsText : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - if (arguments.Count() == 1 && arguments.ElementAt(0).Value != null) - { - return CreateResult((GetFirstValue(arguments) is string), DataType.Boolean); - } - return CreateResult(false, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class IsText : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + if (arguments.Count() == 1 && arguments.ElementAt(0).Value != null) { + return CreateResult((GetFirstValue(arguments) is string), DataType.Boolean); } + return CreateResult(false, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/N.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/N.cs index 046c7a4..18d6665 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/N.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/N.cs
@@ -1,39 +1,31 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class N : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = GetFirstValue(arguments); - - if (arg is bool) - { - var val = (bool) arg ? 1d : 0d; - return CreateResult(val, DataType.Decimal); - } - else if (IsNumeric(arg)) - { - var val = ConvertUtil.GetValueDouble(arg); - return CreateResult(val, DataType.Decimal); - } - else if (arg is string) - { - return CreateResult(0d, DataType.Decimal); - } - else if (arg is ExcelErrorValue) - { - return CreateResult(arg, DataType.ExcelError); - } - throw new ExcelErrorValueException(eErrorType.Value); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class N : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = GetFirstValue(arguments); + + if (arg is bool) { + var val = (bool)arg ? 1d : 0d; + return CreateResult(val, DataType.Decimal); } + if (IsNumeric(arg)) { + var val = ConvertUtil.GetValueDouble(arg); + return CreateResult(val, DataType.Decimal); + } + if (arg is string) { + return CreateResult(0d, DataType.Decimal); + } + if (arg is ExcelErrorValue) { + return CreateResult(arg, DataType.ExcelError); + } + throw new ExcelErrorValueException(eErrorType.Value); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Information/Na.cs b/EPPlus/FormulaParsing/Excel/Functions/Information/Na.cs index 7d2fc03..93bfba2 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Information/Na.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Information/Na.cs
@@ -1,16 +1,12 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information -{ - public class Na : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return CreateResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Information; + +public class Na : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return CreateResult(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/IntArgumentParser.cs b/EPPlus/FormulaParsing/Excel/Functions/IntArgumentParser.cs index 6ae3a09..b510d93 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/IntArgumentParser.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/IntArgumentParser.cs
@@ -7,55 +7,47 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Utilities; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class IntArgumentParser : ArgumentParser - { - public override object Parse(object obj) - { - Require.That(obj).Named("argument").IsNotNull(); - int result; - if (obj is ExcelDataProvider.IRangeInfo) - { - var r = ((ExcelDataProvider.IRangeInfo)obj).FirstOrDefault(); - return r == null ? 0 : Convert.ToInt32(r.ValueDouble); - } - var objType = obj.GetType(); - if (objType == typeof(int)) - { - return (int)obj; - } - if (objType == typeof(double) || objType == typeof(decimal)) - { - return Convert.ToInt32(obj); - } - if (!int.TryParse(obj.ToString(), out result)) - { - throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); - } - return result; - } +using System; +using System.Linq; +using OfficeOpenXml.FormulaParsing.Exceptions; +using OfficeOpenXml.FormulaParsing.Utilities; + +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; + +public class IntArgumentParser : ArgumentParser { + public override object Parse(object obj) { + Require.That(obj).Named("argument").IsNotNull(); + int result; + if (obj is ExcelDataProvider.IRangeInfo) { + var r = ((ExcelDataProvider.IRangeInfo)obj).FirstOrDefault(); + return r == null ? 0 : Convert.ToInt32(r.ValueDouble); } + var objType = obj.GetType(); + if (objType == typeof(int)) { + return (int)obj; + } + if (objType == typeof(double) || objType == typeof(decimal)) { + return Convert.ToInt32(obj); + } + if (!int.TryParse(obj.ToString(), out result)) { + throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); + } + return result; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/And.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/And.cs index 363b447..c483af5 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/And.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/And.cs
@@ -7,42 +7,38 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class And : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - for (var x = 0; x < arguments.Count(); x++) - { - if (!ArgToBool(arguments, x)) - { - return new CompileResult(false, DataType.Boolean); - } - } - return new CompileResult(true, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class And : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + for (var x = 0; x < arguments.Count(); x++) { + if (!ArgToBool(arguments, x)) { + return new(false, DataType.Boolean); + } } + return new(true, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/False.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/False.cs index c568f3c..176d31a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/False.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/False.cs
@@ -7,34 +7,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class False : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return CreateResult(false, DataType.Boolean); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class False : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return CreateResult(false, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/If.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/If.cs index 1dadfd3..bc55272 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/If.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/If.cs
@@ -7,39 +7,37 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class If : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var condition = ArgToBool(arguments, 0); - var firstStatement = arguments.ElementAt(1).Value; - var secondStatement = arguments.ElementAt(2).Value; - var factory = new CompileResultFactory(); - return condition ? factory.Create(firstStatement) : factory.Create(secondStatement); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class If : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var condition = ArgToBool(arguments, 0); + var firstStatement = arguments.ElementAt(1).Value; + var secondStatement = arguments.ElementAt(2).Value; + var factory = new CompileResultFactory(); + return condition ? factory.Create(firstStatement) : factory.Create(secondStatement); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs index a5e5802..8fe9993 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs
@@ -1,18 +1,15 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class IfError : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var firstArg = arguments.First(); - return GetResultByObject(firstArg.Value); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class IfError : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var firstArg = arguments.First(); + return GetResultByObject(firstArg.Value); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfNa.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/IfNa.cs index 6c3d710..ec74404 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/IfNa.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/IfNa.cs
@@ -1,18 +1,15 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class IfNa : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var firstArg = arguments.First(); - return GetResultByObject(firstArg.Value); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class IfNa : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var firstArg = arguments.First(); + return GetResultByObject(firstArg.Value); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/Not.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/Not.cs index 62cd5eb..aec7f74 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/Not.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/Not.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class Not : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var result = !ArgToBool(arguments, 0); - return new CompileResult(result, DataType.Boolean); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class Not : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var result = !ArgToBool(arguments, 0); + return new(result, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/Or.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/Or.cs index 08907bd..bcf6e31 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/Or.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/Or.cs
@@ -7,42 +7,38 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class Or : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - for (var x = 0; x < arguments.Count(); x++) - { - if (ArgToBool(arguments, x)) - { - return new CompileResult(true, DataType.Boolean); - } - } - return new CompileResult(false, DataType.Boolean); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class Or : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + for (var x = 0; x < arguments.Count(); x++) { + if (ArgToBool(arguments, x)) { + return new(true, DataType.Boolean); + } } + return new(false, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Logical/True.cs b/EPPlus/FormulaParsing/Excel/Functions/Logical/True.cs index 2a85e3e..bb23a62 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Logical/True.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Logical/True.cs
@@ -7,34 +7,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical -{ - public class True : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return CreateResult(true, DataType.Boolean); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; + +public class True : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return CreateResult(true, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Abs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Abs.cs index 8f41338..ad29a14 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Abs.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Abs.cs
@@ -7,40 +7,36 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Abs : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var val = ArgToDecimal(arguments, 0); - if (val < 0) - { - val *= -1; - } - return CreateResult(val, DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Abs : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var val = ArgToDecimal(arguments, 0); + if (val < 0) { + val *= -1; } + return CreateResult(val, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Acos.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Acos.cs index 6a7db11..077a02e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Acos.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Acos.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Acos : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(MathHelper.Arccos(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Acos : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(MathHelper.Arccos(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Acosh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Acosh.cs index ac3d530..cf07e1b 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Acosh.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Acosh.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Acosh : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(MathHelper.HArccos(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Acosh : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(MathHelper.HArccos(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Asin.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Asin.cs index 4ca0a2f..288763c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Asin.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Asin.cs
@@ -1,6 +1,6 @@ -using System; using System.Collections.Generic; -using System.Linq; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; + /* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or @@ -10,33 +10,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Asin : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Asin(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Asin : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Asin(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Asinh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Asinh.cs index e75d1f5..80ebdfa 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Asinh.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Asinh.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Asinh : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(MathHelper.HArcsin(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Asinh : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(MathHelper.HArcsin(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Atan.cs index 38c6096..9cc60b0 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Atan.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Atan : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Atan(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Atan : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Atan(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan2.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Atan2.cs index 34e4411..a490c1d 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Atan2.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Atan2.cs
@@ -7,38 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Atan2 : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var arg1 = ArgToDecimal(arguments, 0); - var arg2 = ArgToDecimal(arguments, 1); - // Had to switch order of the arguments to get the same result as in excel /MA - return CreateResult(System.Math.Atan2(arg2, arg1), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Atan2 : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var arg1 = ArgToDecimal(arguments, 0); + var arg2 = ArgToDecimal(arguments, 1); + // Had to switch order of the arguments to get the same result as in excel /MA + return CreateResult(System.Math.Atan2(arg2, arg1), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Atanh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Atanh.cs index 797ab65..302c97f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Atanh.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Atanh.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Atanh : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(MathHelper.HArctan(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Atanh : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(MathHelper.HArctan(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Average.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Average.cs index c5c878d..159d9de 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Average.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Average.cs
@@ -7,102 +7,91 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Average : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1, eErrorType.Div0); - double nValues = 0d, result = 0d; - foreach (var arg in arguments) - { - Calculate(arg, context, ref result, ref nValues); - } - return CreateResult(Divide(result, nValues), DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private void Calculate(FunctionArgument arg, ParsingContext context, ref double retVal, ref double nValues, bool isInArray = false) - { - if (ShouldIgnore(arg)) - { - return; - } - if (arg.Value is IEnumerable<FunctionArgument>) - { - foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) - { - Calculate(item, context, ref retVal, ref nValues, true); - } - } - else if (arg.IsExcelRange) - { - foreach (var c in arg.ValueAsRangeInfo) - { - if (ShouldIgnore(c, context)) continue; - CheckForAndHandleExcelError(c); - if (!IsNumeric(c.Value)) continue; - nValues++; - retVal += c.ValueDouble; - } - } - else - { - var numericValue = GetNumericValue(arg.Value, isInArray); - if (numericValue.HasValue) - { - nValues++; - retVal += numericValue.Value; - } - else if ((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) - { - if (!isInArray) - { - ThrowExcelErrorValueException(eErrorType.Value); - } - } - } - CheckForAndHandleExcelError(arg); - } - - private double? GetNumericValue(object obj, bool isInArray) - { - if (IsNumeric(obj)) - { - return ConvertUtil.GetValueDouble(obj); - } - else if ((obj is bool) && !isInArray) - { - return ConvertUtil.GetValueDouble(obj); - } - else if (ConvertUtil.IsNumericString(obj)) - { - return double.Parse(obj.ToString(), CultureInfo.InvariantCulture); - } - return default(double?); - } +public class Average : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1, eErrorType.Div0); + double nValues = 0d, + result = 0d; + foreach (var arg in arguments) { + Calculate(arg, context, ref result, ref nValues); } + return CreateResult(Divide(result, nValues), DataType.Decimal); + } + + private void Calculate( + FunctionArgument arg, + ParsingContext context, + ref double retVal, + ref double nValues, + bool isInArray = false) { + if (ShouldIgnore(arg)) { + return; + } + if (arg.Value is IEnumerable<FunctionArgument>) { + foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) { + Calculate(item, context, ref retVal, ref nValues, true); + } + } else if (arg.IsExcelRange) { + foreach (var c in arg.ValueAsRangeInfo) { + if (ShouldIgnore(c, context)) { + continue; + } + CheckForAndHandleExcelError(c); + if (!IsNumeric(c.Value)) { + continue; + } + nValues++; + retVal += c.ValueDouble; + } + } else { + var numericValue = GetNumericValue(arg.Value, isInArray); + if (numericValue.HasValue) { + nValues++; + retVal += numericValue.Value; + } else if ((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) { + if (!isInArray) { + ThrowExcelErrorValueException(eErrorType.Value); + } + } + } + CheckForAndHandleExcelError(arg); + } + + private double? GetNumericValue(object obj, bool isInArray) { + if (IsNumeric(obj)) { + return ConvertUtil.GetValueDouble(obj); + } + if ((obj is bool) && !isInArray) { + return ConvertUtil.GetValueDouble(obj); + } + if (ConvertUtil.IsNumericString(obj)) { + return double.Parse(obj.ToString(), CultureInfo.InvariantCulture); + } + return default(double?); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageA.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageA.cs index 8dd5bb9..00f575f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageA.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageA.cs
@@ -7,118 +7,100 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2014-01-06 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class AverageA : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1, eErrorType.Div0); - double nValues = 0d, result = 0d; - foreach (var arg in arguments) - { - Calculate(arg, context, ref result, ref nValues); - } - return CreateResult(Divide(result, nValues), DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private void Calculate(FunctionArgument arg, ParsingContext context, ref double retVal, ref double nValues, bool isInArray = false) - { - if (ShouldIgnore(arg)) - { - return; - } - if (arg.Value is IEnumerable<FunctionArgument>) - { - foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) - { - Calculate(item, context, ref retVal, ref nValues, true); - } - } - else if (arg.IsExcelRange) - { - foreach (var c in arg.ValueAsRangeInfo) - { - if (ShouldIgnore(c, context)) continue; - CheckForAndHandleExcelError(c); - if (IsNumeric(c.Value)) - { - nValues++; - retVal += c.ValueDouble; - } - else if (c.Value is bool) - { - nValues++; - retVal += (bool) c.Value ? 1 : 0; - } - else if (c.Value is string) - { - nValues++; - } - } - } - else - { - var numericValue = GetNumericValue(arg.Value, isInArray); - if (numericValue.HasValue) - { - nValues++; - retVal += numericValue.Value; - } - else if((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) - { - if (isInArray) - { - nValues++; - } - else - { - ThrowExcelErrorValueException(eErrorType.Value); - } - } - } - CheckForAndHandleExcelError(arg); - } - - private double? GetNumericValue(object obj, bool isInArray) - { - if (IsNumeric(obj)) - { - return ConvertUtil.GetValueDouble(obj); - } - else if (obj is bool) - { - if (isInArray) return default(double?); - return ConvertUtil.GetValueDouble(obj); - } - else if (ConvertUtil.IsNumericString(obj)) - { - return double.Parse(obj.ToString(), CultureInfo.InvariantCulture); - } - return default(double?); - } +public class AverageA : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1, eErrorType.Div0); + double nValues = 0d, + result = 0d; + foreach (var arg in arguments) { + Calculate(arg, context, ref result, ref nValues); } + return CreateResult(Divide(result, nValues), DataType.Decimal); + } + + private void Calculate( + FunctionArgument arg, + ParsingContext context, + ref double retVal, + ref double nValues, + bool isInArray = false) { + if (ShouldIgnore(arg)) { + return; + } + if (arg.Value is IEnumerable<FunctionArgument>) { + foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) { + Calculate(item, context, ref retVal, ref nValues, true); + } + } else if (arg.IsExcelRange) { + foreach (var c in arg.ValueAsRangeInfo) { + if (ShouldIgnore(c, context)) { + continue; + } + CheckForAndHandleExcelError(c); + if (IsNumeric(c.Value)) { + nValues++; + retVal += c.ValueDouble; + } else if (c.Value is bool) { + nValues++; + retVal += (bool)c.Value ? 1 : 0; + } else if (c.Value is string) { + nValues++; + } + } + } else { + var numericValue = GetNumericValue(arg.Value, isInArray); + if (numericValue.HasValue) { + nValues++; + retVal += numericValue.Value; + } else if ((arg.Value is string) && !ConvertUtil.IsNumericString(arg.Value)) { + if (isInArray) { + nValues++; + } else { + ThrowExcelErrorValueException(eErrorType.Value); + } + } + } + CheckForAndHandleExcelError(arg); + } + + private double? GetNumericValue(object obj, bool isInArray) { + if (IsNumeric(obj)) { + return ConvertUtil.GetValueDouble(obj); + } + if (obj is bool) { + if (isInArray) { + return default(double?); + } + return ConvertUtil.GetValueDouble(obj); + } + if (ConvertUtil.IsNumericString(obj)) { + return double.Parse(obj.ToString(), CultureInfo.InvariantCulture); + } + return default(double?); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs index 14e6b7e..3b83858 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIf.cs
@@ -7,155 +7,142 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.Utils; using Require = OfficeOpenXml.FormulaParsing.Utilities.Require; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class AverageIf : HiddenValuesHandlingFunction - { - private readonly NumericExpressionEvaluator _numericExpressionEvaluator; - private readonly WildCardValueMatcher _wildCardValueMatcher; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public AverageIf() - : this(new NumericExpressionEvaluator(), new WildCardValueMatcher()) - { +public class AverageIf : HiddenValuesHandlingFunction { + private readonly NumericExpressionEvaluator _numericExpressionEvaluator; + private readonly WildCardValueMatcher _wildCardValueMatcher; - } + public AverageIf() + : this(new(), new()) {} - public AverageIf(NumericExpressionEvaluator evaluator, WildCardValueMatcher wildCardValueMatcher) - { - Require.That(evaluator).Named("evaluator").IsNotNull(); - Require.That(evaluator).Named("wildCardValueMatcher").IsNotNull(); - _numericExpressionEvaluator = evaluator; - _wildCardValueMatcher = wildCardValueMatcher; - } + public AverageIf( + NumericExpressionEvaluator evaluator, + WildCardValueMatcher wildCardValueMatcher) { + Require.That(evaluator).Named("evaluator").IsNotNull(); + Require.That(evaluator).Named("wildCardValueMatcher").IsNotNull(); + _numericExpressionEvaluator = evaluator; + _wildCardValueMatcher = wildCardValueMatcher; + } - private bool Evaluate(object obj, string expression) - { - double? candidate = default(double?); - if (IsNumeric(obj)) - { - candidate = ConvertUtil.GetValueDouble(obj); - } - if (candidate.HasValue) - { - return _numericExpressionEvaluator.Evaluate(candidate.Value, expression); - } - if (obj == null) return false; - return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; - } - - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var firstArg = arguments.ElementAt(0); - var args = firstArg.Value as IEnumerable<FunctionArgument>; - if (args == null && firstArg.IsExcelRange) - { - args = new List<FunctionArgument>(){ firstArg }; - } - var criteria = arguments.ElementAt(1).Value; - ThrowExcelErrorValueExceptionIf(() => criteria == null || criteria.ToString().Length > 255, eErrorType.Value); - var retVal = 0d; - if (arguments.Count() > 2) - { - var secondArg = arguments.ElementAt(2); - var lookupRange = secondArg.Value as IEnumerable<FunctionArgument>; - if (lookupRange == null && secondArg.IsExcelRange) - { - lookupRange = new List<FunctionArgument>() {secondArg}; - } - retVal = CalculateWithLookupRange(args, criteria.ToString(), lookupRange, context); - } - else - { - retVal = CalculateSingleRange(args, criteria.ToString(), context); - } - return CreateResult(retVal, DataType.Decimal); - } - - private double CalculateWithLookupRange(IEnumerable<FunctionArgument> range, string criteria, IEnumerable<FunctionArgument> sumRange, ParsingContext context) - { - var retVal = 0d; - var nMatches = 0; - var flattenedRange = ArgsToObjectEnumerable(false, range, context); - var flattenedSumRange = ArgsToDoubleEnumerable(sumRange, context); - for (var x = 0; x < flattenedRange.Count(); x++) - { - var candidate = flattenedSumRange.ElementAt(x); - if (Evaluate(flattenedRange.ElementAt(x), criteria)) - { - nMatches++; - retVal += candidate; - } - } - return Divide(retVal, nMatches); - } - - private double CalculateSingleRange(IEnumerable<FunctionArgument> args, string expression, ParsingContext context) - { - var retVal = 0d; - var nMatches = 0; - var flattendedRange = ArgsToDoubleEnumerable(args, context); - var candidates = flattendedRange as double[] ?? flattendedRange.ToArray(); - foreach (var candidate in candidates) - { - if (Evaluate(candidate, expression)) - { - retVal += candidate; - nMatches++; - } - } - return Divide(retVal, nMatches); - } - - private double Calculate(FunctionArgument arg, string expression) - { - var retVal = 0d; - if (ShouldIgnore(arg) || !_numericExpressionEvaluator.Evaluate(arg.Value, expression)) - { - return retVal; - } - if (IsNumeric(arg.Value)) - { - retVal += ConvertUtil.GetValueDouble(arg.Value); - } - //else if (arg.Value is System.DateTime) - //{ - // retVal += Convert.ToDateTime(arg.Value).ToOADate(); - //} - else if (arg.Value is IEnumerable<FunctionArgument>) - { - foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) - { - retVal += Calculate(item, expression); - } - } - return retVal; - } + private bool Evaluate(object obj, string expression) { + double? candidate = default(double?); + if (IsNumeric(obj)) { + candidate = ConvertUtil.GetValueDouble(obj); } + if (candidate.HasValue) { + return _numericExpressionEvaluator.Evaluate(candidate.Value, expression); + } + if (obj == null) { + return false; + } + return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; + } + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var firstArg = arguments.ElementAt(0); + var args = firstArg.Value as IEnumerable<FunctionArgument>; + if (args == null && firstArg.IsExcelRange) { + args = new List<FunctionArgument> { firstArg }; + } + var criteria = arguments.ElementAt(1).Value; + ThrowExcelErrorValueExceptionIf( + () => criteria == null || criteria.ToString().Length > 255, + eErrorType.Value); + var retVal = 0d; + if (arguments.Count() > 2) { + var secondArg = arguments.ElementAt(2); + var lookupRange = secondArg.Value as IEnumerable<FunctionArgument>; + if (lookupRange == null && secondArg.IsExcelRange) { + lookupRange = new List<FunctionArgument> { secondArg }; + } + retVal = CalculateWithLookupRange(args, criteria.ToString(), lookupRange, context); + } else { + retVal = CalculateSingleRange(args, criteria.ToString(), context); + } + return CreateResult(retVal, DataType.Decimal); + } + + private double CalculateWithLookupRange( + IEnumerable<FunctionArgument> range, + string criteria, + IEnumerable<FunctionArgument> sumRange, + ParsingContext context) { + var retVal = 0d; + var nMatches = 0; + var flattenedRange = ArgsToObjectEnumerable(false, range, context); + var flattenedSumRange = ArgsToDoubleEnumerable(sumRange, context); + for (var x = 0; x < flattenedRange.Count(); x++) { + var candidate = flattenedSumRange.ElementAt(x); + if (Evaluate(flattenedRange.ElementAt(x), criteria)) { + nMatches++; + retVal += candidate; + } + } + return Divide(retVal, nMatches); + } + + private double CalculateSingleRange( + IEnumerable<FunctionArgument> args, + string expression, + ParsingContext context) { + var retVal = 0d; + var nMatches = 0; + var flattendedRange = ArgsToDoubleEnumerable(args, context); + var candidates = flattendedRange as double[] ?? flattendedRange.ToArray(); + foreach (var candidate in candidates) { + if (Evaluate(candidate, expression)) { + retVal += candidate; + nMatches++; + } + } + return Divide(retVal, nMatches); + } + + private double Calculate(FunctionArgument arg, string expression) { + var retVal = 0d; + if (ShouldIgnore(arg) || !_numericExpressionEvaluator.Evaluate(arg.Value, expression)) { + return retVal; + } + if (IsNumeric(arg.Value)) { + retVal += ConvertUtil.GetValueDouble(arg.Value); + } + //else if (arg.Value is System.DateTime) + //{ + // retVal += Convert.ToDateTime(arg.Value).ToOADate(); + //} + else if (arg.Value is IEnumerable<FunctionArgument>) { + foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) { + retVal += Calculate(item, expression); + } + } + return retVal; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs index 7333ce2..a24266c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/AverageIfs.cs
@@ -7,60 +7,63 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-02-01 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class AverageIfs : MultipleRangeCriteriasFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 3); - var sumRange = ArgsToDoubleEnumerable(true, new List<FunctionArgument> { functionArguments[0] }, context).ToList(); - var argRanges = new List<ExcelDataProvider.IRangeInfo>(); - var criterias = new List<object>(); - for (var ix = 1; ix < 31; ix += 2) - { - if (functionArguments.Length <= ix) break; - var rangeInfo = functionArguments[ix].ValueAsRangeInfo; - argRanges.Add(rangeInfo); - if (ix > 1) - { - ThrowExcelErrorValueExceptionIf(() => rangeInfo.GetNCells() != argRanges[0].GetNCells(), eErrorType.Value); - } - criterias.Add(functionArguments[ix + 1].Value); - } - IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]); - var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList(); - for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) - { - var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]); - matchIndexes = enumerable.Intersect(indexes); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - var result = matchIndexes.Average(index => sumRange[index]); - - return CreateResult(result, DataType.Decimal); - } +public class AverageIfs : MultipleRangeCriteriasFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 3); + var sumRange = ArgsToDoubleEnumerable( + true, + new List<FunctionArgument> { functionArguments[0] }, + context) + .ToList(); + var argRanges = new List<ExcelDataProvider.IRangeInfo>(); + var criterias = new List<object>(); + for (var ix = 1; ix < 31; ix += 2) { + if (functionArguments.Length <= ix) { + break; + } + var rangeInfo = functionArguments[ix].ValueAsRangeInfo; + argRanges.Add(rangeInfo); + if (ix > 1) { + ThrowExcelErrorValueExceptionIf( + () => rangeInfo.GetNCells() != argRanges[0].GetNCells(), + eErrorType.Value); + } + criterias.Add(functionArguments[ix + 1].Value); } + IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]); + var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList(); + for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) { + var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]); + matchIndexes = enumerable.Intersect(indexes); + } + + var result = matchIndexes.Average(index => sumRange[index]); + + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Ceiling.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Ceiling.cs index a441db2..2140891 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Ceiling.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Ceiling.cs
@@ -7,62 +7,54 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Ceiling : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var number = ArgToDecimal(arguments, 0); - var significance = ArgToDecimal(arguments, 1); - ValidateNumberAndSign(number, significance); - if (significance < 1 && significance > 0) - { - var floor = System.Math.Floor(number); - var rest = number - floor; - var nSign = (int)(rest / significance) + 1; - return CreateResult(floor + (nSign * significance), DataType.Decimal); - } - else if (significance == 1) - { - return CreateResult(System.Math.Ceiling(number), DataType.Decimal); - } - else - { - var result = number - (number % significance) + significance; - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private void ValidateNumberAndSign(double number, double sign) - { - if (number > 0d && sign < 0) - { - var values = string.Format("num: {0}, sign: {1}", number, sign); - throw new InvalidOperationException("Ceiling cannot handle a negative significance when the number is positive" + values); - } - } +public class Ceiling : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var number = ArgToDecimal(arguments, 0); + var significance = ArgToDecimal(arguments, 1); + ValidateNumberAndSign(number, significance); + if (significance < 1 && significance > 0) { + var floor = System.Math.Floor(number); + var rest = number - floor; + var nSign = (int)(rest / significance) + 1; + return CreateResult(floor + (nSign * significance), DataType.Decimal); } + if (significance == 1) { + return CreateResult(System.Math.Ceiling(number), DataType.Decimal); + } + var result = number - (number % significance) + significance; + return CreateResult(result, DataType.Decimal); + } + + private void ValidateNumberAndSign(double number, double sign) { + if (number > 0d && sign < 0) { + var values = string.Format("num: {0}, sign: {1}", number, sign); + throw new InvalidOperationException( + "Ceiling cannot handle a negative significance when the number is positive" + values); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Cos.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Cos.cs index e889619..a605707 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Cos.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Cos.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Cos : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Cos(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Cos : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Cos(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Cosh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Cosh.cs index f294478..bb15381 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Cosh.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Cosh.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Cosh : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Cosh(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Cosh : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Cosh(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Count.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Count.cs index 21a58c1..c5c42da 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Count.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Count.cs
@@ -7,111 +7,98 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Count : HiddenValuesHandlingFunction - { - private enum ItemContext - { - InRange, - InArray, - SingleArg - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var nItems = 0d; - Calculate(arguments, ref nItems, context, ItemContext.SingleArg); - return CreateResult(nItems, DataType.Integer); - } +public class Count : HiddenValuesHandlingFunction { + private enum ItemContext { + InRange, + InArray, + SingleArg, + } - private void Calculate(IEnumerable<FunctionArgument> items, ref double nItems, ParsingContext context, ItemContext itemContext) - { - foreach (var item in items) - { - var cs = item.Value as ExcelDataProvider.IRangeInfo; - if (cs != null) - { - foreach (var c in cs) - { - _CheckForAndHandleExcelError(c, context); - if (ShouldIgnore(c, context) == false && ShouldCount(c.Value, ItemContext.InRange)) - { - nItems++; - } - } - } - else - { - var value = item.Value as IEnumerable<FunctionArgument>; - if (value != null) - { - Calculate(value, ref nItems, context, ItemContext.InArray); - } - else - { - _CheckForAndHandleExcelError(item, context); - if (ShouldIgnore(item) == false && ShouldCount(item.Value, itemContext)) - { - nItems++; - } - } - } - } - } + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var nItems = 0d; + Calculate(arguments, ref nItems, context, ItemContext.SingleArg); + return CreateResult(nItems, DataType.Integer); + } - private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) - { - //if (context.Scopes.Current.IsSubtotal) - //{ - // CheckForAndHandleExcelError(arg); - //} + private void Calculate( + IEnumerable<FunctionArgument> items, + ref double nItems, + ParsingContext context, + ItemContext itemContext) { + foreach (var item in items) { + var cs = item.Value as ExcelDataProvider.IRangeInfo; + if (cs != null) { + foreach (var c in cs) { + _CheckForAndHandleExcelError(c, context); + if (ShouldIgnore(c, context) == false && ShouldCount(c.Value, ItemContext.InRange)) { + nItems++; + } } - - private void _CheckForAndHandleExcelError(ExcelDataProvider.ICellInfo cell, ParsingContext context) - { - //if (context.Scopes.Current.IsSubtotal) - //{ - // CheckForAndHandleExcelError(cell); - //} + } else { + var value = item.Value as IEnumerable<FunctionArgument>; + if (value != null) { + Calculate(value, ref nItems, context, ItemContext.InArray); + } else { + _CheckForAndHandleExcelError(item, context); + if (ShouldIgnore(item) == false && ShouldCount(item.Value, itemContext)) { + nItems++; + } } - - private bool ShouldCount(object value, ItemContext context) - { - switch (context) - { - case ItemContext.SingleArg: - return IsNumeric(value) || IsNumericString(value); - case ItemContext.InRange: - return IsNumeric(value); - case ItemContext.InArray: - return IsNumeric(value) || IsNumericString(value); - default: - throw new ArgumentException("Unknown ItemContext:" + context.ToString()); - } - } + } } + } + + private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) { + //if (context.Scopes.Current.IsSubtotal) + //{ + // CheckForAndHandleExcelError(arg); + //} + } + + private void _CheckForAndHandleExcelError( + ExcelDataProvider.ICellInfo cell, + ParsingContext context) { + //if (context.Scopes.Current.IsSubtotal) + //{ + // CheckForAndHandleExcelError(cell); + //} + } + + private bool ShouldCount(object value, ItemContext context) { + switch (context) { + case ItemContext.SingleArg: + return IsNumeric(value) || IsNumericString(value); + case ItemContext.InRange: + return IsNumeric(value); + case ItemContext.InArray: + return IsNumeric(value) || IsNumericString(value); + default: + throw new ArgumentException("Unknown ItemContext:" + context); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountA.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountA.cs index 0f44b47..3e7fd3c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountA.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/CountA.cs
@@ -7,91 +7,79 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class CountA : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var nItems = 0d; - Calculate(arguments, context, ref nItems); - return CreateResult(nItems, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private void Calculate(IEnumerable<FunctionArgument> items, ParsingContext context, ref double nItems) - { - foreach (var item in items) - { - var cs = item.Value as ExcelDataProvider.IRangeInfo; - if (cs != null) - { - foreach (var c in cs) - { - _CheckForAndHandleExcelError(c, context); - if (!ShouldIgnore(c, context) && ShouldCount(c.Value)) - { - nItems++; - } - } - } - else if (item.Value is IEnumerable<FunctionArgument>) - { - Calculate((IEnumerable<FunctionArgument>)item.Value, context, ref nItems); - } - else - { - _CheckForAndHandleExcelError(item, context); - if (!ShouldIgnore(item) && ShouldCount(item.Value)) - { - nItems++; - } - } +public class CountA : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var nItems = 0d; + Calculate(arguments, context, ref nItems); + return CreateResult(nItems, DataType.Integer); + } - } + private void Calculate( + IEnumerable<FunctionArgument> items, + ParsingContext context, + ref double nItems) { + foreach (var item in items) { + var cs = item.Value as ExcelDataProvider.IRangeInfo; + if (cs != null) { + foreach (var c in cs) { + _CheckForAndHandleExcelError(c, context); + if (!ShouldIgnore(c, context) && ShouldCount(c.Value)) { + nItems++; + } } - - private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) - { - if (context.Scopes.Current.IsSubtotal) - { - CheckForAndHandleExcelError(arg); - } + } else if (item.Value is IEnumerable<FunctionArgument>) { + Calculate((IEnumerable<FunctionArgument>)item.Value, context, ref nItems); + } else { + _CheckForAndHandleExcelError(item, context); + if (!ShouldIgnore(item) && ShouldCount(item.Value)) { + nItems++; } - - private void _CheckForAndHandleExcelError(ExcelDataProvider.ICellInfo cell, ParsingContext context) - { - if (context.Scopes.Current.IsSubtotal) - { - CheckForAndHandleExcelError(cell); - } - } - - private bool ShouldCount(object value) - { - if (value == null) return false; - return (!string.IsNullOrEmpty(value.ToString())); - } + } } + } + + private void _CheckForAndHandleExcelError(FunctionArgument arg, ParsingContext context) { + if (context.Scopes.Current.IsSubtotal) { + CheckForAndHandleExcelError(arg); + } + } + + private void _CheckForAndHandleExcelError( + ExcelDataProvider.ICellInfo cell, + ParsingContext context) { + if (context.Scopes.Current.IsSubtotal) { + CheckForAndHandleExcelError(cell); + } + } + + private bool ShouldCount(object value) { + if (value == null) { + return false; + } + return (!string.IsNullOrEmpty(value.ToString())); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountBlank.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountBlank.cs index a5932ac..23176ae 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountBlank.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/CountBlank.cs
@@ -1,28 +1,25 @@ -using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; using System; using System.Collections.Generic; using System.Linq; -using System.Text; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class CountBlank : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = arguments.First(); - if(!arg.IsExcelRange)throw new InvalidOperationException("CountBlank only support ranges as arguments"); - var result = arg.ValueAsRangeInfo.GetNCells(); - foreach (var cell in arg.ValueAsRangeInfo) - { - if (!(cell.Value == null || cell.Value == string.Empty)) - { - result--; - } - } - return CreateResult(result, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class CountBlank : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = arguments.First(); + if (!arg.IsExcelRange) { + throw new InvalidOperationException("CountBlank only support ranges as arguments"); } + var result = arg.ValueAsRangeInfo.GetNCells(); + foreach (var cell in arg.ValueAsRangeInfo) { + if (!(cell.Value == null || cell.Value == string.Empty)) { + result--; + } + } + return CreateResult(result, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountIf.cs index 02f57a9..e5e7f14 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIf.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/CountIf.cs
@@ -1,84 +1,66 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.Utils; using Require = OfficeOpenXml.FormulaParsing.Utilities.Require; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class CountIf : ExcelFunction - { - private readonly NumericExpressionEvaluator _numericExpressionEvaluator; - private readonly WildCardValueMatcher _wildCardValueMatcher; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public CountIf() - : this(new NumericExpressionEvaluator(), new WildCardValueMatcher()) - { +public class CountIf : ExcelFunction { + private readonly NumericExpressionEvaluator _numericExpressionEvaluator; + private readonly WildCardValueMatcher _wildCardValueMatcher; - } + public CountIf() + : this(new(), new()) {} - public CountIf(NumericExpressionEvaluator evaluator, WildCardValueMatcher wildCardValueMatcher) - { - Require.That(evaluator).Named("evaluator").IsNotNull(); - Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull(); - _numericExpressionEvaluator = evaluator; - _wildCardValueMatcher = wildCardValueMatcher; - } + public CountIf(NumericExpressionEvaluator evaluator, WildCardValueMatcher wildCardValueMatcher) { + Require.That(evaluator).Named("evaluator").IsNotNull(); + Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull(); + _numericExpressionEvaluator = evaluator; + _wildCardValueMatcher = wildCardValueMatcher; + } - private bool Evaluate(object obj, string expression) - { - double? candidate = default(double?); - if (IsNumeric(obj)) - { - candidate = ConvertUtil.GetValueDouble(obj); - } - if (candidate.HasValue) - { - return _numericExpressionEvaluator.Evaluate(candidate.Value, expression); - } - if (obj == null) return false; - return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; - } - - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 2); - var range = functionArguments.ElementAt(0); - var criteria = ArgToString(functionArguments, 1); - double result = 0d; - if (range.IsExcelRange) - { - foreach (var cell in range.ValueAsRangeInfo) - { - if (Evaluate(cell.Value, criteria)) - { - result++; - } - } - } - else if (range.Value is IEnumerable<FunctionArgument>) - { - foreach (var arg in (IEnumerable<FunctionArgument>) range.Value) - { - if(Evaluate(arg.Value, criteria)) - { - result++; - } - } - } - else - { - if (Evaluate(range.Value, criteria)) - { - result++; - } - } - return CreateResult(result, DataType.Integer); - } + private bool Evaluate(object obj, string expression) { + double? candidate = default(double?); + if (IsNumeric(obj)) { + candidate = ConvertUtil.GetValueDouble(obj); } + if (candidate.HasValue) { + return _numericExpressionEvaluator.Evaluate(candidate.Value, expression); + } + if (obj == null) { + return false; + } + return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; + } + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 2); + var range = functionArguments.ElementAt(0); + var criteria = ArgToString(functionArguments, 1); + double result = 0d; + if (range.IsExcelRange) { + foreach (var cell in range.ValueAsRangeInfo) { + if (Evaluate(cell.Value, criteria)) { + result++; + } + } + } else if (range.Value is IEnumerable<FunctionArgument>) { + foreach (var arg in (IEnumerable<FunctionArgument>)range.Value) { + if (Evaluate(arg.Value, criteria)) { + result++; + } + } + } else { + if (Evaluate(range.Value, criteria)) { + result++; + } + } + return CreateResult(result, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIfs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/CountIfs.cs index 34e7526..e4b7418 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/CountIfs.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/CountIfs.cs
@@ -7,63 +7,56 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using System.Xml.XPath; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.Utilities; -using OfficeOpenXml.Utils; -using Require = OfficeOpenXml.FormulaParsing.Utilities.Require; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class CountIfs : MultipleRangeCriteriasFunction - { +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 2); - var argRanges = new List<ExcelDataProvider.IRangeInfo>(); - var criterias = new List<object>(); - for (var ix = 0; ix < 30; ix +=2) - { - if (functionArguments.Length <= ix) break; - var rangeInfo = functionArguments[ix].ValueAsRangeInfo; - argRanges.Add(rangeInfo); - if (ix > 0) - { - ThrowExcelErrorValueExceptionIf(() => rangeInfo.GetNCells() != argRanges[0].GetNCells(), eErrorType.Value); - } - criterias.Add(functionArguments[ix+1].Value); - } - IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]); - var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList(); - for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) - { - var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]); - matchIndexes = enumerable.Intersect(indexes); - } - - return CreateResult((double)matchIndexes.Count(), DataType.Integer); - } +public class CountIfs : MultipleRangeCriteriasFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 2); + var argRanges = new List<ExcelDataProvider.IRangeInfo>(); + var criterias = new List<object>(); + for (var ix = 0; ix < 30; ix += 2) { + if (functionArguments.Length <= ix) { + break; + } + var rangeInfo = functionArguments[ix].ValueAsRangeInfo; + argRanges.Add(rangeInfo); + if (ix > 0) { + ThrowExcelErrorValueExceptionIf( + () => rangeInfo.GetNCells() != argRanges[0].GetNCells(), + eErrorType.Value); + } + criterias.Add(functionArguments[ix + 1].Value); } + IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]); + var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList(); + for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) { + var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]); + matchIndexes = enumerable.Intersect(indexes); + } + + return CreateResult((double)matchIndexes.Count(), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Degrees.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Degrees.cs index 85d2979..7faae97 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Degrees.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Degrees.cs
@@ -1,19 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Degrees : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var angle = ArgToDecimal(arguments, 0); - var result = (angle*180)/System.Math.PI; - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Degrees : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var angle = ArgToDecimal(arguments, 0); + var result = (angle * 180) / System.Math.PI; + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Exp.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Exp.cs index 843b179..de88305 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Exp.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Exp.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Exp : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Exp(number), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Exp : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Exp(number), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Fact.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Fact.cs index da54301..2bb24f5 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Fact.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Fact.cs
@@ -1,24 +1,19 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Fact : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToDecimal(arguments, 0); - ThrowExcelErrorValueExceptionIf(() => number < 0, eErrorType.NA); - var result = 1d; - for (var x = 1; x < number; x++) - { - result *= x; - } - return CreateResult(result, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Fact : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToDecimal(arguments, 0); + ThrowExcelErrorValueExceptionIf(() => number < 0, eErrorType.Na); + var result = 1d; + for (var x = 1; x < number; x++) { + result *= x; } + return CreateResult(result, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Floor.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Floor.cs index 29d57c7..caa43c5 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Floor.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Floor.cs
@@ -7,70 +7,59 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Floor : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var number = ArgToDecimal(arguments, 0); - var significance = ArgToDecimal(arguments, 1); - ValidateNumberAndSign(number, significance); - if (significance < 1 && significance > 0) - { - var floor = System.Math.Floor(number); - var rest = number - floor; - var nSign = (int)(rest / significance); - return CreateResult(floor + (nSign * significance), DataType.Decimal); - } - else if (significance == 1) - { - return CreateResult(System.Math.Floor(number), DataType.Decimal); - } - else - { - double result; - if (number > 1) - { - result = number - (number % significance) + significance; - } - else - { - result = number - (number % significance); - } - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private void ValidateNumberAndSign(double number, double sign) - { - if (number > 0d && sign < 0) - { - var values = string.Format("num: {0}, sign: {1}", number, sign); - throw new InvalidOperationException("Floor cannot handle a negative significance when the number is positive" + values); - } - } +public class Floor : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var number = ArgToDecimal(arguments, 0); + var significance = ArgToDecimal(arguments, 1); + ValidateNumberAndSign(number, significance); + if (significance < 1 && significance > 0) { + var floor = System.Math.Floor(number); + var rest = number - floor; + var nSign = (int)(rest / significance); + return CreateResult(floor + (nSign * significance), DataType.Decimal); } + if (significance == 1) { + return CreateResult(System.Math.Floor(number), DataType.Decimal); + } + double result; + if (number > 1) { + result = number - (number % significance) + significance; + } else { + result = number - (number % significance); + } + return CreateResult(result, DataType.Decimal); + } + + private void ValidateNumberAndSign(double number, double sign) { + if (number > 0d && sign < 0) { + var values = string.Format("num: {0}, sign: {1}", number, sign); + throw new InvalidOperationException( + "Floor cannot handle a negative significance when the number is positive" + values); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Large.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Large.cs index adf4fe4..025c47f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Large.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Large.cs
@@ -1,22 +1,19 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Large : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var args = arguments.ElementAt(0); - var index = ArgToInt(arguments, 1) - 1; - var values = ArgsToDoubleEnumerable(new List<FunctionArgument> {args}, context); - ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num); - var result = values.OrderByDescending(x => x).ElementAt(index); - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Large : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var args = arguments.ElementAt(0); + var index = ArgToInt(arguments, 1) - 1; + var values = ArgsToDoubleEnumerable(new List<FunctionArgument> { args }, context); + ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num); + var result = values.OrderByDescending(x => x).ElementAt(index); + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Ln.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Ln.cs index 5769eec..e93147f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Ln.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Ln.cs
@@ -1,18 +1,14 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Ln : ExcelFunction -{ - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Log(arg, System.Math.E), DataType.Decimal); - } -} +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Ln : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Log(arg, System.Math.E), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Log.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Log.cs index 53b0007..c348ecf 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Log.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Log.cs
@@ -7,41 +7,38 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Log : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToDecimal(arguments, 0); - if (arguments.Count() == 1) - { - return CreateResult(System.Math.Log(number, 10d), DataType.Decimal); - } - var newBase = ArgToDecimal(arguments, 1); - return CreateResult(System.Math.Log(number, newBase), DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Log : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToDecimal(arguments, 0); + if (arguments.Count() == 1) { + return CreateResult(System.Math.Log(number, 10d), DataType.Decimal); } + var newBase = ArgToDecimal(arguments, 1); + return CreateResult(System.Math.Log(number, newBase), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Log10.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Log10.cs index 28c8eb3..c9f9431 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Log10.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Log10.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Log10 : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Log10(number), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Log10 : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Log10(number), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/MathHelper.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/MathHelper.cs index e4e813a..6b9163a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/MathHelper.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/MathHelper.cs
@@ -7,159 +7,132 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using MathObj = System.Math; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - /// <summary> - /// Thanks to the guys in this thread: http://stackoverflow.com/questions/2840798/c-sharp-math-class-question - /// </summary> - public static class MathHelper - { - // Secant - public static double Sec(double x) - { - return 1 / MathObj.Cos(x); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - // Cosecant - public static double Cosec(double x) - { - return 1 / MathObj.Sin(x); - } +/// <summary> +/// Thanks to the guys in this thread: http://stackoverflow.com/questions/2840798/c-sharp-math-class-question +/// </summary> +public static class MathHelper { + // Secant + public static double Sec(double x) { + return 1 / MathObj.Cos(x); + } - // Cotangent - public static double Cotan(double x) - { - return 1 / MathObj.Tan(x); - } + // Cosecant + public static double Cosec(double x) { + return 1 / MathObj.Sin(x); + } - // Inverse Sine - public static double Arcsin(double x) - { - return MathObj.Atan(x / MathObj.Sqrt(-x * x + 1)); - } + // Cotangent + public static double Cotan(double x) { + return 1 / MathObj.Tan(x); + } - // Inverse Cosine - public static double Arccos(double x) - { - return MathObj.Atan(-x / MathObj.Sqrt(-x * x + 1)) + 2 * MathObj.Atan(1); - } + // Inverse Sine + public static double Arcsin(double x) { + return MathObj.Atan(x / MathObj.Sqrt(-x * x + 1)); + } + // Inverse Cosine + public static double Arccos(double x) { + return MathObj.Atan(-x / MathObj.Sqrt(-x * x + 1)) + 2 * MathObj.Atan(1); + } - // Inverse Secant - public static double Arcsec(double x) - { - return 2 * MathObj.Atan(1) - MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1)); - } + // Inverse Secant + public static double Arcsec(double x) { + return 2 * MathObj.Atan(1) - MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1)); + } - // Inverse Cosecant - public static double Arccosec(double x) - { - return MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1)); - } + // Inverse Cosecant + public static double Arccosec(double x) { + return MathObj.Atan(MathObj.Sign(x) / MathObj.Sqrt(x * x - 1)); + } - // Inverse Cotangent - public static double Arccotan(double x) - { - return 2 * MathObj.Atan(1) - MathObj.Atan(x); - } + // Inverse Cotangent + public static double Arccotan(double x) { + return 2 * MathObj.Atan(1) - MathObj.Atan(x); + } - // Hyperbolic Sine - public static double HSin(double x) - { - return (MathObj.Exp(x) - MathObj.Exp(-x)) / 2; - } + // Hyperbolic Sine + public static double HSin(double x) { + return (MathObj.Exp(x) - MathObj.Exp(-x)) / 2; + } - // Hyperbolic Cosine - public static double HCos(double x) - { - return (MathObj.Exp(x) + MathObj.Exp(-x)) / 2; - } + // Hyperbolic Cosine + public static double HCos(double x) { + return (MathObj.Exp(x) + MathObj.Exp(-x)) / 2; + } - // Hyperbolic Tangent - public static double HTan(double x) - { - return (MathObj.Exp(x) - MathObj.Exp(-x)) / (MathObj.Exp(x) + MathObj.Exp(-x)); - } + // Hyperbolic Tangent + public static double HTan(double x) { + return (MathObj.Exp(x) - MathObj.Exp(-x)) / (MathObj.Exp(x) + MathObj.Exp(-x)); + } - // Hyperbolic Secant - public static double HSec(double x) - { - return 2 / (MathObj.Exp(x) + MathObj.Exp(-x)); - } + // Hyperbolic Secant + public static double HSec(double x) { + return 2 / (MathObj.Exp(x) + MathObj.Exp(-x)); + } - // Hyperbolic Cosecant - public static double HCosec(double x) - { - return 2 / (MathObj.Exp(x) - MathObj.Exp(-x)); - } + // Hyperbolic Cosecant + public static double HCosec(double x) { + return 2 / (MathObj.Exp(x) - MathObj.Exp(-x)); + } - // Hyperbolic Cotangent - public static double HCotan(double x) - { - return (MathObj.Exp(x) + MathObj.Exp(-x)) / (MathObj.Exp(x) - MathObj.Exp(-x)); - } + // Hyperbolic Cotangent + public static double HCotan(double x) { + return (MathObj.Exp(x) + MathObj.Exp(-x)) / (MathObj.Exp(x) - MathObj.Exp(-x)); + } - // Inverse Hyperbolic Sine - public static double HArcsin(double x) - { - return MathObj.Log(x + MathObj.Sqrt(x * x + 1)); - } + // Inverse Hyperbolic Sine + public static double HArcsin(double x) { + return MathObj.Log(x + MathObj.Sqrt(x * x + 1)); + } - // Inverse Hyperbolic Cosine - public static double HArccos(double x) - { - return MathObj.Log(x + MathObj.Sqrt(x * x - 1)); - } + // Inverse Hyperbolic Cosine + public static double HArccos(double x) { + return MathObj.Log(x + MathObj.Sqrt(x * x - 1)); + } - // Inverse Hyperbolic Tangent - public static double HArctan(double x) - { - return MathObj.Log((1 + x) / (1 - x)) / 2; - } + // Inverse Hyperbolic Tangent + public static double HArctan(double x) { + return MathObj.Log((1 + x) / (1 - x)) / 2; + } - // Inverse Hyperbolic Secant - public static double HArcsec(double x) - { - return MathObj.Log((MathObj.Sqrt(-x * x + 1) + 1) / x); - } + // Inverse Hyperbolic Secant + public static double HArcsec(double x) { + return MathObj.Log((MathObj.Sqrt(-x * x + 1) + 1) / x); + } - // Inverse Hyperbolic Cosecant - public static double HArccosec(double x) - { - return MathObj.Log((MathObj.Sign(x) * MathObj.Sqrt(x * x + 1) + 1) / x); - } + // Inverse Hyperbolic Cosecant + public static double HArccosec(double x) { + return MathObj.Log((MathObj.Sign(x) * MathObj.Sqrt(x * x + 1) + 1) / x); + } - // Inverse Hyperbolic Cotangent - public static double HArccotan(double x) - { - return MathObj.Log((x + 1) / (x - 1)) / 2; - } + // Inverse Hyperbolic Cotangent + public static double HArccotan(double x) { + return MathObj.Log((x + 1) / (x - 1)) / 2; + } - // Logarithm to base N - public static double LogN(double x, double n) - { - return MathObj.Log(x) / MathObj.Log(n); - } - } + // Logarithm to base N + public static double LogN(double x, double n) { + return MathObj.Log(x) / MathObj.Log(n); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Max.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Max.cs index 689c6eb..c6ddf8f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Max.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Max.cs
@@ -7,36 +7,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Max : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); - return CreateResult(values.Max(), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Max : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); + return CreateResult(values.Max(), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Maxa.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Maxa.cs index cd19664..1ef491a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Maxa.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Maxa.cs
@@ -7,49 +7,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Maxa : ExcelFunction - { - private readonly DoubleEnumerableArgConverter _argConverter; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public Maxa() - : this(new DoubleEnumerableArgConverter()) - { +public class Maxa : ExcelFunction { + private readonly DoubleEnumerableArgConverter _argConverter; - } - public Maxa(DoubleEnumerableArgConverter argConverter) - { - Require.That(argConverter).Named("argConverter").IsNotNull(); - _argConverter = argConverter; - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments); - return CreateResult(values.Max(), DataType.Decimal); - } - } + public Maxa() + : this(new()) {} + + public Maxa(DoubleEnumerableArgConverter argConverter) { + Require.That(argConverter).Named("argConverter").IsNotNull(); + _argConverter = argConverter; + } + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments); + return CreateResult(values.Max(), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Median.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Median.cs index 80cd503..6edc020 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Median.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Median.cs
@@ -7,48 +7,44 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-10 *******************************************************************************/ -using OfficeOpenXml.FormulaParsing.ExpressionGraph; + using System; using System.Collections.Generic; using System.Linq; -using System.Text; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Median : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var nums = ArgsToDoubleEnumerable(arguments, context); - var arr = nums.ToArray(); - Array.Sort(arr); - ThrowExcelErrorValueExceptionIf(() => arr.Length == 0, eErrorType.Num); - double result; - if (arr.Length % 2 == 1) - { - result = arr[arr.Length / 2]; - } - else - { - var startIndex = arr.Length/2 - 1; - result = (arr[startIndex] + arr[startIndex + 1])/2d; - } - return CreateResult(result, DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Median : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var nums = ArgsToDoubleEnumerable(arguments, context); + var arr = nums.ToArray(); + Array.Sort(arr); + ThrowExcelErrorValueExceptionIf(() => arr.Length == 0, eErrorType.Num); + double result; + if (arr.Length % 2 == 1) { + result = arr[arr.Length / 2]; + } else { + var startIndex = arr.Length / 2 - 1; + result = (arr[startIndex] + arr[startIndex + 1]) / 2d; } + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Min.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Min.cs index edd621f..f2b5fdf 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Min.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Min.cs
@@ -7,36 +7,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Min : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); - return CreateResult(values.Min(), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Min : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var values = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); + return CreateResult(values.Min(), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Mina.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Mina.cs index 65ebc87..a93424f 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Mina.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Mina.cs
@@ -7,49 +7,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Mina : ExcelFunction - { - private readonly DoubleEnumerableArgConverter _argConverter; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public Mina() - : this(new DoubleEnumerableArgConverter()) - { +public class Mina : ExcelFunction { + private readonly DoubleEnumerableArgConverter _argConverter; - } - public Mina(DoubleEnumerableArgConverter argConverter) - { - Require.That(argConverter).Named("argConverter").IsNotNull(); - _argConverter = argConverter; - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments); - return CreateResult(values.Min(), DataType.Decimal); - } - } + public Mina() + : this(new()) {} + + public Mina(DoubleEnumerableArgConverter argConverter) { + Require.That(argConverter).Named("argConverter").IsNotNull(); + _argConverter = argConverter; + } + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var values = _argConverter.ConvertArgsIncludingOtherTypes(arguments); + return CreateResult(values.Min(), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Mod.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Mod.cs index 4025d6b..968e1c8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Mod.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Mod.cs
@@ -7,37 +7,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Mod : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var n1 = ArgToDecimal(arguments, 0); - var n2 = ArgToDecimal(arguments, 1); - return new CompileResult(n1 % n2, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Mod : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var n1 = ArgToDecimal(arguments, 0); + var n2 = ArgToDecimal(arguments, 1); + return new(n1 % n2, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs index 4f29447..5efe6f0 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/MultipleRangeCriteriasFunction.cs
@@ -7,85 +7,72 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-15 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.Utils; using Require = OfficeOpenXml.FormulaParsing.Utilities.Require; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public abstract class MultipleRangeCriteriasFunction : ExcelFunction - { +public abstract class MultipleRangeCriteriasFunction : ExcelFunction { + private readonly NumericExpressionEvaluator _numericExpressionEvaluator; + private readonly WildCardValueMatcher _wildCardValueMatcher; - private readonly NumericExpressionEvaluator _numericExpressionEvaluator; - private readonly WildCardValueMatcher _wildCardValueMatcher; + protected MultipleRangeCriteriasFunction() + : this(new(), new()) {} - protected MultipleRangeCriteriasFunction() - :this(new NumericExpressionEvaluator(), new WildCardValueMatcher()) - { - - } + protected MultipleRangeCriteriasFunction( + NumericExpressionEvaluator evaluator, + WildCardValueMatcher wildCardValueMatcher) { + Require.That(evaluator).Named("evaluator").IsNotNull(); + Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull(); + _numericExpressionEvaluator = evaluator; + _wildCardValueMatcher = wildCardValueMatcher; + } - protected MultipleRangeCriteriasFunction(NumericExpressionEvaluator evaluator, WildCardValueMatcher wildCardValueMatcher) - { - Require.That(evaluator).Named("evaluator").IsNotNull(); - Require.That(wildCardValueMatcher).Named("wildCardValueMatcher").IsNotNull(); - _numericExpressionEvaluator = evaluator; - _wildCardValueMatcher = wildCardValueMatcher; - } - - protected bool Evaluate(object obj, object expression) - { - double? candidate = default(double?); - if (IsNumeric(obj)) - { - candidate = ConvertUtil.GetValueDouble(obj); - } - if (candidate.HasValue && expression is string) - { - return _numericExpressionEvaluator.Evaluate(candidate.Value, expression.ToString()); - } - if (obj == null) return false; - return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; - } - - protected List<int> GetMatchIndexes(ExcelDataProvider.IRangeInfo rangeInfo, object searched) - { - var result = new List<int>(); - var internalIndex = 0; - for (var row = rangeInfo.Address._fromRow; row <= rangeInfo.Address._toRow; row++) - { - for (var col = rangeInfo.Address._fromCol; col <= rangeInfo.Address._toCol; col++) - { - var candidate = rangeInfo.GetValue(row, col); - if (Evaluate(candidate, searched)) - { - result.Add(internalIndex); - } - internalIndex++; - } - } - return result; - } + protected bool Evaluate(object obj, object expression) { + double? candidate = default(double?); + if (IsNumeric(obj)) { + candidate = ConvertUtil.GetValueDouble(obj); } + if (candidate.HasValue && expression is string) { + return _numericExpressionEvaluator.Evaluate(candidate.Value, expression.ToString()); + } + if (obj == null) { + return false; + } + return _wildCardValueMatcher.IsMatch(expression, obj.ToString()) == 0; + } + + protected List<int> GetMatchIndexes(ExcelDataProvider.IRangeInfo rangeInfo, object searched) { + var result = new List<int>(); + var internalIndex = 0; + for (var row = rangeInfo.Address._fromRow; row <= rangeInfo.Address._toRow; row++) { + for (var col = rangeInfo.Address._fromCol; col <= rangeInfo.Address._toCol; col++) { + var candidate = rangeInfo.GetValue(row, col); + if (Evaluate(candidate, searched)) { + result.Add(internalIndex); + } + internalIndex++; + } + } + return result; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Pi.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Pi.cs index 244dce7..c606b48 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Pi.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Pi.cs
@@ -7,35 +7,32 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Pi : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var result = System.Math.Round((double)System.Math.PI, 14); - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Pi : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var result = System.Math.Round(System.Math.PI, 14); + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Power.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Power.cs index abe7e67..f0fd0a6 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Power.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Power.cs
@@ -7,38 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Power : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var number = ArgToDecimal(arguments, 0); - var power = ArgToDecimal(arguments, 1); - var result = System.Math.Pow(number, power); - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Power : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var number = ArgToDecimal(arguments, 0); + var power = ArgToDecimal(arguments, 1); + var result = System.Math.Pow(number, power); + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Product.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Product.cs index d8c8c4e..5414558 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Product.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Product.cs
@@ -7,85 +7,83 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Product : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var result = 0d; - var index = 0; - while (AreEqual(result, 0d) && index < arguments.Count()) - { - result = CalculateFirstItem(arguments, index++, context); - } - result = CalculateCollection(arguments.Skip(index), result, (arg, current) => - { - if (ShouldIgnore(arg)) return current; - if (arg.ValueIsExcelError) - { - ThrowExcelErrorValueException(arg.ValueAsExcelErrorValue.Type); - } - if (arg.IsExcelRange) - { - foreach (var cell in arg.ValueAsRangeInfo) - { - if(ShouldIgnore(cell, context)) return current; - current *= cell.ValueDouble; - } - return current; - } - var obj = arg.Value; - if (obj != null && IsNumeric(obj)) - { - var val = Convert.ToDouble(obj); - current *= val; - } - return current; - }); - return CreateResult(result, DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private double CalculateFirstItem(IEnumerable<FunctionArgument> arguments, int index, ParsingContext context) - { - var element = arguments.ElementAt(index); - var argList = new List<FunctionArgument> { element }; - var valueList = ArgsToDoubleEnumerable(false, false, argList, context); - var result = 0d; - foreach (var value in valueList) - { - if (result == 0d && value > 0d) - { - result = value; - } - else - { - result *= value; - } - } - return result; - } +public class Product : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var result = 0d; + var index = 0; + while (AreEqual(result, 0d) && index < arguments.Count()) { + result = CalculateFirstItem(arguments, index++, context); } + result = CalculateCollection( + arguments.Skip(index), + result, + (arg, current) => { + if (ShouldIgnore(arg)) { + return current; + } + if (arg.ValueIsExcelError) { + ThrowExcelErrorValueException(arg.ValueAsExcelErrorValue.Type); + } + if (arg.IsExcelRange) { + foreach (var cell in arg.ValueAsRangeInfo) { + if (ShouldIgnore(cell, context)) { + return current; + } + current *= cell.ValueDouble; + } + return current; + } + var obj = arg.Value; + if (obj != null && IsNumeric(obj)) { + var val = Convert.ToDouble(obj); + current *= val; + } + return current; + }); + return CreateResult(result, DataType.Decimal); + } + + private double CalculateFirstItem( + IEnumerable<FunctionArgument> arguments, + int index, + ParsingContext context) { + var element = arguments.ElementAt(index); + var argList = new List<FunctionArgument> { element }; + var valueList = ArgsToDoubleEnumerable(false, false, argList, context); + var result = 0d; + foreach (var value in valueList) { + if (result == 0d && value > 0d) { + result = value; + } else { + result *= value; + } + } + return result; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Quotient.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Quotient.cs index e4f7307..866ddd9 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Quotient.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Quotient.cs
@@ -1,21 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Quotient : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var num = ArgToDecimal(arguments, 0); - var denom = ArgToDecimal(arguments, 1); - ThrowExcelErrorValueExceptionIf(() => (int)denom == 0, eErrorType.Div0); - var result = (int)(num/denom); - return CreateResult(result, DataType.Integer); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Quotient : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var num = ArgToDecimal(arguments, 0); + var denom = ArgToDecimal(arguments, 1); + ThrowExcelErrorValueExceptionIf(() => (int)denom == 0, eErrorType.Div0); + var result = (int)(num / denom); + return CreateResult(result, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Rand.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Rand.cs index e04ebf5..9beb787 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Rand.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Rand.cs
@@ -1,24 +1,17 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Rand : ExcelFunction - { - private static int Seed - { - get; - set; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - Seed = Seed > 50 ? 0 : Seed + 5; - var val = new Random(System.DateTime.Now.Millisecond + Seed).NextDouble(); - return CreateResult(val, DataType.Decimal); - } - } +public class Rand : ExcelFunction { + private static int Seed { get; set; } + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + Seed = Seed > 50 ? 0 : Seed + 5; + var val = new Random(System.DateTime.Now.Millisecond + Seed).NextDouble(); + return CreateResult(val, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/RandBetween.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/RandBetween.cs index 0202085..5bb9e8a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/RandBetween.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/RandBetween.cs
@@ -7,53 +7,47 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class RandBetween : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var low = ArgToDecimal(arguments, 0); - var high = ArgToDecimal(arguments, 1); - var rand = new Rand().Execute(new FunctionArgument[0], context).Result; - var randPart = (CalulateDiff(high, low) * (double)rand) + 1; - randPart = System.Math.Floor(randPart); - return CreateResult(low + randPart, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private double CalulateDiff(double high, double low) - { - if (high > 0 && low < 0) - { - return high + low * - 1; - } - else if (high < 0 && low < 0) - { - return high * -1 - low * -1; - } - return high - low; - } +public class RandBetween : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var low = ArgToDecimal(arguments, 0); + var high = ArgToDecimal(arguments, 1); + var rand = new Rand().Execute(new FunctionArgument[0], context).Result; + var randPart = (CalulateDiff(high, low) * (double)rand) + 1; + randPart = System.Math.Floor(randPart); + return CreateResult(low + randPart, DataType.Integer); + } + + private double CalulateDiff(double high, double low) { + if (high > 0 && low < 0) { + return high + low * -1; } + if (high < 0 && low < 0) { + return high * -1 - low * -1; + } + return high - low; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Rank.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Rank.cs index 7087b5f..ae71b2c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Rank.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Rank.cs
@@ -1,69 +1,66 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Rank : ExcelFunction - { - bool _isAvg; - public Rank(bool isAvg=false) - { - _isAvg=isAvg; - } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var number = ArgToDecimal(arguments, 0); - var refer = arguments.ElementAt(1); - bool asc = false; - if (arguments.Count() > 2) - { - asc = base.ArgToBool(arguments, 2); - } - var l = new List<double>(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math { + public class Rank : ExcelFunction { + bool _isAvg; - foreach (var c in refer.ValueAsRangeInfo) - { - var v = Utils.ConvertUtil.GetValueDouble(c.Value, false, true); - if (!double.IsNaN(v)) - { - l.Add(v); - } - } - l.Sort(); - double ix; - if (asc) - { - ix = l.IndexOf(number)+1; - if(_isAvg) - { - int st = Convert.ToInt32(ix); - while (l.Count > st && l[st] == number) st++; - if (st > ix) ix = ix + ((st - ix) / 2D); - } - } - else - { - ix = l.LastIndexOf(number); - if (_isAvg) - { - int st = Convert.ToInt32(ix)-1; - while (0 <= st && l[st] == number) st--; - if (st+1 < ix) ix = ix - ((ix - st - 1) / 2D); - } - ix = l.Count - ix; - } - if (ix <= 0 || ix>l.Count) - { - return new CompileResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); - } - else - { - return CreateResult(ix, DataType.Decimal); - } - } + public Rank(bool isAvg = false) { + _isAvg = isAvg; } + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var number = ArgToDecimal(arguments, 0); + var refer = arguments.ElementAt(1); + bool asc = false; + if (arguments.Count() > 2) { + asc = base.ArgToBool(arguments, 2); + } + var l = new List<double>(); + + foreach (var c in refer.ValueAsRangeInfo) { + var v = Utils.ConvertUtil.GetValueDouble(c.Value, false, true); + if (!double.IsNaN(v)) { + l.Add(v); + } + } + l.Sort(); + double ix; + if (asc) { + ix = l.IndexOf(number) + 1; + if (_isAvg) { + int st = Convert.ToInt32(ix); + while (l.Count > st && l[st] == number) { + st++; + } + if (st > ix) { + ix = ix + ((st - ix) / 2D); + } + } + } else { + ix = l.LastIndexOf(number); + if (_isAvg) { + int st = Convert.ToInt32(ix) - 1; + while (0 <= st && l[st] == number) { + st--; + } + if (st + 1 < ix) { + ix = ix - ((ix - st - 1) / 2D); + } + } + ix = l.Count - ix; + } + if (ix <= 0 || ix > l.Count) { + return new CompileResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); + } else { + return CreateResult(ix, DataType.Decimal); + } + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Round.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Round.cs index 78407fc..1bda92d 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Round.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Round.cs
@@ -7,42 +7,38 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Round : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var number = ArgToDecimal(arguments, 0); - var nDigits = ArgToInt(arguments, 1); - if (nDigits < 0) - { - nDigits *= -1; - return CreateResult(number - (number % (System.Math.Pow(10, nDigits))), DataType.Integer); - } - return CreateResult(System.Math.Round(number, nDigits), DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Round : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var number = ArgToDecimal(arguments, 0); + var nDigits = ArgToInt(arguments, 1); + if (nDigits < 0) { + nDigits *= -1; + return CreateResult(number - (number % (System.Math.Pow(10, nDigits))), DataType.Integer); } + return CreateResult(System.Math.Round(number, nDigits), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Rounddown.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Rounddown.cs index 82e9fcd..396c355 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Rounddown.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Rounddown.cs
@@ -7,61 +7,54 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2014-01-06 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Rounddown : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var number = ArgToDecimal(arguments, 0); - var nDecimals = ArgToInt(arguments, 1); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - var nFactor = number < 0 ? -1 : 1; - number *= nFactor; +public class Rounddown : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var number = ArgToDecimal(arguments, 0); + var nDecimals = ArgToInt(arguments, 1); - double result; - if (nDecimals > 0) - { - result = RoundDownDecimalNumber(number, nDecimals); - } - else - { - result = (int)System.Math.Floor(number); - result = result - (result % System.Math.Pow(10, (nDecimals*-1))); - } - return CreateResult(result * nFactor, DataType.Decimal); - } + var nFactor = number < 0 ? -1 : 1; + number *= nFactor; - private static double RoundDownDecimalNumber(double number, int nDecimals) - { - var integerPart = System.Math.Floor(number); - var decimalPart = number - integerPart; - decimalPart = System.Math.Pow(10d, nDecimals)*decimalPart; - decimalPart = System.Math.Truncate(decimalPart)/System.Math.Pow(10d, nDecimals); - var result = integerPart + decimalPart; - return result; - } + double result; + if (nDecimals > 0) { + result = RoundDownDecimalNumber(number, nDecimals); + } else { + result = (int)System.Math.Floor(number); + result = result - (result % System.Math.Pow(10, (nDecimals * -1))); } + return CreateResult(result * nFactor, DataType.Decimal); + } + + private static double RoundDownDecimalNumber(double number, int nDecimals) { + var integerPart = System.Math.Floor(number); + var decimalPart = number - integerPart; + decimalPart = System.Math.Pow(10d, nDecimals) * decimalPart; + decimalPart = System.Math.Truncate(decimalPart) / System.Math.Pow(10d, nDecimals); + var result = integerPart + decimalPart; + return result; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Roundup.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Roundup.cs index 80c00ff..d411ce6 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Roundup.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Roundup.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,40 +7,40 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2014-01-06 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Roundup : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var number = ArgToDecimal(arguments, 0); - var nDigits = ArgToInt(arguments, 1); - double result = (number >= 0) - ? System.Math.Ceiling(number * System.Math.Pow(10, nDigits)) / System.Math.Pow(10, nDigits) - : System.Math.Floor(number * System.Math.Pow(10, nDigits)) / System.Math.Pow(10, nDigits); - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Roundup : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var number = ArgToDecimal(arguments, 0); + var nDigits = ArgToInt(arguments, 1); + double result = + (number >= 0) + ? System.Math.Ceiling(number * System.Math.Pow(10, nDigits)) + / System.Math.Pow(10, nDigits) + : System.Math.Floor(number * System.Math.Pow(10, nDigits)) + / System.Math.Pow(10, nDigits); + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sign.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sign.cs index a060685..e09a919 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sign.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Sign.cs
@@ -7,45 +7,39 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Sign : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var result = 0d; - var val = ArgToDecimal(arguments, 0); - if (val < 0) - { - result = -1; - } - else if (val > 0) - { - result = 1; - } - return CreateResult(result, DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Sign : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var result = 0d; + var val = ArgToDecimal(arguments, 0); + if (val < 0) { + result = -1; + } else if (val > 0) { + result = 1; } + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sin.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sin.cs index 0e3bc1f..5b55efa 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sin.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Sin.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Sin : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Sin(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Sin : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Sin(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sinh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sinh.cs index ec1b646..5cf3d88 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sinh.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Sinh.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Sinh : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Sinh(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Sinh : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Sinh(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Small.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Small.cs index 5defb12..f22e9fa 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Small.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Small.cs
@@ -1,22 +1,19 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Small : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var args = arguments.ElementAt(0); - var index = ArgToInt(arguments, 1) - 1; - var values = ArgsToDoubleEnumerable(new List<FunctionArgument> { args }, context); - ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num); - var result = values.OrderBy(x => x).ElementAt(index); - return CreateResult(result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Small : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var args = arguments.ElementAt(0); + var index = ArgToInt(arguments, 1) - 1; + var values = ArgsToDoubleEnumerable(new List<FunctionArgument> { args }, context); + ThrowExcelErrorValueExceptionIf(() => index < 0 || index >= values.Count(), eErrorType.Num); + var result = values.OrderBy(x => x).ElementAt(index); + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sqrt.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sqrt.cs index ccaebf7..61dff82 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sqrt.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Sqrt.cs
@@ -7,37 +7,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Sqrt : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - var result = System.Math.Sqrt((double)arg); - return CreateResult((double)result, DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Sqrt : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + var result = System.Math.Sqrt(arg); + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs index a87edd3..cea3e32 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/SqrtPi.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class SqrtPi : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Sqrt(number * System.Math.PI), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class SqrtPi : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Sqrt(number * System.Math.PI), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Stdev.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Stdev.cs index 44bfa43..62831fb 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Stdev.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Stdev.cs
@@ -7,56 +7,53 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; -using MathObj = System.Math; using OfficeOpenXml.FormulaParsing.ExpressionGraph; +using MathObj = System.Math; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Stdev : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var values = ArgsToDoubleEnumerable(arguments, context, false); - return CreateResult(StandardDeviation(values), DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private double StandardDeviation(IEnumerable<double> values) - { - double ret = 0; - if (values.Any()) - { - var nValues = values.Count(); - if(nValues == 1) throw new ExcelErrorValueException(eErrorType.Div0); - //Compute the Average - double avg = values.Average(); - //Perform the Sum of (value-avg)_2_2 - double sum = values.Sum(d => MathObj.Pow(d - avg, 2)); - //Put it all together - ret = MathObj.Sqrt(Divide(sum, (values.Count() - 1))); - } - return ret; - } +public class Stdev : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var values = ArgsToDoubleEnumerable(arguments, context, false); + return CreateResult(StandardDeviation(values), DataType.Decimal); + } + private double StandardDeviation(IEnumerable<double> values) { + double ret = 0; + if (values.Any()) { + var nValues = values.Count(); + if (nValues == 1) { + throw new ExcelErrorValueException(eErrorType.Div0); + } + //Compute the Average + double avg = values.Average(); + //Perform the Sum of (value-avg)_2_2 + double sum = values.Sum(d => MathObj.Pow(d - avg, 2)); + //Put it all together + ret = MathObj.Sqrt(Divide(sum, (values.Count() - 1))); } + return ret; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/StdevP.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/StdevP.cs index f97065d..16e7b7a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/StdevP.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/StdevP.cs
@@ -7,42 +7,39 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using MathObj = System.Math; using OfficeOpenXml.FormulaParsing.ExpressionGraph; +using MathObj = System.Math; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class StdevP : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); - return CreateResult(StandardDeviation(args), DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private static double StandardDeviation(IEnumerable<double> values) - { - double avg = values.Average(); - return MathObj.Sqrt(values.Average(v => MathObj.Pow(v - avg, 2))); - } - } +public class StdevP : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); + return CreateResult(StandardDeviation(args), DataType.Decimal); + } + + private static double StandardDeviation(IEnumerable<double> values) { + double avg = values.Average(); + return MathObj.Sqrt(values.Average(v => MathObj.Pow(v - avg, 2))); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs index d02024e..45e11e6 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Subtotal.cs
@@ -7,101 +7,92 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Subtotal : ExcelFunction - { - private Dictionary<int, HiddenValuesHandlingFunction> _functions = new Dictionary<int, HiddenValuesHandlingFunction>(); - - public Subtotal() - { - Initialize(); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private void Initialize() - { - _functions[1] = new Average(); - _functions[2] = new Count(); - _functions[3] = new CountA(); - _functions[4] = new Max(); - _functions[5] = new Min(); - _functions[6] = new Product(); - _functions[7] = new Stdev(); - _functions[8] = new StdevP(); - _functions[9] = new Sum(); - _functions[10] = new Var(); - _functions[11] = new VarP(); +public class Subtotal : ExcelFunction { + private Dictionary<int, HiddenValuesHandlingFunction> _functions = new(); - AddHiddenValueHandlingFunction(new Average(), 101); - AddHiddenValueHandlingFunction(new Count(), 102); - AddHiddenValueHandlingFunction(new CountA(), 103); - AddHiddenValueHandlingFunction(new Max(), 104); - AddHiddenValueHandlingFunction(new Min(), 105); - AddHiddenValueHandlingFunction(new Product(), 106); - AddHiddenValueHandlingFunction(new Stdev(), 107); - AddHiddenValueHandlingFunction(new StdevP(), 108); - AddHiddenValueHandlingFunction(new Sum(), 109); - AddHiddenValueHandlingFunction(new Var(), 110); - AddHiddenValueHandlingFunction(new VarP(), 111); - } + public Subtotal() { + Initialize(); + } - private void AddHiddenValueHandlingFunction(HiddenValuesHandlingFunction func, int funcNum) - { - func.IgnoreHiddenValues = true; - _functions[funcNum] = func; - } + private void Initialize() { + _functions[1] = new Average(); + _functions[2] = new Count(); + _functions[3] = new CountA(); + _functions[4] = new Max(); + _functions[5] = new Min(); + _functions[6] = new Product(); + _functions[7] = new Stdev(); + _functions[8] = new StdevP(); + _functions[9] = new Sum(); + _functions[10] = new Var(); + _functions[11] = new VarP(); - public override void BeforeInvoke(ParsingContext context) - { - base.BeforeInvoke(context); - context.Scopes.Current.IsSubtotal = true; - } + AddHiddenValueHandlingFunction(new Average(), 101); + AddHiddenValueHandlingFunction(new Count(), 102); + AddHiddenValueHandlingFunction(new CountA(), 103); + AddHiddenValueHandlingFunction(new Max(), 104); + AddHiddenValueHandlingFunction(new Min(), 105); + AddHiddenValueHandlingFunction(new Product(), 106); + AddHiddenValueHandlingFunction(new Stdev(), 107); + AddHiddenValueHandlingFunction(new StdevP(), 108); + AddHiddenValueHandlingFunction(new Sum(), 109); + AddHiddenValueHandlingFunction(new Var(), 110); + AddHiddenValueHandlingFunction(new VarP(), 111); + } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var funcNum = ArgToInt(arguments, 0); - if (context.Scopes.Current.Parent != null && context.Scopes.Current.Parent.IsSubtotal) - { - return CreateResult(0d, DataType.Decimal); - } - var actualArgs = arguments.Skip(1); - ExcelFunction function = null; - function = GetFunctionByCalcType(funcNum); - var compileResult = function.Execute(actualArgs, context); - compileResult.IsResultOfSubtotal = true; - return compileResult; - } + private void AddHiddenValueHandlingFunction(HiddenValuesHandlingFunction func, int funcNum) { + func.IgnoreHiddenValues = true; + _functions[funcNum] = func; + } - private ExcelFunction GetFunctionByCalcType(int funcNum) - { - if (!_functions.ContainsKey(funcNum)) - { - ThrowExcelErrorValueException(eErrorType.Value); - //throw new ArgumentException("Invalid funcNum " + funcNum + ", valid ranges are 1-11 and 101-111"); - } - return _functions[funcNum]; - } + public override void BeforeInvoke(ParsingContext context) { + base.BeforeInvoke(context); + context.Scopes.Current.IsSubtotal = true; + } + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var funcNum = ArgToInt(arguments, 0); + if (context.Scopes.Current.Parent != null && context.Scopes.Current.Parent.IsSubtotal) { + return CreateResult(0d, DataType.Decimal); } + var actualArgs = arguments.Skip(1); + ExcelFunction function = null; + function = GetFunctionByCalcType(funcNum); + var compileResult = function.Execute(actualArgs, context); + compileResult.IsResultOfSubtotal = true; + return compileResult; + } + + private ExcelFunction GetFunctionByCalcType(int funcNum) { + if (!_functions.ContainsKey(funcNum)) { + ThrowExcelErrorValueException(eErrorType.Value); + //throw new ArgumentException("Invalid funcNum " + funcNum + ", valid ranges are 1-11 and 101-111"); + } + return _functions[funcNum]; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sum.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sum.cs index 4cc7d24..5d3550e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sum.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Sum.cs
@@ -7,78 +7,61 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Sum : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var retVal = 0d; - if (arguments != null) - { - foreach (var arg in arguments) - { - retVal += Calculate(arg, context); - } - } - return CreateResult(retVal, DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - - private double Calculate(FunctionArgument arg, ParsingContext context) - { - var retVal = 0d; - if (ShouldIgnore(arg)) - { - return retVal; - } - if (arg.Value is IEnumerable<FunctionArgument>) - { - foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) - { - retVal += Calculate(item, context); - } - } - else if (arg.Value is ExcelDataProvider.IRangeInfo) - { - foreach (var c in (ExcelDataProvider.IRangeInfo)arg.Value) - { - if (ShouldIgnore(c, context) == false) - { - CheckForAndHandleExcelError(c); - retVal += c.ValueDouble; - } - } - } - else - { - CheckForAndHandleExcelError(arg); - retVal += ConvertUtil.GetValueDouble(arg.Value, true); - } - return retVal; - } +public class Sum : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var retVal = 0d; + if (arguments != null) { + foreach (var arg in arguments) { + retVal += Calculate(arg, context); + } } + return CreateResult(retVal, DataType.Decimal); + } + + private double Calculate(FunctionArgument arg, ParsingContext context) { + var retVal = 0d; + if (ShouldIgnore(arg)) { + return retVal; + } + if (arg.Value is IEnumerable<FunctionArgument>) { + foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) { + retVal += Calculate(item, context); + } + } else if (arg.Value is ExcelDataProvider.IRangeInfo) { + foreach (var c in (ExcelDataProvider.IRangeInfo)arg.Value) { + if (ShouldIgnore(c, context) == false) { + CheckForAndHandleExcelError(c); + retVal += c.ValueDouble; + } + } + } else { + CheckForAndHandleExcelError(arg); + retVal += ConvertUtil.GetValueDouble(arg.Value, true); + } + return retVal; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs index 3c50d3e..1750c4e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIf.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,170 +7,161 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.FormulaParsing.Exceptions; -using Util=OfficeOpenXml.Utils; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; +using OfficeOpenXml.FormulaParsing.Utilities; +using Util = OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class SumIf : HiddenValuesHandlingFunction - { - private readonly NumericExpressionEvaluator _evaluator; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public SumIf() - : this(new NumericExpressionEvaluator()) - { +public class SumIf : HiddenValuesHandlingFunction { + private readonly NumericExpressionEvaluator _evaluator; - } + public SumIf() + : this(new()) {} - public SumIf(NumericExpressionEvaluator evaluator) - { - Require.That(evaluator).Named("evaluator").IsNotNull(); - _evaluator = evaluator; - } + public SumIf(NumericExpressionEvaluator evaluator) { + Require.That(evaluator).Named("evaluator").IsNotNull(); + _evaluator = evaluator; + } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var args = arguments.ElementAt(0).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>; - var criteria = arguments.ElementAt(1).Value; - ThrowExcelErrorValueExceptionIf(() => criteria == null || criteria.ToString().Length > 255, eErrorType.Value); - var retVal = 0d; - if (arguments.Count() > 2) - { - var sumRange = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo;//IEnumerable<FunctionArgument>; - retVal = CalculateWithSumRange(args, criteria.ToString(), sumRange, context); - } - else - { - if (args != null) - { - retVal = CalculateSingleRange(args, criteria.ToString(), context); - } - else - { - retVal = CalculateSingleRange((arguments.ElementAt(0).Value as IEnumerable<FunctionArgument>), - criteria.ToString(), context); - } - } - return CreateResult(retVal, DataType.Decimal); - } - - private double CalculateWithSumRange(IEnumerable<FunctionArgument> range, string criteria, IEnumerable<FunctionArgument> sumRange, ParsingContext context) - { - var retVal = 0d; - var flattenedRange = ArgsToDoubleEnumerable(range, context); - var flattenedSumRange = ArgsToDoubleEnumerable(sumRange, context); - for (var x = 0; x < flattenedRange.Count(); x++) - { - var candidate = flattenedSumRange.ElementAt(x); - if (_evaluator.Evaluate(flattenedRange.ElementAt(x), criteria)) - { - retVal += candidate; - } - } - return retVal; - } - - private double CalculateWithSumRange(ExcelDataProvider.IRangeInfo range, string criteria, ExcelDataProvider.IRangeInfo sumRange, ParsingContext context) - { - var retVal = 0d; - foreach(var cell in range) - { - if (_evaluator.Evaluate(cell.Value, criteria)) - { - var or = cell.Row-range.Address._fromRow; - var oc = cell.Column - range.Address._fromCol; - if(sumRange.Address._fromRow+or <= sumRange.Address._toRow && - sumRange.Address._fromCol+oc <= sumRange.Address._toCol) - { - var v = sumRange.GetOffset(or, oc); - if (v is ExcelErrorValue) - { - throw (new ExcelErrorValueException((ExcelErrorValue)v)); - } - retVal += Util.ConvertUtil.GetValueDouble(v, true); - } - } - } - return retVal; - } - - private double CalculateSingleRange(IEnumerable<FunctionArgument> args, string expression, ParsingContext context) - { - var retVal = 0d; - var flattendedRange = ArgsToDoubleEnumerable(args, context); - foreach (var candidate in flattendedRange) - { - if (_evaluator.Evaluate(candidate, expression)) - { - retVal += candidate; - } - } - return retVal; - } - - private double CalculateSingleRange(ExcelDataProvider.IRangeInfo range, string expression, ParsingContext context) - { - var retVal = 0d; - foreach (var candidate in range) - { - if (_evaluator.Evaluate(candidate.Value, expression)) - { - if (candidate.IsExcelError) - { - throw (new ExcelErrorValueException((ExcelErrorValue)candidate.Value)); - } - retVal += candidate.ValueDouble; - } - } - return retVal; - } - - //private double Calculate(FunctionArgument arg, string expression) - //{ - // var retVal = 0d; - // if (ShouldIgnore(arg) || !_evaluator.Evaluate(arg.Value, expression)) - // { - // return retVal; - // } - // if (arg.Value is double || arg.Value is int) - // { - // retVal += Convert.ToDouble(arg.Value); - // } - // else if (arg.Value is System.DateTime) - // { - // retVal += Convert.ToDateTime(arg.Value).ToOADate(); - // } - // else if (arg.Value is IEnumerable<FunctionArgument>) - // { - // foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) - // { - // retVal += Calculate(item, expression); - // } - // } - // return retVal; - //} + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var args = arguments.ElementAt(0).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>; + var criteria = arguments.ElementAt(1).Value; + ThrowExcelErrorValueExceptionIf( + () => criteria == null || criteria.ToString().Length > 255, + eErrorType.Value); + var retVal = 0d; + if (arguments.Count() > 2) { + var sumRange = arguments.ElementAt(2).Value as ExcelDataProvider.IRangeInfo; //IEnumerable<FunctionArgument>; + retVal = CalculateWithSumRange(args, criteria.ToString(), sumRange, context); + } else { + if (args != null) { + retVal = CalculateSingleRange(args, criteria.ToString(), context); + } else { + retVal = CalculateSingleRange( + (arguments.ElementAt(0).Value as IEnumerable<FunctionArgument>), + criteria.ToString(), + context); + } } + return CreateResult(retVal, DataType.Decimal); + } + + private double CalculateWithSumRange( + IEnumerable<FunctionArgument> range, + string criteria, + IEnumerable<FunctionArgument> sumRange, + ParsingContext context) { + var retVal = 0d; + var flattenedRange = ArgsToDoubleEnumerable(range, context); + var flattenedSumRange = ArgsToDoubleEnumerable(sumRange, context); + for (var x = 0; x < flattenedRange.Count(); x++) { + var candidate = flattenedSumRange.ElementAt(x); + if (_evaluator.Evaluate(flattenedRange.ElementAt(x), criteria)) { + retVal += candidate; + } + } + return retVal; + } + + private double CalculateWithSumRange( + ExcelDataProvider.IRangeInfo range, + string criteria, + ExcelDataProvider.IRangeInfo sumRange, + ParsingContext context) { + var retVal = 0d; + foreach (var cell in range) { + if (_evaluator.Evaluate(cell.Value, criteria)) { + var or = cell.Row - range.Address._fromRow; + var oc = cell.Column - range.Address._fromCol; + if (sumRange.Address._fromRow + or <= sumRange.Address._toRow + && sumRange.Address._fromCol + oc <= sumRange.Address._toCol) { + var v = sumRange.GetOffset(or, oc); + if (v is ExcelErrorValue) { + throw (new ExcelErrorValueException((ExcelErrorValue)v)); + } + retVal += Util.ConvertUtil.GetValueDouble(v, true); + } + } + } + return retVal; + } + + private double CalculateSingleRange( + IEnumerable<FunctionArgument> args, + string expression, + ParsingContext context) { + var retVal = 0d; + var flattendedRange = ArgsToDoubleEnumerable(args, context); + foreach (var candidate in flattendedRange) { + if (_evaluator.Evaluate(candidate, expression)) { + retVal += candidate; + } + } + return retVal; + } + + private double CalculateSingleRange( + ExcelDataProvider.IRangeInfo range, + string expression, + ParsingContext context) { + var retVal = 0d; + foreach (var candidate in range) { + if (_evaluator.Evaluate(candidate.Value, expression)) { + if (candidate.IsExcelError) { + throw (new ExcelErrorValueException((ExcelErrorValue)candidate.Value)); + } + retVal += candidate.ValueDouble; + } + } + return retVal; + } + + //private double Calculate(FunctionArgument arg, string expression) + //{ + // var retVal = 0d; + // if (ShouldIgnore(arg) || !_evaluator.Evaluate(arg.Value, expression)) + // { + // return retVal; + // } + // if (arg.Value is double || arg.Value is int) + // { + // retVal += Convert.ToDouble(arg.Value); + // } + // else if (arg.Value is System.DateTime) + // { + // retVal += Convert.ToDateTime(arg.Value).ToOADate(); + // } + // else if (arg.Value is IEnumerable<FunctionArgument>) + // { + // foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) + // { + // retVal += Calculate(item, expression); + // } + // } + // return retVal; + //} }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIfs.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIfs.cs index aefaea0..72ed696 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/SumIfs.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/SumIfs.cs
@@ -7,60 +7,63 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-15 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class SumIfs : MultipleRangeCriteriasFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 3); - var sumRange = ArgsToDoubleEnumerable(true, new List<FunctionArgument> {functionArguments[0]}, context).ToList(); - var argRanges = new List<ExcelDataProvider.IRangeInfo>(); - var criterias = new List<object>(); - for (var ix = 1; ix < 31; ix += 2) - { - if (functionArguments.Length <= ix) break; - var rangeInfo = functionArguments[ix].ValueAsRangeInfo; - argRanges.Add(rangeInfo); - if (ix > 1) - { - ThrowExcelErrorValueExceptionIf(() => rangeInfo.GetNCells() != argRanges[0].GetNCells(), eErrorType.Value); - } - criterias.Add(functionArguments[ix + 1].Value); - } - IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]); - var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList(); - for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) - { - var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]); - matchIndexes = enumerable.Intersect(indexes); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - var result = matchIndexes.Sum(index => sumRange[index]); - - return CreateResult(result, DataType.Decimal); - } +public class SumIfs : MultipleRangeCriteriasFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 3); + var sumRange = ArgsToDoubleEnumerable( + true, + new List<FunctionArgument> { functionArguments[0] }, + context) + .ToList(); + var argRanges = new List<ExcelDataProvider.IRangeInfo>(); + var criterias = new List<object>(); + for (var ix = 1; ix < 31; ix += 2) { + if (functionArguments.Length <= ix) { + break; + } + var rangeInfo = functionArguments[ix].ValueAsRangeInfo; + argRanges.Add(rangeInfo); + if (ix > 1) { + ThrowExcelErrorValueExceptionIf( + () => rangeInfo.GetNCells() != argRanges[0].GetNCells(), + eErrorType.Value); + } + criterias.Add(functionArguments[ix + 1].Value); } + IEnumerable<int> matchIndexes = GetMatchIndexes(argRanges[0], criterias[0]); + var enumerable = matchIndexes as IList<int> ?? matchIndexes.ToList(); + for (var ix = 1; ix < argRanges.Count && enumerable.Any(); ix++) { + var indexes = GetMatchIndexes(argRanges[ix], criterias[ix]); + matchIndexes = enumerable.Intersect(indexes); + } + + var result = matchIndexes.Sum(index => sumRange[index]); + + return CreateResult(result, DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/SumProduct.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/SumProduct.cs index 5ee6de5..6985eb7 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/SumProduct.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/SumProduct.cs
@@ -7,100 +7,80 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class SumProduct : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - double result = 0d; - List<List<double>> results = new List<List<double>>(); - foreach (var arg in arguments) - { - results.Add(new List<double>()); - var currentResult = results.Last(); - if (arg.Value is IEnumerable<FunctionArgument>) - { - foreach (var val in (IEnumerable<FunctionArgument>)arg.Value) - { - AddValue(val.Value, currentResult); - } - } - else if (arg.Value is FunctionArgument) - { - AddValue(arg.Value, currentResult); - } - else if (arg.IsExcelRange) - { - var r=arg.ValueAsRangeInfo; - for (int col = r.Address._fromCol; col <= r.Address._toCol; col++) - { - for (int row = r.Address._fromRow; row <= r.Address._toRow; row++) - { - AddValue(r.GetValue(row,col), currentResult); - } - } - } - } - // Validate that all supplied lists have the same length - var arrayLength = results.First().Count; - foreach (var list in results) - { - if (list.Count != arrayLength) - { - throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); - //throw new ExcelFunctionException("All supplied arrays must have the same length", ExcelErrorCodes.Value); - } - } - for (var rowIndex = 0; rowIndex < arrayLength; rowIndex++) - { - double rowResult = 1; - for (var colIndex = 0; colIndex < results.Count; colIndex++) - { - rowResult *= results[colIndex][rowIndex]; - } - result += rowResult; - } - return CreateResult(result, DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - private void AddValue(object convertVal, List<double> currentResult) - { - if (IsNumeric(convertVal)) - { - currentResult.Add(Convert.ToDouble(convertVal)); - } - else if (convertVal is ExcelErrorValue) - { - throw (new ExcelErrorValueException((ExcelErrorValue)convertVal)); - } - else - { - currentResult.Add(0d); - } +public class SumProduct : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + double result = 0d; + List<List<double>> results = new List<List<double>>(); + foreach (var arg in arguments) { + results.Add(new()); + var currentResult = results.Last(); + if (arg.Value is IEnumerable<FunctionArgument>) { + foreach (var val in (IEnumerable<FunctionArgument>)arg.Value) { + AddValue(val.Value, currentResult); } + } else if (arg.Value is FunctionArgument) { + AddValue(arg.Value, currentResult); + } else if (arg.IsExcelRange) { + var r = arg.ValueAsRangeInfo; + for (int col = r.Address._fromCol; col <= r.Address._toCol; col++) { + for (int row = r.Address._fromRow; row <= r.Address._toRow; row++) { + AddValue(r.GetValue(row, col), currentResult); + } + } + } } + // Validate that all supplied lists have the same length + var arrayLength = results.First().Count; + foreach (var list in results) { + if (list.Count != arrayLength) { + throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); + //throw new ExcelFunctionException("All supplied arrays must have the same length", ExcelErrorCodes.Value); + } + } + for (var rowIndex = 0; rowIndex < arrayLength; rowIndex++) { + double rowResult = 1; + for (var colIndex = 0; colIndex < results.Count; colIndex++) { + rowResult *= results[colIndex][rowIndex]; + } + result += rowResult; + } + return CreateResult(result, DataType.Decimal); + } + + private void AddValue(object convertVal, List<double> currentResult) { + if (IsNumeric(convertVal)) { + currentResult.Add(Convert.ToDouble(convertVal)); + } else if (convertVal is ExcelErrorValue) { + throw (new ExcelErrorValueException((ExcelErrorValue)convertVal)); + } else { + currentResult.Add(0d); + } + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Sumsq.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Sumsq.cs index 2a4a077..9bb56d3 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Sumsq.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Sumsq.cs
@@ -1,69 +1,50 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Sumsq : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var retVal = 0d; - if (arguments != null) - { - foreach (var arg in arguments) - { - retVal += Calculate(arg, context); - } - } - return CreateResult(retVal, DataType.Decimal); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - - private double Calculate(FunctionArgument arg, ParsingContext context, bool isInArray = false) - { - var retVal = 0d; - if (ShouldIgnore(arg)) - { - return retVal; - } - if (arg.Value is IEnumerable<FunctionArgument>) - { - foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) - { - retVal += Calculate(item, context, true); - } - } - else - { - var cs = arg.Value as ExcelDataProvider.IRangeInfo; - if (cs != null) - { - foreach (var c in cs) - { - if (ShouldIgnore(c, context) == false) - { - CheckForAndHandleExcelError(c); - retVal += System.Math.Pow(c.ValueDouble, 2); - } - } - } - else - { - CheckForAndHandleExcelError(arg); - if (IsNumericString(arg.Value) && !isInArray) - { - var value = ConvertUtil.GetValueDouble(arg.Value); - return System.Math.Pow(value, 2); - } - var ignoreBool = isInArray; - retVal += System.Math.Pow(ConvertUtil.GetValueDouble(arg.Value, ignoreBool), 2); - } - } - return retVal; - } +public class Sumsq : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var retVal = 0d; + if (arguments != null) { + foreach (var arg in arguments) { + retVal += Calculate(arg, context); + } } + return CreateResult(retVal, DataType.Decimal); + } + + private double Calculate(FunctionArgument arg, ParsingContext context, bool isInArray = false) { + var retVal = 0d; + if (ShouldIgnore(arg)) { + return retVal; + } + if (arg.Value is IEnumerable<FunctionArgument>) { + foreach (var item in (IEnumerable<FunctionArgument>)arg.Value) { + retVal += Calculate(item, context, true); + } + } else { + var cs = arg.Value as ExcelDataProvider.IRangeInfo; + if (cs != null) { + foreach (var c in cs) { + if (ShouldIgnore(c, context) == false) { + CheckForAndHandleExcelError(c); + retVal += System.Math.Pow(c.ValueDouble, 2); + } + } + } else { + CheckForAndHandleExcelError(arg); + if (IsNumericString(arg.Value) && !isInArray) { + var value = ConvertUtil.GetValueDouble(arg.Value); + return System.Math.Pow(value, 2); + } + var ignoreBool = isInArray; + retVal += System.Math.Pow(ConvertUtil.GetValueDouble(arg.Value, ignoreBool), 2); + } + } + return retVal; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Tan.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Tan.cs index b15bab6..dd85652 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Tan.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Tan.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Tan : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Tan(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Tan : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Tan(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Tanh.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Tanh.cs index 6b2333b..e2e4f14 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Tanh.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Tanh.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Tanh : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var arg = ArgToDecimal(arguments, 0); - return CreateResult(System.Math.Tanh(arg), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Tanh : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var arg = ArgToDecimal(arguments, 0); + return CreateResult(System.Math.Tanh(arg), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Trunc.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Trunc.cs index fc21fea..3730382 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Trunc.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Trunc.cs
@@ -7,43 +7,39 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2014-01-06 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Trunc : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToDecimal(arguments, 0); - if (arguments.Count() == 1) - { - return CreateResult(System.Math.Truncate(number), DataType.Decimal); - } - var nDigits = ArgToInt(arguments, 1); - var func = context.Configuration.FunctionRepository.GetFunction("rounddown"); - return func.Execute(arguments, context); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Trunc : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToDecimal(arguments, 0); + if (arguments.Count() == 1) { + return CreateResult(System.Math.Truncate(number), DataType.Decimal); } + var nDigits = ArgToInt(arguments, 1); + var func = context.Configuration.FunctionRepository.GetFunction("rounddown"); + return func.Execute(arguments, context); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/Var.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/Var.cs index c18e7c5..b32b165 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/Var.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/Var.cs
@@ -7,37 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class Var : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); - return new CompileResult(VarMethods.Var(args), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class Var : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); + return new(VarMethods.Var(args), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs index e48dcb9..d12ddf8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/VarMethods.cs
@@ -7,52 +7,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-04-19 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - internal static class VarMethods - { - private static double Divide(double left, double right) - { - if (System.Math.Abs(right - 0d) < double.Epsilon) - { - throw new ExcelErrorValueException(eErrorType.Div0); - } - return left / right; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; - public static double Var(IEnumerable<double> args) - { - double avg = args.Average(); - double d = args.Aggregate(0.0, (total, next) => total += System.Math.Pow(next - avg, 2)); - return Divide(d, (args.Count() - 1)); - } - - public static double VarP(IEnumerable<double> args) - { - double avg = args.Average(); - double d = args.Aggregate(0.0, (total, next) => total += System.Math.Pow(next - avg, 2)); - return Divide(d, args.Count()); - } +internal static class VarMethods { + private static double Divide(double left, double right) { + if (System.Math.Abs(right - 0d) < double.Epsilon) { + throw new ExcelErrorValueException(eErrorType.Div0); } + return left / right; + } + + public static double Var(IEnumerable<double> args) { + double avg = args.Average(); + double d = args.Aggregate(0.0, (total, next) => total += System.Math.Pow(next - avg, 2)); + return Divide(d, (args.Count() - 1)); + } + + public static double VarP(IEnumerable<double> args) { + double avg = args.Average(); + double d = args.Aggregate(0.0, (total, next) => total += System.Math.Pow(next - avg, 2)); + return Divide(d, args.Count()); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Math/VarP.cs b/EPPlus/FormulaParsing/Excel/Functions/Math/VarP.cs index 159fe18..1afab92 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Math/VarP.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Math/VarP.cs
@@ -7,36 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math -{ - public class VarP : HiddenValuesHandlingFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); - return new CompileResult(VarMethods.VarP(args), DataType.Decimal); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Math; + +public class VarP : HiddenValuesHandlingFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var args = ArgsToDoubleEnumerable(IgnoreHiddenValues, false, arguments, context); + return new(VarMethods.VarP(args), DataType.Decimal); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Numeric/CInt.cs b/EPPlus/FormulaParsing/Excel/Functions/Numeric/CInt.cs index 1e6f6af..0482de8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Numeric/CInt.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Numeric/CInt.cs
@@ -7,37 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System.Globalization; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Numeric -{ - public class CInt : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var num = ArgToDecimal(arguments, 0); - return CreateResult((int)System.Math.Floor(num), DataType.Integer); - } - } +using System.Collections.Generic; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; + +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Numeric; + +public class CInt : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var num = ArgToDecimal(arguments, 0); + return CreateResult((int)System.Math.Floor(num), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs b/EPPlus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs index d6fc7ba..71c5252 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/ObjectEnumerableArgConverter.cs
@@ -7,52 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions -{ - public class ObjectEnumerableArgConverter : CollectionFlattener<object> - { - public virtual IEnumerable<object> ConvertArgs(bool ignoreHidden, IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - return base.FuncArgsToFlatEnumerable(arguments, (arg, argList) => - { - if (arg.Value is ExcelDataProvider.IRangeInfo) - { - foreach (var cell in (ExcelDataProvider.IRangeInfo)arg.Value) - { - if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context)) - { - argList.Add(cell.Value); - } - } - } - else - { - argList.Add(arg.Value); - } - }) - ; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions; - } - } +public class ObjectEnumerableArgConverter : CollectionFlattener<object> { + public virtual IEnumerable<object> ConvertArgs( + bool ignoreHidden, + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + return base.FuncArgsToFlatEnumerable( + arguments, + (arg, argList) => { + if (arg.Value is ExcelDataProvider.IRangeInfo) { + foreach (var cell in (ExcelDataProvider.IRangeInfo)arg.Value) { + if (!CellStateHelper.ShouldIgnore(ignoreHidden, cell, context)) { + argList.Add(cell.Value); + } + } + } else { + argList.Add(arg.Value); + } + }); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs index a80d4a5..3d75525 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Address.cs
@@ -7,65 +7,58 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using OfficeOpenXml.FormulaParsing.Exceptions; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Address : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var row = ArgToInt(arguments, 0); - var col = ArgToInt(arguments, 1); - ThrowExcelErrorValueExceptionIf(() => row < 0 && col < 0, eErrorType.Value); - var referenceType = ExcelReferenceType.AbsoluteRowAndColumn; - var worksheetSpec = string.Empty; - if (arguments.Count() > 2) - { - var arg3 = ArgToInt(arguments, 2); - ThrowExcelErrorValueExceptionIf(() => arg3 < 1 || arg3 > 4, eErrorType.Value); - referenceType = (ExcelReferenceType)ArgToInt(arguments, 2); - } - if (arguments.Count() > 3) - { - var fourthArg = arguments.ElementAt(3).Value; - if (fourthArg is bool && !(bool)fourthArg) - { - throw new InvalidOperationException("Excelformulaparser does not support the R1C1 format!"); - } - } - if (arguments.Count() > 4) - { - var fifthArg = arguments.ElementAt(4).Value; - if (fifthArg is string && !string.IsNullOrEmpty(fifthArg.ToString())) - { - worksheetSpec = fifthArg + "!"; - } - } - var translator = new IndexToAddressTranslator(context.ExcelDataProvider, referenceType); - return CreateResult(worksheetSpec + translator.ToAddress(col, row), DataType.ExcelAddress); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Address : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var row = ArgToInt(arguments, 0); + var col = ArgToInt(arguments, 1); + ThrowExcelErrorValueExceptionIf(() => row < 0 && col < 0, eErrorType.Value); + var referenceType = ExcelReferenceType.AbsoluteRowAndColumn; + var worksheetSpec = string.Empty; + if (arguments.Count() > 2) { + var arg3 = ArgToInt(arguments, 2); + ThrowExcelErrorValueExceptionIf(() => arg3 < 1 || arg3 > 4, eErrorType.Value); + referenceType = (ExcelReferenceType)ArgToInt(arguments, 2); } + if (arguments.Count() > 3) { + var fourthArg = arguments.ElementAt(3).Value; + if (fourthArg is bool && !(bool)fourthArg) { + throw new InvalidOperationException("Excelformulaparser does not support the R1C1 format!"); + } + } + if (arguments.Count() > 4) { + var fifthArg = arguments.ElementAt(4).Value; + if (fifthArg is string && !string.IsNullOrEmpty(fifthArg.ToString())) { + worksheetSpec = fifthArg + "!"; + } + } + var translator = new IndexToAddressTranslator(context.ExcelDataProvider, referenceType); + return CreateResult(worksheetSpec + translator.ToAddress(col, row), DataType.ExcelAddress); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs index fd9659d..e558462 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ArrayLookupNavigator.cs
@@ -1,78 +1,59 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Linq; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class ArrayLookupNavigator : LookupNavigator - { - private readonly FunctionArgument[] _arrayData; - private int _index = 0; - private object _currentValue; - - public ArrayLookupNavigator(LookupDirection direction, LookupArguments arguments, ParsingContext parsingContext) - : base(direction, arguments, parsingContext) - { - Require.That(arguments).Named("arguments").IsNotNull(); - Require.That(arguments.DataArray).Named("arguments.DataArray").IsNotNull(); - _arrayData = arguments.DataArray.ToArray(); - Initialize(); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; - private void Initialize() - { - if (Arguments.LookupIndex >= _arrayData.Length) - { - throw new ExcelErrorValueException(eErrorType.Ref); - } - SetCurrentValue(); +public class ArrayLookupNavigator : LookupNavigator { + private readonly FunctionArgument[] _arrayData; + private int _index; + private object _currentValue; - } + public ArrayLookupNavigator( + LookupDirection direction, + LookupArguments arguments, + ParsingContext parsingContext) + : base(direction, arguments, parsingContext) { + Require.That(arguments).Named("arguments").IsNotNull(); + Require.That(arguments.DataArray).Named("arguments.DataArray").IsNotNull(); + _arrayData = arguments.DataArray.ToArray(); + Initialize(); + } - public override int Index - { - get { return _index; } - } - - private void SetCurrentValue() - { - _currentValue = _arrayData[_index]; - } - - private bool HasNext() - { - if (Direction == LookupDirection.Vertical) - { - return _index < (_arrayData.Length - 1); - } - else - { - return false; - } - } - - public override bool MoveNext() - { - if (!HasNext()) return false; - if (Direction == LookupDirection.Vertical) - { - _index++; - } - SetCurrentValue(); - return true; - } - - public override object CurrentValue - { - get { return _arrayData[_index].Value; } - } - - public override object GetLookupValue() - { - return _arrayData[_index].Value; - } + private void Initialize() { + if (Arguments.LookupIndex >= _arrayData.Length) { + throw new ExcelErrorValueException(eErrorType.Ref); } + SetCurrentValue(); + } + + public override int Index => _index; + + private void SetCurrentValue() { + _currentValue = _arrayData[_index]; + } + + private bool HasNext() { + if (Direction == LookupDirection.Vertical) { + return _index < (_arrayData.Length - 1); + } + return false; + } + + public override bool MoveNext() { + if (!HasNext()) { + return false; + } + if (Direction == LookupDirection.Vertical) { + _index++; + } + SetCurrentValue(); + return true; + } + + public override object CurrentValue => _arrayData[_index].Value; + + public override object GetLookupValue() { + return _arrayData[_index].Value; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs index 491c6c6..599467b 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Choose.cs
@@ -7,41 +7,38 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Choose : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var index = ArgToInt(arguments, 0); - var items = new List<string>(); - for (int x = 0; x < arguments.Count(); x++) - { - items.Add(arguments.ElementAt(x).ValueFirst.ToString()); - } - return CreateResult(items[index], DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Choose : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var index = ArgToInt(arguments, 0); + var items = new List<string>(); + for (int x = 0; x < arguments.Count(); x++) { + items.Add(arguments.ElementAt(x).ValueFirst.ToString()); } + return CreateResult(items[index], DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs index 38e9360..c2b4366 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Column.cs
@@ -7,46 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.FormulaParsing.ExcelUtilities; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Column : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - if (arguments == null || arguments.Count() == 0) - { - return CreateResult(context.Scopes.Current.Address.FromCol, DataType.Integer); - } - var rangeAddress = ArgToString(arguments, 0); - if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) - throw new ArgumentException("An invalid argument was supplied"); - var factory = new RangeAddressFactory(context.ExcelDataProvider); - var address = factory.Create(rangeAddress); - return CreateResult(address.FromCol, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Column : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + if (arguments == null || arguments.Count() == 0) { + return CreateResult(context.Scopes.Current.Address.FromCol, DataType.Integer); } + var rangeAddress = ArgToString(arguments, 0); + if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) { + throw new ArgumentException("An invalid argument was supplied"); + } + var factory = new RangeAddressFactory(context.ExcelDataProvider); + var address = factory.Create(rangeAddress); + return CreateResult(address.FromCol, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs index d7eff8a..27864bb 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Columns.cs
@@ -7,53 +7,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Utilities; -using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.ExcelUtilities; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Columns : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var r=arguments.ElementAt(0).ValueAsRangeInfo; - if (r != null) - { - return CreateResult(r.Address._toCol - r.Address._fromCol + 1, DataType.Integer); - } - else - { - var range = ArgToString(arguments, 0); - if (ExcelAddressUtil.IsValidAddress(range)) - { - var factory = new RangeAddressFactory(context.ExcelDataProvider); - var address = factory.Create(range); - return CreateResult(address.ToCol - address.FromCol + 1, DataType.Integer); - } - } - throw new ArgumentException("Invalid range supplied"); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Columns : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var r = arguments.ElementAt(0).ValueAsRangeInfo; + if (r != null) { + return CreateResult(r.Address._toCol - r.Address._fromCol + 1, DataType.Integer); } + var range = ArgToString(arguments, 0); + if (ExcelAddressUtil.IsValidAddress(range)) { + var factory = new RangeAddressFactory(context.ExcelDataProvider); + var address = factory.Create(range); + return CreateResult(address.ToCol - address.FromCol + 1, DataType.Integer); + } + throw new ArgumentException("Invalid range supplied"); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs index 36a5ea5..124fb3e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/ExcelLookupNavigator.cs
@@ -7,119 +7,100 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Utilities; + using OfficeOpenXml.FormulaParsing.ExcelUtilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class ExcelLookupNavigator : LookupNavigator - { - private int _currentRow; - private int _currentCol; - private object _currentValue; - private RangeAddress _rangeAddress; - private int _index; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; - public ExcelLookupNavigator(LookupDirection direction, LookupArguments arguments, ParsingContext parsingContext) - : base(direction, arguments, parsingContext) - { - Initialize(); - } +public class ExcelLookupNavigator : LookupNavigator { + private int _currentRow; + private int _currentCol; + private object _currentValue; + private RangeAddress _rangeAddress; + private int _index; - private void Initialize() - { - _index = 0; - var factory = new RangeAddressFactory(ParsingContext.ExcelDataProvider); - if (Arguments.RangeInfo == null) - { - _rangeAddress = factory.Create(ParsingContext.Scopes.Current.Address.Worksheet, Arguments.RangeAddress); - } - else - { - _rangeAddress = factory.Create(Arguments.RangeInfo.Address.WorkSheet, Arguments.RangeInfo.Address.Address); - } - _currentCol = _rangeAddress.FromCol; - _currentRow = _rangeAddress.FromRow; - SetCurrentValue(); - } + public ExcelLookupNavigator( + LookupDirection direction, + LookupArguments arguments, + ParsingContext parsingContext) + : base(direction, arguments, parsingContext) { + Initialize(); + } - private void SetCurrentValue() - { - _currentValue = ParsingContext.ExcelDataProvider.GetCellValue(_rangeAddress.Worksheet, _currentRow, _currentCol); - } - - private bool HasNext() - { - if (Direction == LookupDirection.Vertical) - { - return _currentRow < _rangeAddress.ToRow; - } - else - { - return _currentCol < _rangeAddress.ToCol; - } - } - - public override int Index - { - get { return _index; } - } - - public override bool MoveNext() - { - if (!HasNext()) return false; - if (Direction == LookupDirection.Vertical) - { - _currentRow++; - } - else - { - _currentCol++; - } - _index++; - SetCurrentValue(); - return true; - } - - public override object CurrentValue - { - get { return _currentValue; } - } - - public override object GetLookupValue() - { - var row = _currentRow; - var col = _currentCol; - if (Direction == LookupDirection.Vertical) - { - col += Arguments.LookupIndex - 1; - row += Arguments.LookupOffset; - } - else - { - row += Arguments.LookupIndex - 1; - col += Arguments.LookupOffset; - } - return ParsingContext.ExcelDataProvider.GetCellValue(_rangeAddress.Worksheet, row, col); - } + private void Initialize() { + _index = 0; + var factory = new RangeAddressFactory(ParsingContext.ExcelDataProvider); + if (Arguments.RangeInfo == null) { + _rangeAddress = factory.Create( + ParsingContext.Scopes.Current.Address.Worksheet, + Arguments.RangeAddress); + } else { + _rangeAddress = factory.Create( + Arguments.RangeInfo.Address.WorkSheet, + Arguments.RangeInfo.Address.Address); } + _currentCol = _rangeAddress.FromCol; + _currentRow = _rangeAddress.FromRow; + SetCurrentValue(); + } + + private void SetCurrentValue() { + _currentValue = ParsingContext.ExcelDataProvider.GetCellValue( + _rangeAddress.Worksheet, + _currentRow, + _currentCol); + } + + private bool HasNext() { + if (Direction == LookupDirection.Vertical) { + return _currentRow < _rangeAddress.ToRow; + } + return _currentCol < _rangeAddress.ToCol; + } + + public override int Index => _index; + + public override bool MoveNext() { + if (!HasNext()) { + return false; + } + if (Direction == LookupDirection.Vertical) { + _currentRow++; + } else { + _currentCol++; + } + _index++; + SetCurrentValue(); + return true; + } + + public override object CurrentValue => _currentValue; + + public override object GetLookupValue() { + var row = _currentRow; + var col = _currentCol; + if (Direction == LookupDirection.Vertical) { + col += Arguments.LookupIndex - 1; + row += Arguments.LookupOffset; + } else { + row += Arguments.LookupIndex - 1; + col += Arguments.LookupOffset; + } + return ParsingContext.ExcelDataProvider.GetCellValue(_rangeAddress.Worksheet, row, col); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs index 0dc39b8..a2ec6a3 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/HLookup.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,39 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class HLookup : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var lookupArgs = new LookupArguments(arguments); - ThrowExcelErrorValueExceptionIf(() => lookupArgs.LookupIndex < 1, eErrorType.Value); - var navigator = LookupNavigatorFactory.Create(LookupDirection.Horizontal, lookupArgs, context); - return Lookup(navigator, lookupArgs); - } - } +using System.Collections.Generic; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; + +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class HLookup : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var lookupArgs = new LookupArguments(arguments); + ThrowExcelErrorValueExceptionIf(() => lookupArgs.LookupIndex < 1, eErrorType.Value); + var navigator = LookupNavigatorFactory.Create(LookupDirection.Horizontal, lookupArgs, context); + return Lookup(navigator, lookupArgs); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs index 4d97611..7c8431d 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Index.cs
@@ -1,56 +1,49 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Index : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var arg1 = arguments.ElementAt(0); - var args = arg1.Value as IEnumerable<FunctionArgument>; - var crf = new CompileResultFactory(); - if (args != null) - { - var index = ArgToInt(arguments, 1); - if (index > args.Count()) - { - throw new ExcelErrorValueException(eErrorType.Ref); - } - var candidate = args.ElementAt(index - 1); - //Commented JK-Can be any data type - //if (!IsNumber(candidate.Value)) - //{ - // throw new ExcelErrorValueException(eErrorType.Value); - //} - //return CreateResult(ConvertUtil.GetValueDouble(candidate.Value), DataType.Decimal); - return crf.Create(candidate.Value); - } - if (arg1.IsExcelRange) - { - var row = ArgToInt(arguments, 1); - var col = arguments.Count()>2 ? ArgToInt(arguments, 2) : 1; - var ri=arg1.ValueAsRangeInfo; - if (row > ri.Address._toRow - ri.Address._fromRow + 1 || - col > ri.Address._toCol - ri.Address._fromCol + 1) - { - ThrowExcelErrorValueException(eErrorType.Ref); - } - var candidate = ri.GetOffset(row-1, col-1); - //Commented JK-Can be any data type - //if (!IsNumber(candidate.Value)) - //{ - // throw new ExcelErrorValueException(eErrorType.Value); - //} - return crf.Create(candidate); - } - throw new NotImplementedException(); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Index : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var arg1 = arguments.ElementAt(0); + var args = arg1.Value as IEnumerable<FunctionArgument>; + var crf = new CompileResultFactory(); + if (args != null) { + var index = ArgToInt(arguments, 1); + if (index > args.Count()) { + throw new ExcelErrorValueException(eErrorType.Ref); + } + var candidate = args.ElementAt(index - 1); + //Commented JK-Can be any data type + //if (!IsNumber(candidate.Value)) + //{ + // throw new ExcelErrorValueException(eErrorType.Value); + //} + //return CreateResult(ConvertUtil.GetValueDouble(candidate.Value), DataType.Decimal); + return crf.Create(candidate.Value); } + if (arg1.IsExcelRange) { + var row = ArgToInt(arguments, 1); + var col = arguments.Count() > 2 ? ArgToInt(arguments, 2) : 1; + var ri = arg1.ValueAsRangeInfo; + if (row > ri.Address._toRow - ri.Address._fromRow + 1 + || col > ri.Address._toCol - ri.Address._fromCol + 1) { + ThrowExcelErrorValueException(eErrorType.Ref); + } + var candidate = ri.GetOffset(row - 1, col - 1); + //Commented JK-Can be any data type + //if (!IsNumber(candidate.Value)) + //{ + // throw new ExcelErrorValueException(eErrorType.Value); + //} + return crf.Create(candidate); + } + throw new NotImplementedException(); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs index af85a06..ae80178 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Indirect.cs
@@ -7,49 +7,44 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2014-04-13 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Indirect : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var address = ArgToString(arguments, 0); - var adr = new ExcelAddress(address); - var ws = adr.WorkSheet; - if (string.IsNullOrEmpty(ws)) - { - ws = context.Scopes.Current.Address.Worksheet; - } - var result = context.ExcelDataProvider.GetRange(ws, adr._fromRow, adr._fromCol, address); - if (result.IsEmpty) - { - // Bug 15290 - var namedValueExpr = new NamedValueExpression(address, context); - return namedValueExpr.Compile(); - } - return new CompileResult(result, DataType.Enumerable); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Indirect : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var address = ArgToString(arguments, 0); + var adr = new ExcelAddress(address); + var ws = adr.WorkSheet; + if (string.IsNullOrEmpty(ws)) { + ws = context.Scopes.Current.Address.Worksheet; } + var result = context.ExcelDataProvider.GetRange(ws, adr._fromRow, adr._fromCol, address); + if (result.IsEmpty) { + // Bug 15290 + var namedValueExpr = new NamedValueExpression(address, context); + return namedValueExpr.Compile(); + } + return new(result, DataType.Enumerable); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs index 87cf319..8fee752 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Lookup.cs
@@ -7,92 +7,94 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; +using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.Utilities; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using System.Text.RegularExpressions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Lookup : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - if (HaveTwoRanges(arguments)) - { - return HandleTwoRanges(arguments, context); - } - return HandleSingleRange(arguments, context); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; - private bool HaveTwoRanges(IEnumerable<FunctionArgument> arguments) - { - if (arguments.Count() == 2) return false; - return (ExcelAddressUtil.IsValidAddress(arguments.ElementAt(2).Value.ToString())); - } - - private CompileResult HandleSingleRange(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var searchedValue = arguments.ElementAt(0).Value; - Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull(); - var firstAddress = ArgToString(arguments, 1); - var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider); - var address = rangeAddressFactory.Create(firstAddress); - var nRows = address.ToRow - address.FromRow; - var nCols = address.ToCol - address.FromCol; - var lookupIndex = nCols + 1; - var lookupDirection = LookupDirection.Vertical; - if (nCols > nRows) - { - lookupIndex = nRows + 1; - lookupDirection = LookupDirection.Horizontal; - } - var lookupArgs = new LookupArguments(searchedValue, firstAddress, lookupIndex, 0, true); - var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context); - return Lookup(navigator, lookupArgs); - } - - private CompileResult HandleTwoRanges(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var searchedValue = arguments.ElementAt(0).Value; - Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull(); - Require.That(arguments.ElementAt(2).Value).Named("secondAddress").IsNotNull(); - var firstAddress = ArgToString(arguments, 1); - var secondAddress = ArgToString(arguments, 2); - var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider); - var address1 = rangeAddressFactory.Create(firstAddress); - var address2 = rangeAddressFactory.Create(secondAddress); - var lookupIndex = (address2.FromCol - address1.FromCol) + 1; - var lookupOffset = address2.FromRow - address1.FromRow; - var lookupDirection = GetLookupDirection(address1); - if (lookupDirection == LookupDirection.Horizontal) - { - lookupIndex = (address2.FromRow - address1.FromRow) + 1; - lookupOffset = address2.FromCol - address1.FromCol; - } - var lookupArgs = new LookupArguments(searchedValue, firstAddress, lookupIndex, lookupOffset, true); - var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context); - return Lookup(navigator, lookupArgs); - } +public class Lookup : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + if (HaveTwoRanges(arguments)) { + return HandleTwoRanges(arguments, context); } + return HandleSingleRange(arguments, context); + } + + private bool HaveTwoRanges(IEnumerable<FunctionArgument> arguments) { + if (arguments.Count() == 2) { + return false; + } + return (ExcelAddressUtil.IsValidAddress(arguments.ElementAt(2).Value.ToString())); + } + + private CompileResult HandleSingleRange( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var searchedValue = arguments.ElementAt(0).Value; + Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull(); + var firstAddress = ArgToString(arguments, 1); + var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider); + var address = rangeAddressFactory.Create(firstAddress); + var nRows = address.ToRow - address.FromRow; + var nCols = address.ToCol - address.FromCol; + var lookupIndex = nCols + 1; + var lookupDirection = LookupDirection.Vertical; + if (nCols > nRows) { + lookupIndex = nRows + 1; + lookupDirection = LookupDirection.Horizontal; + } + var lookupArgs = new LookupArguments(searchedValue, firstAddress, lookupIndex, 0, true); + var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context); + return Lookup(navigator, lookupArgs); + } + + private CompileResult HandleTwoRanges( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var searchedValue = arguments.ElementAt(0).Value; + Require.That(arguments.ElementAt(1).Value).Named("firstAddress").IsNotNull(); + Require.That(arguments.ElementAt(2).Value).Named("secondAddress").IsNotNull(); + var firstAddress = ArgToString(arguments, 1); + var secondAddress = ArgToString(arguments, 2); + var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider); + var address1 = rangeAddressFactory.Create(firstAddress); + var address2 = rangeAddressFactory.Create(secondAddress); + var lookupIndex = (address2.FromCol - address1.FromCol) + 1; + var lookupOffset = address2.FromRow - address1.FromRow; + var lookupDirection = GetLookupDirection(address1); + if (lookupDirection == LookupDirection.Horizontal) { + lookupIndex = (address2.FromRow - address1.FromRow) + 1; + lookupOffset = address2.FromCol - address1.FromCol; + } + var lookupArgs = new LookupArguments( + searchedValue, + firstAddress, + lookupIndex, + lookupOffset, + true); + var navigator = LookupNavigatorFactory.Create(lookupDirection, lookupArgs, context); + return Lookup(navigator, lookupArgs); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs index 846045f..8bed82d 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupArguments.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,106 +7,97 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class LookupArguments - { - public enum LookupArgumentDataType - { - ExcelRange, - DataArray - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; - public LookupArguments(IEnumerable<FunctionArgument> arguments) - : this(arguments, new ArgumentParsers()) - { +public class LookupArguments { + public enum LookupArgumentDataType { + ExcelRange, + DataArray, + } - } + public LookupArguments(IEnumerable<FunctionArgument> arguments) + : this(arguments, new()) {} - public LookupArguments(IEnumerable<FunctionArgument> arguments, ArgumentParsers argumentParsers) - { - _argumentParsers = argumentParsers; - SearchedValue = arguments.ElementAt(0).Value; - var arg1 = arguments.ElementAt(1).Value; - var dataArray = arg1 as IEnumerable<FunctionArgument>; - if (dataArray != null) - { - DataArray = dataArray; - ArgumentDataType = LookupArgumentDataType.DataArray; - } - else - { - //if (arg1 is ExcelDataProvider.INameInfo) arg1 = ((ExcelDataProvider.INameInfo) arg1).Value; - var rangeInfo = arg1 as ExcelDataProvider.IRangeInfo; - if (rangeInfo != null) - { - RangeAddress = string.IsNullOrEmpty(rangeInfo.Address.WorkSheet) ? rangeInfo.Address.Address : "'" + rangeInfo.Address.WorkSheet + "'!" + rangeInfo.Address.Address; - RangeInfo = rangeInfo; - ArgumentDataType = LookupArgumentDataType.ExcelRange; - } - else - { - RangeAddress = arg1.ToString(); - ArgumentDataType = LookupArgumentDataType.ExcelRange; - } - } - LookupIndex = (int)_argumentParsers.GetParser(DataType.Integer).Parse(arguments.ElementAt(2).Value); - if (arguments.Count() > 3) - { - RangeLookup = (bool)_argumentParsers.GetParser(DataType.Boolean).Parse(arguments.ElementAt(3).Value); - } - else - { - RangeLookup = true; - } - } - - public LookupArguments(object searchedValue, string rangeAddress, int lookupIndex, int lookupOffset, bool rangeLookup) - { - SearchedValue = searchedValue; - RangeAddress = rangeAddress; - LookupIndex = lookupIndex; - LookupOffset = lookupOffset; - RangeLookup = rangeLookup; - } - - private readonly ArgumentParsers _argumentParsers; - - public object SearchedValue { get; private set; } - - public string RangeAddress { get; private set; } - - public int LookupIndex { get; private set; } - - public int LookupOffset { get; private set; } - - public bool RangeLookup { get; private set; } - - public IEnumerable<FunctionArgument> DataArray { get; private set; } - - public ExcelDataProvider.IRangeInfo RangeInfo { get; private set; } - - public LookupArgumentDataType ArgumentDataType { get; private set; } + public LookupArguments(IEnumerable<FunctionArgument> arguments, ArgumentParsers argumentParsers) { + _argumentParsers = argumentParsers; + SearchedValue = arguments.ElementAt(0).Value; + var arg1 = arguments.ElementAt(1).Value; + var dataArray = arg1 as IEnumerable<FunctionArgument>; + if (dataArray != null) { + DataArray = dataArray; + ArgumentDataType = LookupArgumentDataType.DataArray; + } else { + //if (arg1 is ExcelDataProvider.INameInfo) arg1 = ((ExcelDataProvider.INameInfo) arg1).Value; + var rangeInfo = arg1 as ExcelDataProvider.IRangeInfo; + if (rangeInfo != null) { + RangeAddress = string.IsNullOrEmpty(rangeInfo.Address.WorkSheet) + ? rangeInfo.Address.Address + : "'" + rangeInfo.Address.WorkSheet + "'!" + rangeInfo.Address.Address; + RangeInfo = rangeInfo; + ArgumentDataType = LookupArgumentDataType.ExcelRange; + } else { + RangeAddress = arg1.ToString(); + ArgumentDataType = LookupArgumentDataType.ExcelRange; + } } + LookupIndex = (int) + _argumentParsers.GetParser(DataType.Integer).Parse(arguments.ElementAt(2).Value); + if (arguments.Count() > 3) { + RangeLookup = (bool) + _argumentParsers.GetParser(DataType.Boolean).Parse(arguments.ElementAt(3).Value); + } else { + RangeLookup = true; + } + } + + public LookupArguments( + object searchedValue, + string rangeAddress, + int lookupIndex, + int lookupOffset, + bool rangeLookup) { + SearchedValue = searchedValue; + RangeAddress = rangeAddress; + LookupIndex = lookupIndex; + LookupOffset = lookupOffset; + RangeLookup = rangeLookup; + } + + private readonly ArgumentParsers _argumentParsers; + + public object SearchedValue { get; private set; } + + public string RangeAddress { get; private set; } + + public int LookupIndex { get; private set; } + + public int LookupOffset { get; private set; } + + public bool RangeLookup { get; private set; } + + public IEnumerable<FunctionArgument> DataArray { get; private set; } + + public ExcelDataProvider.IRangeInfo RangeInfo { get; private set; } + + public LookupArgumentDataType ArgumentDataType { get; private set; } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs index ee5a7d6..abb564c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupDirection.cs
@@ -7,31 +7,25 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public enum LookupDirection - { - Vertical, - Horizontal - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public enum LookupDirection { + Vertical, + Horizontal, }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs index 800d553..84f20d8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupFunction.cs
@@ -7,111 +7,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public abstract class LookupFunction : ExcelFunction - { - private readonly ValueMatcher _valueMatcher; - private readonly CompileResultFactory _compileResultFactory; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; - public LookupFunction() - : this(new LookupValueMatcher(), new CompileResultFactory()) - { +public abstract class LookupFunction : ExcelFunction { + private readonly ValueMatcher _valueMatcher; + private readonly CompileResultFactory _compileResultFactory; - } + public LookupFunction() + : this(new LookupValueMatcher(), new()) {} - public LookupFunction(ValueMatcher valueMatcher, CompileResultFactory compileResultFactory) - { - _valueMatcher = valueMatcher; - _compileResultFactory = compileResultFactory; - } + public LookupFunction(ValueMatcher valueMatcher, CompileResultFactory compileResultFactory) { + _valueMatcher = valueMatcher; + _compileResultFactory = compileResultFactory; + } - public override bool IsLookupFuction - { - get - { - return true; - } - } + public override bool IsLookupFuction => true; - protected int IsMatch(object o1, object o2) - { - return _valueMatcher.IsMatch(o1, o2); - } + protected int IsMatch(object o1, object o2) { + return _valueMatcher.IsMatch(o1, o2); + } - protected LookupDirection GetLookupDirection(RangeAddress rangeAddress) - { - var nRows = rangeAddress.ToRow - rangeAddress.FromRow; - var nCols = rangeAddress.ToCol - rangeAddress.FromCol; - return nCols > nRows ? LookupDirection.Horizontal : LookupDirection.Vertical; - } + protected LookupDirection GetLookupDirection(RangeAddress rangeAddress) { + var nRows = rangeAddress.ToRow - rangeAddress.FromRow; + var nCols = rangeAddress.ToCol - rangeAddress.FromCol; + return nCols > nRows ? LookupDirection.Horizontal : LookupDirection.Vertical; + } - protected CompileResult Lookup(LookupNavigator navigator, LookupArguments lookupArgs) - { - object lastValue = null; - object lastLookupValue = null; - int? lastMatchResult = null; - if (lookupArgs.SearchedValue == null) - { - return new CompileResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); - } - do - { - var matchResult = IsMatch(navigator.CurrentValue, lookupArgs.SearchedValue); - if (matchResult != 0) - { - if (lastValue != null && navigator.CurrentValue == null) break; - - if (lookupArgs.RangeLookup) - { - if (lastValue == null && matchResult > 0) - { - ThrowExcelErrorValueException(eErrorType.NA); - } - if (lastValue != null && matchResult > 0 && lastMatchResult < 0) - { - return _compileResultFactory.Create(lastLookupValue); - } - lastMatchResult = matchResult; - lastValue = navigator.CurrentValue; - lastLookupValue = navigator.GetLookupValue(); - } - } - else - { - return _compileResultFactory.Create(navigator.GetLookupValue()); - } - } - while (navigator.MoveNext()); - - if (lookupArgs.RangeLookup) - { - return _compileResultFactory.Create(lastLookupValue); - } - return new CompileResult(ExcelErrorValue.Create(eErrorType.NA), DataType.ExcelError); - } + protected CompileResult Lookup(LookupNavigator navigator, LookupArguments lookupArgs) { + object lastValue = null; + object lastLookupValue = null; + int? lastMatchResult = null; + if (lookupArgs.SearchedValue == null) { + return new(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError); } + do { + var matchResult = IsMatch(navigator.CurrentValue, lookupArgs.SearchedValue); + if (matchResult != 0) { + if (lastValue != null && navigator.CurrentValue == null) { + break; + } + + if (lookupArgs.RangeLookup) { + if (lastValue == null && matchResult > 0) { + ThrowExcelErrorValueException(eErrorType.Na); + } + if (lastValue != null && matchResult > 0 && lastMatchResult < 0) { + return _compileResultFactory.Create(lastLookupValue); + } + lastMatchResult = matchResult; + lastValue = navigator.CurrentValue; + lastLookupValue = navigator.GetLookupValue(); + } + } else { + return _compileResultFactory.Create(navigator.GetLookupValue()); + } + } while (navigator.MoveNext()); + + if (lookupArgs.RangeLookup) { + return _compileResultFactory.Create(lastLookupValue); + } + return new(ExcelErrorValue.Create(eErrorType.Na), DataType.ExcelError); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs index 8ef23d5..f93cfbe 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigator.cs
@@ -7,60 +7,51 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.Utilities; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public abstract class LookupNavigator - { - protected readonly LookupDirection Direction; - protected readonly LookupArguments Arguments; - protected readonly ParsingContext ParsingContext; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; +public abstract class LookupNavigator { + protected readonly LookupDirection Direction; + protected readonly LookupArguments Arguments; + protected readonly ParsingContext ParsingContext; + public LookupNavigator( + LookupDirection direction, + LookupArguments arguments, + ParsingContext parsingContext) { + Require.That(arguments).Named("arguments").IsNotNull(); + Require.That(parsingContext).Named("parsingContext").IsNotNull(); + Require + .That(parsingContext.ExcelDataProvider) + .Named("parsingContext.ExcelDataProvider") + .IsNotNull(); + Direction = direction; + Arguments = arguments; + ParsingContext = parsingContext; + } - public LookupNavigator(LookupDirection direction, LookupArguments arguments, ParsingContext parsingContext) - { - Require.That(arguments).Named("arguments").IsNotNull(); - Require.That(parsingContext).Named("parsingContext").IsNotNull(); - Require.That(parsingContext.ExcelDataProvider).Named("parsingContext.ExcelDataProvider").IsNotNull(); - Direction = direction; - Arguments = arguments; - ParsingContext = parsingContext; - } + public abstract int Index { get; } - public abstract int Index - { - get; - } + public abstract bool MoveNext(); - public abstract bool MoveNext(); + public abstract object CurrentValue { get; } - public abstract object CurrentValue - { - get; - } - - public abstract object GetLookupValue(); - } + public abstract object GetLookupValue(); }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs index 2a68900..d444525 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/LookupNavigatorFactory.cs
@@ -1,23 +1,18 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public static class LookupNavigatorFactory - { - public static LookupNavigator Create(LookupDirection direction, LookupArguments args, ParsingContext parsingContext) - { - if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.ExcelRange) - { - return new ExcelLookupNavigator(direction, args, parsingContext); - } - else if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.DataArray) - { - return new ArrayLookupNavigator(direction, args, parsingContext); - } - throw new NotSupportedException("Invalid argument datatype"); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public static class LookupNavigatorFactory { + public static LookupNavigator Create( + LookupDirection direction, + LookupArguments args, + ParsingContext parsingContext) { + if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.ExcelRange) { + return new ExcelLookupNavigator(direction, args, parsingContext); } + if (args.ArgumentDataType == LookupArguments.LookupArgumentDataType.DataArray) { + return new ArrayLookupNavigator(direction, args, parsingContext); + } + throw new NotSupportedException("Invalid argument datatype"); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Match.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Match.cs index a37218e..36f24fc 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Match.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Match.cs
@@ -7,99 +7,84 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; using OfficeOpenXml.FormulaParsing.ExcelUtilities; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Match : LookupFunction - { - private enum MatchType - { - ClosestAbove = -1, - ExactMatch = 0, - ClosestBelow = 1 +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Match : LookupFunction { + private enum MatchType { + ClosestAbove = -1, + ExactMatch = 0, + ClosestBelow = 1, + } + + public Match() + : base(new WildCardValueMatcher(), new()) {} + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + + var searchedValue = arguments.ElementAt(0).Value; + var address = ArgToString(arguments, 1); + var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider); + var rangeAddress = rangeAddressFactory.Create(address); + var matchType = GetMatchType(arguments); + var args = new LookupArguments(searchedValue, address, 0, 0, false); + var lookupDirection = GetLookupDirection(rangeAddress); + var navigator = LookupNavigatorFactory.Create(lookupDirection, args, context); + int? lastMatchResult = default(int?); + do { + var matchResult = IsMatch(navigator.CurrentValue, searchedValue); + if (matchType == MatchType.ClosestBelow && matchResult >= 0) { + if (!lastMatchResult.HasValue && matchResult > 0) { + // TODO: error handling. This happens only if the first item is + // below the searched value. } - - public Match() - : base(new WildCardValueMatcher(), new CompileResultFactory()) - { - + var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index; + return CreateResult(index, DataType.Integer); + } + if (matchType == MatchType.ClosestAbove && matchResult <= 0) { + if (!lastMatchResult.HasValue && matchResult < 0) { + // TODO: error handling. This happens only if the first item is + // above the searched value } + var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index; + return CreateResult(index, DataType.Integer); + } + if (matchType == MatchType.ExactMatch && matchResult == 0) { + return CreateResult(navigator.Index + 1, DataType.Integer); + } + lastMatchResult = matchResult; + } while (navigator.MoveNext()); + return CreateResult(null, DataType.Integer); + } - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - - var searchedValue = arguments.ElementAt(0).Value; - var address = ArgToString(arguments, 1); - var rangeAddressFactory = new RangeAddressFactory(context.ExcelDataProvider); - var rangeAddress = rangeAddressFactory.Create(address); - var matchType = GetMatchType(arguments); - var args = new LookupArguments(searchedValue, address, 0, 0, false); - var lookupDirection = GetLookupDirection(rangeAddress); - var navigator = LookupNavigatorFactory.Create(lookupDirection, args, context); - int? lastMatchResult = default(int?); - do - { - var matchResult = IsMatch(navigator.CurrentValue, searchedValue); - if (matchType == MatchType.ClosestBelow && matchResult >= 0) - { - if (!lastMatchResult.HasValue && matchResult > 0) - { - // TODO: error handling. This happens only if the first item is - // below the searched value. - } - var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index; - return CreateResult(index, DataType.Integer); - } - if (matchType == MatchType.ClosestAbove && matchResult <= 0) - { - if (!lastMatchResult.HasValue && matchResult < 0) - { - // TODO: error handling. This happens only if the first item is - // above the searched value - } - var index = matchResult == 0 ? navigator.Index + 1 : navigator.Index; - return CreateResult(index, DataType.Integer); - } - if (matchType == MatchType.ExactMatch && matchResult == 0) - { - return CreateResult(navigator.Index + 1, DataType.Integer); - } - lastMatchResult = matchResult; - } - while (navigator.MoveNext()); - return CreateResult(null, DataType.Integer); - } - - private MatchType GetMatchType(IEnumerable<FunctionArgument> arguments) - { - var matchType = MatchType.ClosestBelow; - if (arguments.Count() > 2) - { - matchType = (MatchType)ArgToInt(arguments, 2); - } - return matchType; - } + private MatchType GetMatchType(IEnumerable<FunctionArgument> arguments) { + var matchType = MatchType.ClosestBelow; + if (arguments.Count() > 2) { + matchType = (MatchType)ArgToInt(arguments, 2); } + return matchType; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs index 216f79e..8a16080 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Offset.cs
@@ -7,74 +7,70 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-11 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Offset : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 3); - var startRange = ArgToString(functionArguments, 0); - var rowOffset = ArgToInt(functionArguments, 1); - var colOffset = ArgToInt(functionArguments, 2); - int width = 0, height = 0; - if (functionArguments.Length > 3) - { - height = ArgToInt(functionArguments, 3); - ThrowExcelErrorValueExceptionIf(() => height == 0, eErrorType.Ref); - } - if (functionArguments.Length > 4) - { - width = ArgToInt(functionArguments, 4); - ThrowExcelErrorValueExceptionIf(() => width == 0, eErrorType.Ref); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; - var adr = new ExcelAddress(startRange); - var ws = adr.WorkSheet; - - var fromRow = adr._fromRow + rowOffset; - var fromCol = adr._fromCol + colOffset; - var toRow = (height != 0 ? height : adr._toRow) + rowOffset; - var toCol = (width != 0 ? width : adr._toCol) + colOffset; - - var newRange = context.ExcelDataProvider.GetRange(ws, fromRow, fromCol, toRow, toCol); - if (!newRange.IsMulti) - { - if (newRange.IsEmpty) return CompileResult.Empty; - var val = newRange.GetValue(fromRow, fromCol); - if (IsNumeric(val)) - { - return CreateResult(val, DataType.Decimal); - } - if (val is ExcelErrorValue) - { - return CreateResult(val, DataType.ExcelError); - } - return CreateResult(val, DataType.String); - } - return CreateResult(newRange, DataType.Enumerable); - } +public class Offset : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 3); + var startRange = ArgToString(functionArguments, 0); + var rowOffset = ArgToInt(functionArguments, 1); + var colOffset = ArgToInt(functionArguments, 2); + int width = 0, + height = 0; + if (functionArguments.Length > 3) { + height = ArgToInt(functionArguments, 3); + ThrowExcelErrorValueExceptionIf(() => height == 0, eErrorType.Ref); } + if (functionArguments.Length > 4) { + width = ArgToInt(functionArguments, 4); + ThrowExcelErrorValueExceptionIf(() => width == 0, eErrorType.Ref); + } + + var adr = new ExcelAddress(startRange); + var ws = adr.WorkSheet; + + var fromRow = adr._fromRow + rowOffset; + var fromCol = adr._fromCol + colOffset; + var toRow = (height != 0 ? height : adr._toRow) + rowOffset; + var toCol = (width != 0 ? width : adr._toCol) + colOffset; + + var newRange = context.ExcelDataProvider.GetRange(ws, fromRow, fromCol, toRow, toCol); + if (!newRange.IsMulti) { + if (newRange.IsEmpty) { + return CompileResult.Empty; + } + var val = newRange.GetValue(fromRow, fromCol); + if (IsNumeric(val)) { + return CreateResult(val, DataType.Decimal); + } + if (val is ExcelErrorValue) { + return CreateResult(val, DataType.ExcelError); + } + return CreateResult(val, DataType.String); + } + return CreateResult(newRange, DataType.Enumerable); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs index 7b18ce1..5b20a5b 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Row.cs
@@ -7,46 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.FormulaParsing.ExcelUtilities; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Row : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - if (arguments == null || arguments.Count() == 0) - { - return CreateResult(context.Scopes.Current.Address.FromRow, DataType.Integer); - } - var rangeAddress = ArgToString(arguments, 0); - if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) - throw new ArgumentException("An invalid argument was supplied"); - var factory = new RangeAddressFactory(context.ExcelDataProvider); - var address = factory.Create(rangeAddress); - return CreateResult(address.FromRow, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Row : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + if (arguments == null || arguments.Count() == 0) { + return CreateResult(context.Scopes.Current.Address.FromRow, DataType.Integer); } + var rangeAddress = ArgToString(arguments, 0); + if (!ExcelAddressUtil.IsValidAddress(rangeAddress)) { + throw new ArgumentException("An invalid argument was supplied"); + } + var factory = new RangeAddressFactory(context.ExcelDataProvider); + var address = factory.Create(rangeAddress); + return CreateResult(address.FromRow, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs index ab3d580..94f5203 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Rows.cs
@@ -7,53 +7,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.FormulaParsing.ExcelUtilities; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class Rows : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var r=arguments.ElementAt(0).ValueAsRangeInfo; - if (r != null) - { - return CreateResult(r.Address._toRow - r.Address._fromRow + 1, DataType.Integer); - } - else - { - var range = ArgToString(arguments, 0); - if (ExcelAddressUtil.IsValidAddress(range)) - { - var factory = new RangeAddressFactory(context.ExcelDataProvider); - var address = factory.Create(range); - return CreateResult(address.ToRow - address.FromRow + 1, DataType.Integer); - } - } - throw new ArgumentException("Invalid range supplied"); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class Rows : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var r = arguments.ElementAt(0).ValueAsRangeInfo; + if (r != null) { + return CreateResult(r.Address._toRow - r.Address._fromRow + 1, DataType.Integer); } + var range = ArgToString(arguments, 0); + if (ExcelAddressUtil.IsValidAddress(range)) { + var factory = new RangeAddressFactory(context.ExcelDataProvider); + var address = factory.Create(range); + return CreateResult(address.ToRow - address.FromRow + 1, DataType.Integer); + } + throw new ArgumentException("Invalid range supplied"); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs index a1f87b5..559715a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/VLookup.cs
@@ -7,51 +7,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Diagnostics; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup -{ - public class VLookup : LookupFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - Stopwatch sw = null; - if (context.Debug) - { - sw = new Stopwatch(); - sw.Start(); - } - ValidateArguments(arguments, 3); - var lookupArgs = new LookupArguments(arguments); - var navigator = LookupNavigatorFactory.Create(LookupDirection.Vertical, lookupArgs, context); - var result = Lookup(navigator, lookupArgs); - if (context.Debug) - { - sw.Stop(); - context.Configuration.Logger.LogFunction("VLOOKUP", sw.ElapsedMilliseconds); - } - return result; - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.RefAndLookup; + +public class VLookup : LookupFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + Stopwatch sw = null; + if (context.Debug) { + sw = new(); + sw.Start(); } + ValidateArguments(arguments, 3); + var lookupArgs = new LookupArguments(arguments); + var navigator = LookupNavigatorFactory.Create(LookupDirection.Vertical, lookupArgs, context); + var result = Lookup(navigator, lookupArgs); + if (context.Debug) { + sw.Stop(); + context.Configuration.Logger.LogFunction("VLOOKUP", sw.ElapsedMilliseconds); + } + return result; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/CStr.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/CStr.cs index b64da70..2350c6c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/CStr.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/CStr.cs
@@ -7,35 +7,32 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class CStr : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - return CreateResult(ArgToString(arguments, 0), DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class CStr : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + return CreateResult(ArgToString(arguments, 0), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/CharFunction.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/CharFunction.cs index ac21f34..231479a 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/CharFunction.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/CharFunction.cs
@@ -1,19 +1,15 @@ -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.Collections.Generic; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class CharFunction : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToInt(arguments, 0); - ThrowExcelErrorValueExceptionIf(() => number < 1 || number > 255, eErrorType.Value); - return CreateResult(((char) number).ToString(), DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class CharFunction : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToInt(arguments, 0); + ThrowExcelErrorValueExceptionIf(() => number < 1 || number > 255, eErrorType.Value); + return CreateResult(((char)number).ToString(), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Concatenate.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Concatenate.cs index 9102195..9a22422 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Concatenate.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Concatenate.cs
@@ -7,47 +7,42 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Concatenate : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - if (arguments == null) - { - return CreateResult(string.Empty, DataType.String); - } - var sb = new StringBuilder(); - foreach (var arg in arguments) - { - var v = arg.ValueFirst; - if (v != null) - { - sb.Append(v); - } - } - return CreateResult(sb.ToString(), DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Concatenate : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + if (arguments == null) { + return CreateResult(string.Empty, DataType.String); } + var sb = new StringBuilder(); + foreach (var arg in arguments) { + var v = arg.ValueFirst; + if (v != null) { + sb.Append(v); + } + } + return CreateResult(sb.ToString(), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Exact.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Exact.cs index 1cacfff..41d6a3e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Exact.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Exact.cs
@@ -7,48 +7,48 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Exact : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var val1 = arguments.ElementAt(0).ValueFirst; - var val2 = arguments.ElementAt(1).ValueFirst; +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; - if (val1 == null && val2 == null) - { - return CreateResult(true, DataType.Boolean); - } - else if ((val1 == null && val2 != null) || (val1 != null && val2 == null)) - { - return CreateResult(false, DataType.Boolean); - } +public class Exact : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var val1 = arguments.ElementAt(0).ValueFirst; + var val2 = arguments.ElementAt(1).ValueFirst; - var result = string.Compare(val1.ToString(), val2.ToString(), StringComparison.InvariantCulture); - return CreateResult(result == 0, DataType.Boolean); - } + if (val1 == null && val2 == null) { + return CreateResult(true, DataType.Boolean); } + if ((val1 == null && val2 != null) || (val1 != null && val2 == null)) { + return CreateResult(false, DataType.Boolean); + } + + var result = string.Compare( + val1.ToString(), + val2.ToString(), + StringComparison.InvariantCulture); + return CreateResult(result == 0, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Find.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Find.cs index ed622d0..1a8c255 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Find.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Find.cs
@@ -7,50 +7,47 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Find : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 2); - var search = ArgToString(functionArguments, 0); - var searchIn = ArgToString(functionArguments, 1); - var startIndex = 0; - if (functionArguments.Count() > 2) - { - startIndex = ArgToInt(functionArguments, 2); - } - var result = searchIn.IndexOf(search, startIndex, System.StringComparison.Ordinal); - if (result == -1) - { - throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); - } - // Adding 1 because Excel uses 1-based index - return CreateResult(result + 1, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Find : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 2); + var search = ArgToString(functionArguments, 0); + var searchIn = ArgToString(functionArguments, 1); + var startIndex = 0; + if (functionArguments.Count() > 2) { + startIndex = ArgToInt(functionArguments, 2); } + var result = searchIn.IndexOf(search, startIndex, StringComparison.Ordinal); + if (result == -1) { + throw new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Value)); + } + // Adding 1 because Excel uses 1-based index + return CreateResult(result + 1, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Fixed.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Fixed.cs index c852959..4eab700 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Fixed.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Fixed.cs
@@ -1,37 +1,31 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Fixed : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var number = ArgToDecimal(arguments, 0); - var nDecimals = 2; - var noCommas = false; - if (arguments.Count() > 1) - { - nDecimals = ArgToInt(arguments, 1); - } - if (arguments.Count() > 2) - { - noCommas = ArgToBool(arguments, 2); - } - var format = (noCommas ? "F" : "N") + nDecimals.ToString(CultureInfo.InvariantCulture); - if (nDecimals < 0) - { - number = number - (number % (System.Math.Pow(10, nDecimals * -1))); - number = System.Math.Floor(number); - format = noCommas ? "F0" : "N0"; - } - var retVal = number.ToString(format); - return CreateResult(retVal, DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Fixed : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var number = ArgToDecimal(arguments, 0); + var nDecimals = 2; + var noCommas = false; + if (arguments.Count() > 1) { + nDecimals = ArgToInt(arguments, 1); } + if (arguments.Count() > 2) { + noCommas = ArgToBool(arguments, 2); + } + var format = (noCommas ? "F" : "N") + nDecimals.ToString(CultureInfo.InvariantCulture); + if (nDecimals < 0) { + number = number - (number % (System.Math.Pow(10, nDecimals * -1))); + number = System.Math.Floor(number); + format = noCommas ? "F0" : "N0"; + } + var retVal = number.ToString(format); + return CreateResult(retVal, DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs index e2d184a..1635f43 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Hyperlink.cs
@@ -7,39 +7,36 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-10 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Hyperlink : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - if (arguments.Count() > 1) - { - return CreateResult(ArgToString(arguments, 1), DataType.String); - } - return CreateResult(ArgToString(arguments, 0), DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Hyperlink : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + if (arguments.Count() > 1) { + return CreateResult(ArgToString(arguments, 1), DataType.String); } + return CreateResult(ArgToString(arguments, 0), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs index fddfe39..bdbbc74 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Left.cs
@@ -7,37 +7,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Left : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var str = ArgToString(arguments, 0); - var length = ArgToInt(arguments, 1); - return CreateResult(str.Substring(0, length), DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Left : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var str = ArgToString(arguments, 0); + var length = ArgToInt(arguments, 1); + return CreateResult(str.Substring(0, length), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Len.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Len.cs index 357252b..d5ce785 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Len.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Len.cs
@@ -7,36 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Len : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var length = arguments.First().ValueFirst.ToString().Length; - return CreateResult(Convert.ToDouble(length), DataType.Integer); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Len : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var length = arguments.First().ValueFirst.ToString().Length; + return CreateResult(Convert.ToDouble(length), DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Lower.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Lower.cs index 244d86d..b9e51e2 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Lower.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Lower.cs
@@ -7,35 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Lower : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - return CreateResult(arguments.First().ValueFirst.ToString().ToLower(), DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Lower : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + return CreateResult(arguments.First().ValueFirst.ToString().ToLower(), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Mid.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Mid.cs index 3f7da7a..8bbd0e6 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Mid.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Mid.cs
@@ -7,51 +7,46 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Mid : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var text = ArgToString(arguments, 0); - var startIx = ArgToInt(arguments, 1); - var length = ArgToInt(arguments, 2); - if(startIx<=0) - { - throw(new ArgumentException("Argument start can't be less than 1")); - } - //Allow overflowing start and length - if (startIx > text.Length) - { - return CreateResult("", DataType.String); - } - else - { - var result = text.Substring(startIx - 1, startIx - 1 + length < text.Length ? length : text.Length - startIx + 1); - return CreateResult(result, DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Mid : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var text = ArgToString(arguments, 0); + var startIx = ArgToInt(arguments, 1); + var length = ArgToInt(arguments, 2); + if (startIx <= 0) { + throw (new ArgumentException("Argument start can't be less than 1")); } + //Allow overflowing start and length + if (startIx > text.Length) { + return CreateResult("", DataType.String); + } + var result = text.Substring( + startIx - 1, + startIx - 1 + length < text.Length ? length : text.Length - startIx + 1); + return CreateResult(result, DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Proper.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Proper.cs index a6044d3..a336746 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Proper.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Proper.cs
@@ -7,51 +7,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; -using System.Linq; using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Proper : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var text = ArgToString(arguments, 0).ToLower(CultureInfo.InvariantCulture); - var sb = new StringBuilder(); - var previousChar = '.'; - foreach (var ch in text) - { - if (!char.IsLetter(previousChar)) - { - sb.Append(ch.ToString(CultureInfo.InvariantCulture).ToUpperInvariant()); - } - else - { - sb.Append(ch); - } - previousChar = ch; - } - return CreateResult(sb.ToString(), DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Proper : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var text = ArgToString(arguments, 0).ToLower(CultureInfo.InvariantCulture); + var sb = new StringBuilder(); + var previousChar = '.'; + foreach (var ch in text) { + if (!char.IsLetter(previousChar)) { + sb.Append(ch.ToString(CultureInfo.InvariantCulture).ToUpperInvariant()); + } else { + sb.Append(ch); + } + previousChar = ch; } + return CreateResult(sb.ToString(), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Replace.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Replace.cs index c283c5d..37ccc2c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Replace.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Replace.cs
@@ -7,54 +7,49 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Replace : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 4); - var oldText = ArgToString(arguments, 0); - var startPos = ArgToInt(arguments, 1); - var nCharsToReplace = ArgToInt(arguments, 2); - var newText = ArgToString(arguments, 3); - var firstPart = GetFirstPart(oldText, startPos); - var lastPart = GetLastPart(oldText, startPos, nCharsToReplace); - var result = string.Concat(firstPart, newText, lastPart); - return CreateResult(result, DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; - private string GetFirstPart(string text, int startPos) - { - return text.Substring(0, startPos - 1); - } +public class Replace : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 4); + var oldText = ArgToString(arguments, 0); + var startPos = ArgToInt(arguments, 1); + var nCharsToReplace = ArgToInt(arguments, 2); + var newText = ArgToString(arguments, 3); + var firstPart = GetFirstPart(oldText, startPos); + var lastPart = GetLastPart(oldText, startPos, nCharsToReplace); + var result = string.Concat(firstPart, newText, lastPart); + return CreateResult(result, DataType.String); + } - private string GetLastPart(string text, int startPos, int nCharactersToReplace) - { - int startIx = startPos -1; - startIx += nCharactersToReplace; - return text.Substring(startIx, text.Length - startIx); - } - } + private string GetFirstPart(string text, int startPos) { + return text.Substring(0, startPos - 1); + } + + private string GetLastPart(string text, int startPos, int nCharactersToReplace) { + int startIx = startPos - 1; + startIx += nCharactersToReplace; + return text.Substring(startIx, text.Length - startIx); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Rept.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Rept.cs index 2dafbd7..1f7cc5c 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Rept.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Rept.cs
@@ -7,42 +7,39 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2015-01-10 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Rept : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var str = ArgToString(arguments, 0); - var n = ArgToInt(arguments, 1); - var sb = new StringBuilder(); - for (var x = 0; x < n; x++) - { - sb.Append(str); - } - return CreateResult(sb.ToString(), DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Rept : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var str = ArgToString(arguments, 0); + var n = ArgToInt(arguments, 1); + var sb = new StringBuilder(); + for (var x = 0; x < n; x++) { + sb.Append(str); } + return CreateResult(sb.ToString(), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Right.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Right.cs index 748e51d..f78efd9 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Right.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Right.cs
@@ -7,38 +7,35 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Right : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var str = ArgToString(arguments, 0); - var length = ArgToInt(arguments, 1); - var startIx = str.Length - length; - return CreateResult(str.Substring(startIx, str.Length - startIx), DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Right : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var str = ArgToString(arguments, 0); + var length = ArgToInt(arguments, 1); + var startIx = str.Length - length; + return CreateResult(str.Substring(startIx, str.Length - startIx), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Search.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Search.cs index 05528cd..a6d38ba 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Search.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Search.cs
@@ -7,49 +7,46 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2016-03-28 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Search : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); - ValidateArguments(functionArguments, 2); - var search = ArgToString(functionArguments, 0); - var searchIn = ArgToString(functionArguments, 1); - var startIndex = 0; - if (functionArguments.Count() > 2) - { - startIndex = ArgToInt(functionArguments, 2); - } - var result = searchIn.IndexOf(search, startIndex, System.StringComparison.OrdinalIgnoreCase); - if (result == -1) - { - return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); - } - // Adding 1 because Excel uses 1-based index - return CreateResult(result + 1, DataType.Integer); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Search : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + var functionArguments = arguments as FunctionArgument[] ?? arguments.ToArray(); + ValidateArguments(functionArguments, 2); + var search = ArgToString(functionArguments, 0); + var searchIn = ArgToString(functionArguments, 1); + var startIndex = 0; + if (functionArguments.Count() > 2) { + startIndex = ArgToInt(functionArguments, 2); } + var result = searchIn.IndexOf(search, startIndex, StringComparison.OrdinalIgnoreCase); + if (result == -1) { + return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); + } + // Adding 1 because Excel uses 1-based index + return CreateResult(result + 1, DataType.Integer); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs index c0097e2..22d887e 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Substitute.cs
@@ -7,39 +7,36 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Substitute : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 3); - var text = ArgToString(arguments, 0); - var find = ArgToString(arguments, 1); - var replaceWith = ArgToString(arguments, 2); - var result = text.Replace(find, replaceWith); - return CreateResult(result, DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Substitute : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 3); + var text = ArgToString(arguments, 0); + var find = ArgToString(arguments, 1); + var replaceWith = ArgToString(arguments, 2); + var result = text.Replace(find, replaceWith); + return CreateResult(result, DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/T.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/T.cs index 7179891..646b90b 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/T.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/T.cs
@@ -7,37 +7,37 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class T : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var val = arguments.ElementAt(0).ValueFirst; - if (val is string) return CreateResult(val, DataType.String); - return CreateResult(string.Empty, DataType.String); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class T : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var val = arguments.ElementAt(0).ValueFirst; + if (val is string) { + return CreateResult(val, DataType.String); } + return CreateResult(string.Empty, DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Text.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Text.cs index 3d7ba36..00ae7fc 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Text.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Text.cs
@@ -1,4 +1,4 @@ -/* Copyright (C) 2011 Jan Källman +/* Copyright (C) 2011 Jan Källman * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -7,42 +7,43 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 2014-01-17 *******************************************************************************/ -using System; + using System.Collections.Generic; +using System.Globalization; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Text : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 2); - var value = arguments.First().ValueFirst; - var format = ArgToString(arguments, 1); - format = format.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, "."); - format = format.Replace(System.Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator.Replace((char)160,' '), ","); //Special handling for No-Break Space +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; - var result = context.ExcelDataProvider.GetFormat(value, format); +public class Text : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 2); + var value = arguments.First().ValueFirst; + var format = ArgToString(arguments, 1); + format = format.Replace(CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator, "."); + format = format.Replace( + CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator.Replace((char)160, ' '), + ","); //Special handling for No-Break Space - return CreateResult(result, DataType.String); - } - } + var result = context.ExcelDataProvider.GetFormat(value, format); + + return CreateResult(result, DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Upper.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Upper.cs index 5328acd..c40e6f4 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Upper.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Upper.cs
@@ -7,35 +7,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Mats Alm Added 2013-12-03 *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Upper : ExcelFunction - { - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - return CreateResult(arguments.First().ValueFirst.ToString().ToUpper(), DataType.String); - } - } +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; + +public class Upper : ExcelFunction { + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + return CreateResult(arguments.First().ValueFirst.ToString().ToUpper(), DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs b/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs index a6b3e24..3ad4fc8 100644 --- a/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs +++ b/EPPlus/FormulaParsing/Excel/Functions/Text/Value.cs
@@ -1,60 +1,62 @@ -using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; using System.Text.RegularExpressions; using OfficeOpenXml.FormulaParsing.Excel.Functions.DateTime; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text -{ - public class Value : ExcelFunction - { - private readonly string _groupSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberGroupSeparator; - private readonly string _decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator; - private readonly string _timeSeparator = CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator; - private readonly string _shortTimePattern = CultureInfo.CurrentCulture.DateTimeFormat.ShortTimePattern; - private readonly DateValue _dateValueFunc = new DateValue(); - private readonly TimeValue _timeValueFunc = new TimeValue(); +namespace OfficeOpenXml.FormulaParsing.Excel.Functions.Text; - public override CompileResult Execute(IEnumerable<FunctionArgument> arguments, ParsingContext context) - { - ValidateArguments(arguments, 1); - var val = ArgToString(arguments, 0).TrimEnd(' '); - double result = 0d; - if (Regex.IsMatch(val, $"^[\\d]*({Regex.Escape(_groupSeparator)}?[\\d]*)?({Regex.Escape(_decimalSeparator)}[\\d]*)?[ ?% ?]?$")) - { - if (val.EndsWith("%")) - { - val = val.TrimEnd('%'); - result = double.Parse(val) / 100; - } - else - { - result = double.Parse(val); - } - return CreateResult(result, DataType.Decimal); - } - if (double.TryParse(val, NumberStyles.Float, CultureInfo.CurrentCulture, out result)) - { - return CreateResult(result, DataType.Decimal); - } - var timeSeparator = Regex.Escape(_timeSeparator); - if (Regex.IsMatch(val, @"^[\d]{1,2}" + timeSeparator + @"[\d]{2}(" + timeSeparator + @"[\d]{2})?$")) - { - var timeResult = _timeValueFunc.Execute(val); - if (timeResult.DataType == DataType.Date) - { - return timeResult; - } - } - var dateResult = _dateValueFunc.Execute(val); - if (dateResult.DataType == DataType.Date) - { - return dateResult; - } - return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); - } +public class Value : ExcelFunction { + private readonly string _groupSeparator = CultureInfo + .CurrentCulture + .NumberFormat + .NumberGroupSeparator; + private readonly string _decimalSeparator = CultureInfo + .CurrentCulture + .NumberFormat + .NumberDecimalSeparator; + private readonly string _timeSeparator = CultureInfo.CurrentCulture.DateTimeFormat.TimeSeparator; + private readonly string _shortTimePattern = CultureInfo + .CurrentCulture + .DateTimeFormat + .ShortTimePattern; + private readonly DateValue _dateValueFunc = new(); + private readonly TimeValue _timeValueFunc = new(); + + public override CompileResult Execute( + IEnumerable<FunctionArgument> arguments, + ParsingContext context) { + ValidateArguments(arguments, 1); + var val = ArgToString(arguments, 0).TrimEnd(' '); + double result = 0d; + if (Regex.IsMatch( + val, + $"^[\\d]*({Regex.Escape(_groupSeparator)}?[\\d]*)?({Regex.Escape(_decimalSeparator) + }[\\d]*)?[ ?% ?]?$")) { + if (val.EndsWith("%")) { + val = val.TrimEnd('%'); + result = double.Parse(val) / 100; + } else { + result = double.Parse(val); + } + return CreateResult(result, DataType.Decimal); } + if (double.TryParse(val, NumberStyles.Float, CultureInfo.CurrentCulture, out result)) { + return CreateResult(result, DataType.Decimal); + } + var timeSeparator = Regex.Escape(_timeSeparator); + if (Regex.IsMatch( + val, + @"^[\d]{1,2}" + timeSeparator + @"[\d]{2}(" + timeSeparator + @"[\d]{2})?$")) { + var timeResult = _timeValueFunc.Execute(val); + if (timeResult.DataType == DataType.Date) { + return timeResult; + } + } + var dateResult = _dateValueFunc.Execute(val); + if (dateResult.DataType == DataType.Date) { + return dateResult; + } + return CreateResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); + } }
diff --git a/EPPlus/FormulaParsing/Excel/Operators/IOperator.cs b/EPPlus/FormulaParsing/Excel/Operators/IOperator.cs index 63f7851..7975cc1 100644 --- a/EPPlus/FormulaParsing/Excel/Operators/IOperator.cs +++ b/EPPlus/FormulaParsing/Excel/Operators/IOperator.cs
@@ -13,35 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.Excel.Operators -{ - public interface IOperator - { - Operators Operator { get; } +namespace OfficeOpenXml.FormulaParsing.Excel.Operators; - CompileResult Apply(CompileResult left, CompileResult right); +public interface IOperator { + Operators Operator { get; } - int Precedence { get; } - } + CompileResult Apply(CompileResult left, CompileResult right); + + int Precedence { get; } }
diff --git a/EPPlus/FormulaParsing/Excel/Operators/Operator.cs b/EPPlus/FormulaParsing/Excel/Operators/Operator.cs index d53a4ac..9134b3c 100644 --- a/EPPlus/FormulaParsing/Excel/Operators/Operator.cs +++ b/EPPlus/FormulaParsing/Excel/Operators/Operator.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,383 +13,386 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.Excel.Operators -{ - public class Operator : IOperator - { - private const int PrecedencePercent = 2; - private const int PrecedenceExp = 4; - private const int PrecedenceMultiplyDevide = 6; - private const int PrecedenceIntegerDivision = 8; - private const int PrecedenceModulus = 10; - private const int PrecedenceAddSubtract = 12; - private const int PrecedenceConcat = 15; - private const int PrecedenceComparison = 25; +namespace OfficeOpenXml.FormulaParsing.Excel.Operators; - private Operator() { } +public class Operator : IOperator { + private const int _precedencePercent = 2; + private const int _precedenceExp = 4; + private const int _precedenceMultiplyDevide = 6; + private const int _precedenceIntegerDivision = 8; + private const int _precedenceModulus = 10; + private const int _precedenceAddSubtract = 12; + private const int _precedenceConcat = 15; + private const int _precedenceComparison = 25; - private Operator(Operators @operator, int precedence, Func<CompileResult, CompileResult, CompileResult> implementation) - { - _implementation = implementation; - _precedence = precedence; - _operator = @operator; - } + private Operator() {} - private readonly Func<CompileResult, CompileResult, CompileResult> _implementation; - private readonly int _precedence; - private readonly Operators _operator; + private Operator( + Operators @operator, + int precedence, + Func<CompileResult, CompileResult, CompileResult> implementation) { + _implementation = implementation; + _precedence = precedence; + _operator = @operator; + } - int IOperator.Precedence - { - get { return _precedence; } - } + private readonly Func<CompileResult, CompileResult, CompileResult> _implementation; + private readonly int _precedence; + private readonly Operators _operator; - Operators IOperator.Operator - { - get { return _operator; } - } + int IOperator.Precedence => _precedence; - public CompileResult Apply(CompileResult left, CompileResult right) - { - if (left.Result is ExcelErrorValue) - { - return new CompileResult(left.Result, DataType.ExcelError); - //throw(new ExcelErrorValueException((ExcelErrorValue)left.Result)); - } - else if (right.Result is ExcelErrorValue) - { - return new CompileResult(right.Result, DataType.ExcelError); - //throw(new ExcelErrorValueException((ExcelErrorValue)right.Result)); - } - return _implementation(left, right); - } + Operators IOperator.Operator { + get { return _operator; } + } - public override string ToString() - { - return "Operator: " + _operator; - } + public CompileResult Apply(CompileResult left, CompileResult right) { + if (left.Result is ExcelErrorValue) { + return new(left.Result, DataType.ExcelError); + //throw(new ExcelErrorValueException((ExcelErrorValue)left.Result)); + } + if (right.Result is ExcelErrorValue) { + return new(right.Result, DataType.ExcelError); + //throw(new ExcelErrorValueException((ExcelErrorValue)right.Result)); + } + return _implementation(left, right); + } - private static IOperator _plus; - public static IOperator Plus - { - get - { - return _plus ?? (_plus = new Operator(Operators.Plus, PrecedenceAddSubtract, (l, r) => - { - l = l == null || l.Result == null ? new CompileResult(0, DataType.Integer) : l; - r = r == null || r.Result == null ? new CompileResult(0, DataType.Integer) : r; + public override string ToString() { + return "Operator: " + _operator; + } + + private static IOperator _plus; + + public static IOperator Plus { + get { + return _plus + ?? (_plus = new Operator( + Operators.Plus, + _precedenceAddSubtract, + (l, r) => { + l = l == null || l.Result == null ? new(0, DataType.Integer) : l; + r = r == null || r.Result == null ? new(0, DataType.Integer) : r; ExcelErrorValue errorVal; - if (EitherIsError(l, r, out errorVal)) - { - return new CompileResult(errorVal); + if (EitherIsError(l, r, out errorVal)) { + return new(errorVal); } - if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) - { - return new CompileResult(l.ResultNumeric + r.ResultNumeric, DataType.Integer); + if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) { + return new(l.ResultNumeric + r.ResultNumeric, DataType.Integer); } - else if ((l.IsNumeric || l.IsNumericString || l.Result is ExcelDataProvider.IRangeInfo) && - (r.IsNumeric || r.IsNumericString || r.Result is ExcelDataProvider.IRangeInfo)) - { - return new CompileResult(l.ResultNumeric + r.ResultNumeric, DataType.Decimal); + if ((l.IsNumeric + || l.IsNumericString + || l.Result is ExcelDataProvider.IRangeInfo) + && (r.IsNumeric + || r.IsNumericString + || r.Result is ExcelDataProvider.IRangeInfo)) { + return new(l.ResultNumeric + r.ResultNumeric, DataType.Decimal); } - return new CompileResult(eErrorType.Value); - })); - } - } + return new(eErrorType.Value); + })); + } + } - private static IOperator _minus; - public static IOperator Minus - { - get - { - return _minus ?? (_minus = new Operator(Operators.Minus, PrecedenceAddSubtract, (l, r) => - { - l = l == null || l.Result == null ? new CompileResult(0, DataType.Integer) : l; - r = r == null || r.Result == null ? new CompileResult(0, DataType.Integer) : r; - if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) - { - return new CompileResult(l.ResultNumeric - r.ResultNumeric, DataType.Integer); + private static IOperator _minus; + + public static IOperator Minus { + get { + return _minus + ?? (_minus = new Operator( + Operators.Minus, + _precedenceAddSubtract, + (l, r) => { + l = l == null || l.Result == null ? new(0, DataType.Integer) : l; + r = r == null || r.Result == null ? new(0, DataType.Integer) : r; + if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) { + return new(l.ResultNumeric - r.ResultNumeric, DataType.Integer); } - else if ((l.IsNumeric || l.IsNumericString || l.Result is ExcelDataProvider.IRangeInfo) && - (r.IsNumeric || r.IsNumericString || r.Result is ExcelDataProvider.IRangeInfo)) - { - return new CompileResult(l.ResultNumeric - r.ResultNumeric, DataType.Decimal); + if ((l.IsNumeric + || l.IsNumericString + || l.Result is ExcelDataProvider.IRangeInfo) + && (r.IsNumeric + || r.IsNumericString + || r.Result is ExcelDataProvider.IRangeInfo)) { + return new(l.ResultNumeric - r.ResultNumeric, DataType.Decimal); } - return new CompileResult(eErrorType.Value); - })); - } - } + return new(eErrorType.Value); + })); + } + } - private static IOperator _multiply; - public static IOperator Multiply - { - get - { - return _multiply ?? (_multiply = new Operator(Operators.Multiply, PrecedenceMultiplyDevide, (l, r) => - { + private static IOperator _multiply; + + public static IOperator Multiply { + get { + return _multiply + ?? (_multiply = new Operator( + Operators.Multiply, + _precedenceMultiplyDevide, + (l, r) => { l = l ?? new CompileResult(0, DataType.Integer); r = r ?? new CompileResult(0, DataType.Integer); - if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) - { - return new CompileResult(l.ResultNumeric*r.ResultNumeric, DataType.Integer); + if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) { + return new(l.ResultNumeric * r.ResultNumeric, DataType.Integer); } - else if ((l.IsNumeric || l.IsNumericString || l.Result is ExcelDataProvider.IRangeInfo) && - (r.IsNumeric || r.IsNumericString || r.Result is ExcelDataProvider.IRangeInfo)) - { - return new CompileResult(l.ResultNumeric*r.ResultNumeric, DataType.Decimal); + if ((l.IsNumeric + || l.IsNumericString + || l.Result is ExcelDataProvider.IRangeInfo) + && (r.IsNumeric + || r.IsNumericString + || r.Result is ExcelDataProvider.IRangeInfo)) { + return new(l.ResultNumeric * r.ResultNumeric, DataType.Decimal); } - return new CompileResult(eErrorType.Value); - })); - } - } + return new(eErrorType.Value); + })); + } + } - private static IOperator _divide; - public static IOperator Divide - { - get - { - return _divide ?? (_divide = new Operator(Operators.Divide, PrecedenceMultiplyDevide, (l, r) => - { - if (!(l.IsNumeric || l.IsNumericString || l.Result is ExcelDataProvider.IRangeInfo) || - !(r.IsNumeric || r.IsNumericString || r.Result is ExcelDataProvider.IRangeInfo)) - { - return new CompileResult(eErrorType.Value); + private static IOperator _divide; + + public static IOperator Divide { + get { + return _divide + ?? (_divide = new Operator( + Operators.Divide, + _precedenceMultiplyDevide, + (l, r) => { + if (!(l.IsNumeric + || l.IsNumericString + || l.Result is ExcelDataProvider.IRangeInfo) + || !(r.IsNumeric + || r.IsNumericString + || r.Result is ExcelDataProvider.IRangeInfo)) { + return new(eErrorType.Value); } var left = l.ResultNumeric; var right = r.ResultNumeric; - if (Math.Abs(right - 0d) < double.Epsilon) - { - return new CompileResult(eErrorType.Div0); + if (Math.Abs(right - 0d) < double.Epsilon) { + return new(eErrorType.Div0); } - else if ((l.IsNumeric || l.IsNumericString || l.Result is ExcelDataProvider.IRangeInfo) && - (r.IsNumeric || r.IsNumericString || r.Result is ExcelDataProvider.IRangeInfo)) - { - return new CompileResult(left/right, DataType.Decimal); + if ((l.IsNumeric + || l.IsNumericString + || l.Result is ExcelDataProvider.IRangeInfo) + && (r.IsNumeric + || r.IsNumericString + || r.Result is ExcelDataProvider.IRangeInfo)) { + return new(left / right, DataType.Decimal); } - return new CompileResult(eErrorType.Value); - })); - } - } - - public static IOperator Exp - { - get - { - return new Operator(Operators.Exponentiation, PrecedenceExp, (l, r) => - { - if (l == null && r == null) - { - return new CompileResult(eErrorType.Value); - } - l = l ?? new CompileResult(0, DataType.Integer); - r = r ?? new CompileResult(0, DataType.Integer); - if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo) && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) - { - return new CompileResult(Math.Pow(l.ResultNumeric, r.ResultNumeric), DataType.Decimal); - } - return new CompileResult(0d, DataType.Decimal); - }); - } - } - - public static IOperator Concat - { - get - { - return new Operator(Operators.Concat, PrecedenceConcat, (l, r) => - { - l = l ?? new CompileResult(string.Empty, DataType.String); - r = r ?? new CompileResult(string.Empty, DataType.String); - var lStr = l.Result != null ? l.ResultValue.ToString() : string.Empty; - var rStr = r.Result != null ? r.ResultValue.ToString() : string.Empty; - return new CompileResult(string.Concat(lStr, rStr), DataType.String); - }); - } - } - - private static IOperator _greaterThan; - public static IOperator GreaterThan - { - get - { - //return new Operator(Operators.GreaterThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) > 0, DataType.Boolean)); - return _greaterThan ?? - (_greaterThan = - new Operator(Operators.LessThanOrEqual, PrecedenceComparison, - (l, r) => Compare(l, r, (compRes) => compRes > 0))); - } - } - - private static IOperator _eq; - public static IOperator Eq - { - get - { - //return new Operator(Operators.Equals, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) == 0, DataType.Boolean)); - return _eq ?? - (_eq = - new Operator(Operators.LessThanOrEqual, PrecedenceComparison, - (l, r) => Compare(l, r, (compRes) => compRes == 0))); - } - } - - private static IOperator _notEqualsTo; - public static IOperator NotEqualsTo - { - get - { - //return new Operator(Operators.NotEqualTo, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) != 0, DataType.Boolean)); - return _notEqualsTo ?? - (_notEqualsTo = - new Operator(Operators.LessThanOrEqual, PrecedenceComparison, - (l, r) => Compare(l, r, (compRes) => compRes != 0))); - } - } - - private static IOperator _greaterThanOrEqual; - public static IOperator GreaterThanOrEqual - { - get - { - //return new Operator(Operators.GreaterThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) >= 0, DataType.Boolean)); - return _greaterThanOrEqual ?? - (_greaterThanOrEqual = - new Operator(Operators.LessThanOrEqual, PrecedenceComparison, - (l, r) => Compare(l, r, (compRes) => compRes >= 0))); - } - } - - private static IOperator _lessThan; - public static IOperator LessThan - { - get - { - //return new Operator(Operators.LessThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) < 0, DataType.Boolean)); - return _lessThan ?? - (_lessThan = - new Operator(Operators.LessThanOrEqual, PrecedenceComparison, - (l, r) => Compare(l, r, (compRes) => compRes < 0))); - } - } - - public static IOperator LessThanOrEqual - { - get - { - //return new Operator(Operators.LessThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) <= 0, DataType.Boolean)); - return new Operator(Operators.LessThanOrEqual, PrecedenceComparison, (l, r) => Compare(l, r, (compRes) => compRes <= 0)); - } - } - - private static IOperator _percent; - public static IOperator Percent - { - get - { - if (_percent == null) - { - _percent = new Operator(Operators.Percent, PrecedencePercent, (l, r) => - { - l = l ?? new CompileResult(0, DataType.Integer); - r = r ?? new CompileResult(0, DataType.Integer); - if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) - { - return new CompileResult(l.ResultNumeric * r.ResultNumeric, DataType.Integer); - } - else if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo) && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) - { - return new CompileResult(l.ResultNumeric * r.ResultNumeric, DataType.Decimal); - } - return new CompileResult(eErrorType.Value); - }); - } - return _percent; - } - } - - private static object GetObjFromOther(CompileResult obj, CompileResult other) - { - if (obj.Result == null) - { - if (other.DataType == DataType.String) return string.Empty; - else return 0d; - } - return obj.ResultValue; - } - - private static CompileResult Compare(CompileResult l, CompileResult r, Func<int, bool> comparison ) - { - ExcelErrorValue errorVal; - if (EitherIsError(l, r, out errorVal)) - { - return new CompileResult(errorVal); - } - object left, right; - left = GetObjFromOther(l, r); - right = GetObjFromOther(r, l); - if (ConvertUtil.IsNumeric(left) && ConvertUtil.IsNumeric(right)) - { - var lnum = ConvertUtil.GetValueDouble(left); - var rnum = ConvertUtil.GetValueDouble(right); - if (Math.Abs(lnum - rnum) < double.Epsilon) - { - return new CompileResult(comparison(0), DataType.Boolean); - } - var comparisonResult = lnum.CompareTo(rnum); - return new CompileResult(comparison(comparisonResult), DataType.Boolean); - } - else - { - var comparisonResult = CompareString(left, right); - return new CompileResult(comparison(comparisonResult), DataType.Boolean); - } - } - - private static int CompareString(object l, object r) - { - var sl = (l ?? "").ToString(); - var sr = (r ?? "").ToString(); - return System.String.Compare(sl, sr, System.StringComparison.Ordinal); - } - - private static bool EitherIsError(CompileResult l, CompileResult r, out ExcelErrorValue errorVal) - { - if (l.DataType == DataType.ExcelError) - { - errorVal = (ExcelErrorValue) l.Result; - return true; - } - if (r.DataType == DataType.ExcelError) - { - errorVal = (ExcelErrorValue) r.Result; - return true; - } - errorVal = null; - return false; - } + return new(eErrorType.Value); + })); } + } + + public static IOperator Exp { + get { + return new Operator( + Operators.Exponentiation, + _precedenceExp, + (l, r) => { + if (l == null && r == null) { + return new(eErrorType.Value); + } + l = l ?? new CompileResult(0, DataType.Integer); + r = r ?? new CompileResult(0, DataType.Integer); + if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo) + && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) { + return new(Math.Pow(l.ResultNumeric, r.ResultNumeric), DataType.Decimal); + } + return new(0d, DataType.Decimal); + }); + } + } + + public static IOperator Concat { + get { + return new Operator( + Operators.Concat, + _precedenceConcat, + (l, r) => { + l = l ?? new CompileResult(string.Empty, DataType.String); + r = r ?? new CompileResult(string.Empty, DataType.String); + var lStr = l.Result != null ? l.ResultValue.ToString() : string.Empty; + var rStr = r.Result != null ? r.ResultValue.ToString() : string.Empty; + return new(string.Concat(lStr, rStr), DataType.String); + }); + } + } + + private static IOperator _greaterThan; + + public static IOperator GreaterThan { + get { + //return new Operator(Operators.GreaterThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) > 0, DataType.Boolean)); + return _greaterThan + ?? (_greaterThan = new Operator( + Operators.LessThanOrEqual, + _precedenceComparison, + (l, r) => Compare(l, r, compRes => compRes > 0))); + } + } + + private static IOperator _eq; + + public static IOperator Eq { + get { + //return new Operator(Operators.Equals, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) == 0, DataType.Boolean)); + return _eq + ?? (_eq = new Operator( + Operators.LessThanOrEqual, + _precedenceComparison, + (l, r) => Compare(l, r, compRes => compRes == 0))); + } + } + + private static IOperator _notEqualsTo; + + public static IOperator NotEqualsTo { + get { + //return new Operator(Operators.NotEqualTo, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) != 0, DataType.Boolean)); + return _notEqualsTo + ?? (_notEqualsTo = new Operator( + Operators.LessThanOrEqual, + _precedenceComparison, + (l, r) => Compare(l, r, compRes => compRes != 0))); + } + } + + private static IOperator _greaterThanOrEqual; + + public static IOperator GreaterThanOrEqual { + get { + //return new Operator(Operators.GreaterThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) >= 0, DataType.Boolean)); + return _greaterThanOrEqual + ?? (_greaterThanOrEqual = new Operator( + Operators.LessThanOrEqual, + _precedenceComparison, + (l, r) => Compare(l, r, compRes => compRes >= 0))); + } + } + + private static IOperator _lessThan; + + public static IOperator LessThan { + get { + //return new Operator(Operators.LessThan, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) < 0, DataType.Boolean)); + return _lessThan + ?? (_lessThan = new Operator( + Operators.LessThanOrEqual, + _precedenceComparison, + (l, r) => Compare(l, r, compRes => compRes < 0))); + } + } + + public static IOperator LessThanOrEqual { + get { + //return new Operator(Operators.LessThanOrEqual, PrecedenceComparison, (l, r) => new CompileResult(Compare(l, r) <= 0, DataType.Boolean)); + return new Operator( + Operators.LessThanOrEqual, + _precedenceComparison, + (l, r) => Compare(l, r, compRes => compRes <= 0)); + } + } + + private static IOperator _percent; + + public static IOperator Percent { + get { + if (_percent == null) { + _percent = new Operator( + Operators.Percent, + _precedencePercent, + (l, r) => { + l = l ?? new CompileResult(0, DataType.Integer); + r = r ?? new CompileResult(0, DataType.Integer); + if (l.DataType == DataType.Integer && r.DataType == DataType.Integer) { + return new(l.ResultNumeric * r.ResultNumeric, DataType.Integer); + } + if ((l.IsNumeric || l.Result is ExcelDataProvider.IRangeInfo) + && (r.IsNumeric || r.Result is ExcelDataProvider.IRangeInfo)) { + return new(l.ResultNumeric * r.ResultNumeric, DataType.Decimal); + } + return new(eErrorType.Value); + }); + } + return _percent; + } + } + + private static object GetObjFromOther(CompileResult obj, CompileResult other) { + if (obj.Result == null) { + if (other.DataType == DataType.String) { + return string.Empty; + } + return 0d; + } + return obj.ResultValue; + } + + private static CompileResult Compare( + CompileResult l, + CompileResult r, + Func<int, bool> comparison) { + ExcelErrorValue errorVal; + if (EitherIsError(l, r, out errorVal)) { + return new(errorVal); + } + object left, + right; + left = GetObjFromOther(l, r); + right = GetObjFromOther(r, l); + if (ConvertUtil.IsNumeric(left) && ConvertUtil.IsNumeric(right)) { + var lnum = ConvertUtil.GetValueDouble(left); + var rnum = ConvertUtil.GetValueDouble(right); + if (Math.Abs(lnum - rnum) < double.Epsilon) { + return new(comparison(0), DataType.Boolean); + } + var comparisonResult = lnum.CompareTo(rnum); + return new(comparison(comparisonResult), DataType.Boolean); + } else { + var comparisonResult = CompareString(left, right); + return new(comparison(comparisonResult), DataType.Boolean); + } + } + + private static int CompareString(object l, object r) { + var sl = (l ?? "").ToString(); + var sr = (r ?? "").ToString(); + return String.Compare(sl, sr, StringComparison.Ordinal); + } + + private static bool EitherIsError( + CompileResult l, + CompileResult r, + out ExcelErrorValue errorVal) { + if (l.DataType == DataType.ExcelError) { + errorVal = (ExcelErrorValue)l.Result; + return true; + } + if (r.DataType == DataType.ExcelError) { + errorVal = (ExcelErrorValue)r.Result; + return true; + } + errorVal = null; + return false; + } }
diff --git a/EPPlus/FormulaParsing/Excel/Operators/Operators.cs b/EPPlus/FormulaParsing/Excel/Operators/Operators.cs index b5b4774..04c07e5 100644 --- a/EPPlus/FormulaParsing/Excel/Operators/Operators.cs +++ b/EPPlus/FormulaParsing/Excel/Operators/Operators.cs
@@ -13,45 +13,39 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Operators -{ - public enum Operators - { - Undefined, - Concat, - Plus, - Minus, - Multiply, - Divide, - Modulus, - Percent, - Equals, - GreaterThan, - GreaterThanOrEqual, - LessThan, - LessThanOrEqual, - NotEqualTo, - IntegerDivision, - Exponentiation - } +namespace OfficeOpenXml.FormulaParsing.Excel.Operators; + +public enum Operators { + Undefined, + Concat, + Plus, + Minus, + Multiply, + Divide, + Modulus, + Percent, + Equals, + GreaterThan, + GreaterThanOrEqual, + LessThan, + LessThanOrEqual, + NotEqualTo, + IntegerDivision, + Exponentiation, }
diff --git a/EPPlus/FormulaParsing/Excel/Operators/OperatorsDict.cs b/EPPlus/FormulaParsing/Excel/Operators/OperatorsDict.cs index 2ea34fb..2f1cf99 100644 --- a/EPPlus/FormulaParsing/Excel/Operators/OperatorsDict.cs +++ b/EPPlus/FormulaParsing/Excel/Operators/OperatorsDict.cs
@@ -13,58 +13,50 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Excel.Operators -{ - public class OperatorsDict : Dictionary<string, IOperator> - { - public OperatorsDict() - { - Add("+", Operator.Plus); - Add("-", Operator.Minus); - Add("*", Operator.Multiply); - Add("/", Operator.Divide); - Add("^", Operator.Exp); - Add("=", Operator.Eq); - Add(">", Operator.GreaterThan); - Add(">=", Operator.GreaterThanOrEqual); - Add("<", Operator.LessThan); - Add("<=", Operator.LessThanOrEqual); - Add("<>", Operator.NotEqualsTo); - Add("&", Operator.Concat); - } +namespace OfficeOpenXml.FormulaParsing.Excel.Operators; - private static IDictionary<string, IOperator> _instance; +public class OperatorsDict : Dictionary<string, IOperator> { + public OperatorsDict() { + Add("+", Operator.Plus); + Add("-", Operator.Minus); + Add("*", Operator.Multiply); + Add("/", Operator.Divide); + Add("^", Operator.Exp); + Add("=", Operator.Eq); + Add(">", Operator.GreaterThan); + Add(">=", Operator.GreaterThanOrEqual); + Add("<", Operator.LessThan); + Add("<=", Operator.LessThanOrEqual); + Add("<>", Operator.NotEqualsTo); + Add("&", Operator.Concat); + } - public static IDictionary<string, IOperator> Instance - { - get - { - if (_instance == null) - { - _instance = new OperatorsDict(); - } - return _instance; - } - } + private static IDictionary<string, IOperator> _instance; + + public static IDictionary<string, IOperator> Instance { + get { + if (_instance == null) { + _instance = new OperatorsDict(); + } + return _instance; } + } }
diff --git a/EPPlus/FormulaParsing/ExcelCalculationOption.cs b/EPPlus/FormulaParsing/ExcelCalculationOption.cs index c642710..a94d5ef 100644 --- a/EPPlus/FormulaParsing/ExcelCalculationOption.cs +++ b/EPPlus/FormulaParsing/ExcelCalculationOption.cs
@@ -1,16 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing -{ - public class ExcelCalculationOption - { - public ExcelCalculationOption() - { - AllowCirculareReferences = false; - } - public bool AllowCirculareReferences { get; set; } - } +public class ExcelCalculationOption { + public ExcelCalculationOption() { + AllowCirculareReferences = false; + } + + public bool AllowCirculareReferences { get; set; } }
diff --git a/EPPlus/FormulaParsing/ExcelCell.cs b/EPPlus/FormulaParsing/ExcelCell.cs index a560b08..aedd49c 100644 --- a/EPPlus/FormulaParsing/ExcelCell.cs +++ b/EPPlus/FormulaParsing/ExcelCell.cs
@@ -1,26 +1,18 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing -{ - public class ExcelCell - { - public ExcelCell(object val, string formula, int colIndex, int rowIndex) - { - Value = val; - Formula = formula; - ColIndex = colIndex; - RowIndex = rowIndex; - } +public class ExcelCell { + public ExcelCell(object val, string formula, int colIndex, int rowIndex) { + Value = val; + Formula = formula; + ColIndex = colIndex; + RowIndex = rowIndex; + } - public int ColIndex { get; private set; } + public int ColIndex { get; private set; } - public int RowIndex { get; private set; } + public int RowIndex { get; private set; } - public object Value { get; private set; } + public object Value { get; private set; } - public string Formula { get; private set; } - } + public string Formula { get; private set; } }
diff --git a/EPPlus/FormulaParsing/ExcelDataProvider.cs b/EPPlus/FormulaParsing/ExcelDataProvider.cs index 17f1257..2c33ece 100644 --- a/EPPlus/FormulaParsing/ExcelDataProvider.cs +++ b/EPPlus/FormulaParsing/ExcelDataProvider.cs
@@ -1,123 +1,153 @@ -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using System.Collections.Generic; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing -{ - /// <summary> - /// This class should be implemented to be able to deliver excel data - /// to the formula parser. - /// </summary> - public abstract class ExcelDataProvider - { - /// <summary> - /// A range of cells in a worksheet. - /// </summary> - public interface IRangeInfo : IEnumerator<ICellInfo>, IEnumerable<ICellInfo> - { - bool IsEmpty { get; } - bool IsMulti { get; } - int GetNCells(); - ExcelAddressBase Address { get; } - object GetValue(int row, int col); - object GetOffset(int rowOffset, int colOffset); +namespace OfficeOpenXml.FormulaParsing; - ExcelWorksheet Worksheet { get; } - } - /// <summary> - /// Information and help methods about a cell - /// </summary> - public interface ICellInfo - { - string Address { get; } - int Row { get; } - int Column { get; } - string Formula { get; } - object Value { get; } - double ValueDouble { get; } - double ValueDoubleLogical { get; } - bool IsHiddenRow { get; } - bool IsExcelError { get; } - IList<Token> Tokens { get; } - } - public interface INameInfo - { - ulong Id { get; set; } - string Worksheet {get; set;} - string Name { get; set; } - string Formula { get; set; } - IList<Token> Tokens { get; } - object Value { get; set; } - } - /// <summary> - /// Returns the names of all worksheet names - /// </summary> - /// <returns></returns> - public abstract ExcelNamedRangeCollection GetWorksheetNames(string worksheet); - /// <summary> - /// Returns all defined names in a workbook - /// </summary> - /// <returns></returns> - public abstract ExcelNamedRangeCollection GetWorkbookNameValues(); - /// <summary> - /// Returns values from the required range. - /// </summary> - /// <param name="worksheetName">The name of the worksheet</param> - /// <param name="row">Row</param> - /// <param name="column">Column</param> - /// <param name="address">The reference address</param> - /// <returns></returns> - public abstract IRangeInfo GetRange(string worksheetName, int row, int column, string address); - public abstract INameInfo GetName(string worksheet, string name); +/// <summary> +/// This class should be implemented to be able to deliver excel data +/// to the formula parser. +/// </summary> +public abstract class ExcelDataProvider { + /// <summary> + /// A range of cells in a worksheet. + /// </summary> + public interface IRangeInfo : IEnumerator<ICellInfo>, IEnumerable<ICellInfo> { + bool IsEmpty { get; } - public abstract IEnumerable<object> GetRangeValues(string address); + bool IsMulti { get; } - public abstract string GetRangeFormula(string worksheetName, int row, int column); - public abstract List<Token> GetRangeFormulaTokens(string worksheetName, int row, int column); - public abstract bool IsRowHidden(string worksheetName, int row); - ///// <summary> - ///// Returns a single cell value - ///// </summary> - ///// <param name="address"></param> - ///// <returns></returns> - //public abstract object GetCellValue(int sheetID, string address); + int GetNCells(); - /// <summary> - /// Returns a single cell value - /// </summary> - /// <param name="sheetName"></param> - /// <param name="row"></param> - /// <param name="col"></param> - /// <returns></returns> - public abstract object GetCellValue(string sheetName, int row, int col); + ExcelAddressBase Address { get; } - ///// <summary> - ///// Sets the value on the cell - ///// </summary> - ///// <param name="address"></param> - ///// <param name="value"></param> - //public abstract void SetCellValue(string address, object value); + object GetValue(int row, int col); - /// <summary> - /// Returns the address of the lowest rightmost cell on the worksheet. - /// </summary> - /// <param name="worksheet"></param> - /// <returns></returns> - public abstract ExcelCellAddress GetDimensionEnd(string worksheet); + object GetOffset(int rowOffset, int colOffset); - /// <summary> - /// Max number of columns in a worksheet that the Excel data provider can handle. - /// </summary> - public abstract int ExcelMaxColumns { get; } + ExcelWorksheet Worksheet { get; } + } - /// <summary> - /// Max number of rows in a worksheet that the Excel data provider can handle - /// </summary> - public abstract int ExcelMaxRows { get; } + /// <summary> + /// Information and help methods about a cell + /// </summary> + public interface ICellInfo { + string Address { get; } - public abstract object GetRangeValue(string worksheetName, int row, int column); - public abstract string GetFormat(object value, string format); + int Row { get; } - public abstract void Reset(); - public abstract IRangeInfo GetRange(string worksheet, int fromRow, int fromCol, int toRow, int toCol); - } + int Column { get; } + + string Formula { get; } + + object Value { get; } + + double ValueDouble { get; } + + double ValueDoubleLogical { get; } + + bool IsHiddenRow { get; } + + bool IsExcelError { get; } + + IList<Token> Tokens { get; } + } + + public interface INameInfo { + ulong Id { get; set; } + + string Worksheet { get; set; } + + string Name { get; set; } + + string Formula { get; set; } + + IList<Token> Tokens { get; } + + object Value { get; set; } + } + + /// <summary> + /// Returns the names of all worksheet names + /// </summary> + /// <returns></returns> + public abstract ExcelNamedRangeCollection GetWorksheetNames(string worksheet); + + /// <summary> + /// Returns all defined names in a workbook + /// </summary> + /// <returns></returns> + public abstract ExcelNamedRangeCollection GetWorkbookNameValues(); + + /// <summary> + /// Returns values from the required range. + /// </summary> + /// <param name="worksheetName">The name of the worksheet</param> + /// <param name="row">Row</param> + /// <param name="column">Column</param> + /// <param name="address">The reference address</param> + /// <returns></returns> + public abstract IRangeInfo GetRange(string worksheetName, int row, int column, string address); + + public abstract INameInfo GetName(string worksheet, string name); + + public abstract IEnumerable<object> GetRangeValues(string address); + + public abstract string GetRangeFormula(string worksheetName, int row, int column); + + public abstract List<Token> GetRangeFormulaTokens(string worksheetName, int row, int column); + + public abstract bool IsRowHidden(string worksheetName, int row); + + ///// <summary> + ///// Returns a single cell value + ///// </summary> + ///// <param name="address"></param> + ///// <returns></returns> + //public abstract object GetCellValue(int sheetID, string address); + + /// <summary> + /// Returns a single cell value + /// </summary> + /// <param name="sheetName"></param> + /// <param name="row"></param> + /// <param name="col"></param> + /// <returns></returns> + public abstract object GetCellValue(string sheetName, int row, int col); + + ///// <summary> + ///// Sets the value on the cell + ///// </summary> + ///// <param name="address"></param> + ///// <param name="value"></param> + //public abstract void SetCellValue(string address, object value); + + /// <summary> + /// Returns the address of the lowest rightmost cell on the worksheet. + /// </summary> + /// <param name="worksheet"></param> + /// <returns></returns> + public abstract ExcelCellAddress GetDimensionEnd(string worksheet); + + /// <summary> + /// Max number of columns in a worksheet that the Excel data provider can handle. + /// </summary> + public abstract int ExcelMaxColumns { get; } + + /// <summary> + /// Max number of rows in a worksheet that the Excel data provider can handle + /// </summary> + public abstract int ExcelMaxRows { get; } + + public abstract object GetRangeValue(string worksheetName, int row, int column); + + public abstract string GetFormat(object value, string format); + + public abstract void Reset(); + + public abstract IRangeInfo GetRange( + string worksheet, + int fromRow, + int fromCol, + int toRow, + int toCol); }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/AddressTranslator.cs b/EPPlus/FormulaParsing/ExcelUtilities/AddressTranslator.cs index 7f13379..7816854 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/AddressTranslator.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/AddressTranslator.cs
@@ -13,119 +13,104 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; + using System.Globalization; -using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - /// <summary> - /// Handles translations from Spreadsheet addresses to 0-based numeric index. - /// </summary> - public class AddressTranslator - { - public enum RangeCalculationBehaviour - { - FirstPart, - LastPart - } +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - private readonly ExcelDataProvider _excelDataProvider; +/// <summary> +/// Handles translations from Spreadsheet addresses to 0-based numeric index. +/// </summary> +public class AddressTranslator { + public enum RangeCalculationBehaviour { + FirstPart, + LastPart, + } - public AddressTranslator(ExcelDataProvider excelDataProvider) - { - Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); - _excelDataProvider = excelDataProvider; - } + private readonly ExcelDataProvider _excelDataProvider; - /// <summary> - /// Translates an address in format "A1" to col- and rowindex. - /// - /// If the supplied address is a range, the address of the first part will be calculated. - /// </summary> - /// <param name="address"></param> - /// <param name="col"></param> - /// <param name="row"></param> - public virtual void ToColAndRow(string address, out int col, out int row) - { - ToColAndRow(address, out col, out row, RangeCalculationBehaviour.FirstPart); - } + public AddressTranslator(ExcelDataProvider excelDataProvider) { + Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); + _excelDataProvider = excelDataProvider; + } - /// <summary> - /// Translates an address in format "A1" to col- and rowindex. - /// </summary> - /// <param name="address"></param> - /// <param name="col"></param> - /// <param name="row"></param> - /// <param name="behaviour"></param> - public virtual void ToColAndRow(string address, out int col, out int row, RangeCalculationBehaviour behaviour) - { - address = address.ToUpper(CultureInfo.InvariantCulture); - var alphaPart = GetAlphaPart(address); - col = 0; - var nLettersInAlphabet = 26; - for (int x = 0; x < alphaPart.Length; x++) - { - var pos = alphaPart.Length - x - 1; - var currentNumericValue = GetNumericAlphaValue(alphaPart[x]); - col += (nLettersInAlphabet * pos * currentNumericValue); - if (pos == 0) - { - col += currentNumericValue; - } - } - //col--; - //row = GetIntPart(address) - 1 ?? GetRowIndexByBehaviour(behaviour); - row = GetIntPart(address) ?? GetRowIndexByBehaviour(behaviour); + /// <summary> + /// Translates an address in format "A1" to col- and rowindex. + /// + /// If the supplied address is a range, the address of the first part will be calculated. + /// </summary> + /// <param name="address"></param> + /// <param name="col"></param> + /// <param name="row"></param> + public virtual void ToColAndRow(string address, out int col, out int row) { + ToColAndRow(address, out col, out row, RangeCalculationBehaviour.FirstPart); + } - } - - private int GetRowIndexByBehaviour(RangeCalculationBehaviour behaviour) - { - if (behaviour == RangeCalculationBehaviour.FirstPart) - { - return 1; - } - return _excelDataProvider.ExcelMaxRows; - } - - private int GetNumericAlphaValue(char c) - { - return (int)c - 64; - } - - private string GetAlphaPart(string address) - { - return Regex.Match(address, "[A-Z]+").Value; - } - - private int? GetIntPart(string address) - { - if (Regex.IsMatch(address, "[0-9]+")) - { - return int.Parse(Regex.Match(address, "[0-9]+").Value); - } - return null; - } + /// <summary> + /// Translates an address in format "A1" to col- and rowindex. + /// </summary> + /// <param name="address"></param> + /// <param name="col"></param> + /// <param name="row"></param> + /// <param name="behaviour"></param> + public virtual void ToColAndRow( + string address, + out int col, + out int row, + RangeCalculationBehaviour behaviour) { + address = address.ToUpper(CultureInfo.InvariantCulture); + var alphaPart = GetAlphaPart(address); + col = 0; + var nLettersInAlphabet = 26; + for (int x = 0; x < alphaPart.Length; x++) { + var pos = alphaPart.Length - x - 1; + var currentNumericValue = GetNumericAlphaValue(alphaPart[x]); + col += (nLettersInAlphabet * pos * currentNumericValue); + if (pos == 0) { + col += currentNumericValue; + } } + //col--; + //row = GetIntPart(address) - 1 ?? GetRowIndexByBehaviour(behaviour); + row = GetIntPart(address) ?? GetRowIndexByBehaviour(behaviour); + } + + private int GetRowIndexByBehaviour(RangeCalculationBehaviour behaviour) { + if (behaviour == RangeCalculationBehaviour.FirstPart) { + return 1; + } + return _excelDataProvider.ExcelMaxRows; + } + + private int GetNumericAlphaValue(char c) { + return c - 64; + } + + private string GetAlphaPart(string address) { + return Regex.Match(address, "[A-Z]+").Value; + } + + private int? GetIntPart(string address) { + if (Regex.IsMatch(address, "[0-9]+")) { + return int.Parse(Regex.Match(address, "[0-9]+").Value); + } + return null; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs b/EPPlus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs index 77ca083..590d3e0 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/CellReferenceProvider.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,57 +13,51 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class CellReferenceProvider - { - public virtual IEnumerable<string> GetReferencedAddresses(string cellFormula, ParsingContext context) - { - var resultCells = new List<string>(); - var r = context.Configuration.Lexer.Tokenize(cellFormula, context.Scopes.Current.Address.Worksheet); - var toAddresses = r.Where(x => x.TokenType == TokenType.ExcelAddress); - foreach (var toAddress in toAddresses) - { - var rangeAddress = context.RangeAddressFactory.Create(toAddress.Value); - var rangeCells = new List<string>(); - if (rangeAddress.FromRow < rangeAddress.ToRow || rangeAddress.FromCol < rangeAddress.ToCol) - { - for (var col = rangeAddress.FromCol; col <= rangeAddress.ToCol; col++) - { - for (var row = rangeAddress.FromRow; row <= rangeAddress.ToRow; row++) - { - resultCells.Add(context.RangeAddressFactory.Create(col, row).Address); - } - } - } - else - { - rangeCells.Add(toAddress.Value); - } - resultCells.AddRange(rangeCells); - } - return resultCells; +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; + +public class CellReferenceProvider { + public virtual IEnumerable<string> GetReferencedAddresses( + string cellFormula, + ParsingContext context) { + var resultCells = new List<string>(); + var r = context.Configuration.Lexer.Tokenize( + cellFormula, + context.Scopes.Current.Address.Worksheet); + var toAddresses = r.Where(x => x.TokenType == TokenType.ExcelAddress); + foreach (var toAddress in toAddresses) { + var rangeAddress = context.RangeAddressFactory.Create(toAddress.Value); + var rangeCells = new List<string>(); + if (rangeAddress.FromRow < rangeAddress.ToRow || rangeAddress.FromCol < rangeAddress.ToCol) { + for (var col = rangeAddress.FromCol; col <= rangeAddress.ToCol; col++) { + for (var row = rangeAddress.FromRow; row <= rangeAddress.ToRow; row++) { + resultCells.Add(context.RangeAddressFactory.Create(col, row).Address); + } } + } else { + rangeCells.Add(toAddress.Value); + } + resultCells.AddRange(rangeCells); } + return resultCells; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs index f8ae9fa..afba2c1 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressInfo.cs
@@ -13,82 +13,59 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class ExcelAddressInfo - { - private ExcelAddressInfo(string address) - { - var addressOnSheet = address; - Worksheet = string.Empty; - if (address.Contains("!")) - { - var worksheetArr = address.Split('!'); - Worksheet = worksheetArr[0]; - addressOnSheet = worksheetArr[1]; - } - if (addressOnSheet.Contains(":")) - { - var rangeArr = addressOnSheet.Split(':'); - StartCell = rangeArr[0]; - EndCell = rangeArr[1]; - } - else - { - StartCell = addressOnSheet; - } - AddressOnSheet = addressOnSheet; - } +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - public static ExcelAddressInfo Parse(string address) - { - Require.That(address).Named("address").IsNotNullOrEmpty(); - return new ExcelAddressInfo(address); - } - - public string Worksheet { get; private set; } - - public bool WorksheetIsSpecified - { - get - { - return !string.IsNullOrEmpty(Worksheet); - } - } - - public bool IsMultipleCells - { - get - { - return !string.IsNullOrEmpty(EndCell); - } - } - - public string StartCell { get; private set; } - - public string EndCell { get; private set; } - - public string AddressOnSheet { get; private set; } +public class ExcelAddressInfo { + private ExcelAddressInfo(string address) { + var addressOnSheet = address; + Worksheet = string.Empty; + if (address.Contains("!")) { + var worksheetArr = address.Split('!'); + Worksheet = worksheetArr[0]; + addressOnSheet = worksheetArr[1]; } + if (addressOnSheet.Contains(":")) { + var rangeArr = addressOnSheet.Split(':'); + StartCell = rangeArr[0]; + EndCell = rangeArr[1]; + } else { + StartCell = addressOnSheet; + } + AddressOnSheet = addressOnSheet; + } + + public static ExcelAddressInfo Parse(string address) { + Require.That(address).Named("address").IsNotNullOrEmpty(); + return new(address); + } + + public string Worksheet { get; private set; } + + public bool WorksheetIsSpecified => !string.IsNullOrEmpty(Worksheet); + + public bool IsMultipleCells => !string.IsNullOrEmpty(EndCell); + + public string StartCell { get; private set; } + + public string EndCell { get; private set; } + + public string AddressOnSheet { get; private set; } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs index 71a301f..75ad665 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/ExcelAddressUtil.cs
@@ -13,59 +13,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public static class ExcelAddressUtil - { - static char[] SheetNameInvalidChars = new char[] { '?', ':', '*', '/', '\\' }; - public static bool IsValidAddress(string token) - { - int ix; - if (token[0] == '\'') - { - ix = token.LastIndexOf('\''); - if (ix > 0 && ix < token.Length - 1 && token[ix + 1] == '!') - { - if (token.IndexOfAny(SheetNameInvalidChars, 1, ix - 1) > 0) - { - return false; - } - token = token.Substring(ix + 2); - } - else - { - return false; - } - } - else if ((ix = token.IndexOf('!')) > 1) - { - if (token.IndexOfAny(SheetNameInvalidChars, 0, token.IndexOf('!')) > 0) - { - return false; - } - token = token.Substring(token.IndexOf('!') + 1); - } - return OfficeOpenXml.ExcelAddress.IsValidAddress(token); +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; + +public static class ExcelAddressUtil { + private static char[] SheetNameInvalidChars = { '?', ':', '*', '/', '\\' }; + + public static bool IsValidAddress(string token) { + int ix; + if (token[0] == '\'') { + ix = token.LastIndexOf('\''); + if (ix > 0 && ix < token.Length - 1 && token[ix + 1] == '!') { + if (token.IndexOfAny(SheetNameInvalidChars, 1, ix - 1) > 0) { + return false; } + token = token.Substring(ix + 2); + } else { + return false; + } + } else if ((ix = token.IndexOf('!')) > 1) { + if (token.IndexOfAny(SheetNameInvalidChars, 0, token.IndexOf('!')) > 0) { + return false; + } + token = token.Substring(token.IndexOf('!') + 1); } + return ExcelCellBase.IsValidAddress(token); + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs index eb87236..9651a35 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/ExcelReferenceType.cs
@@ -13,33 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public enum ExcelReferenceType - { - AbsoluteRowAndColumn = 1, - AbsoluteRowRelativeColumn = 2, - RelativeRowAbsolutColumn = 3, - RelativeRowAndColumn = 4 - } +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; + +public enum ExcelReferenceType { + AbsoluteRowAndColumn = 1, + AbsoluteRowRelativeColumn = 2, + RelativeRowAbsolutColumn = 3, + RelativeRowAndColumn = 4, }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs b/EPPlus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs index 92d2e61..53cf288 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/ExpressionEvaluator.cs
@@ -13,133 +13,116 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; using System.Text.RegularExpressions; using OfficeOpenXml.FormulaParsing.Excel.Operators; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class ExpressionEvaluator - { - private readonly WildCardValueMatcher _wildCardValueMatcher; - private readonly CompileResultFactory _compileResultFactory; +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - public ExpressionEvaluator() - : this(new WildCardValueMatcher(), new CompileResultFactory()) - { +public class ExpressionEvaluator { + private readonly WildCardValueMatcher _wildCardValueMatcher; + private readonly CompileResultFactory _compileResultFactory; - } + public ExpressionEvaluator() + : this(new(), new()) {} - public ExpressionEvaluator(WildCardValueMatcher wildCardValueMatcher, CompileResultFactory compileResultFactory) - { - _wildCardValueMatcher = wildCardValueMatcher; - _compileResultFactory = compileResultFactory; - } + public ExpressionEvaluator( + WildCardValueMatcher wildCardValueMatcher, + CompileResultFactory compileResultFactory) { + _wildCardValueMatcher = wildCardValueMatcher; + _compileResultFactory = compileResultFactory; + } - private string GetNonAlphanumericStartChars(string expression) - { - if (!string.IsNullOrEmpty(expression)) - { - if (Regex.IsMatch(expression, @"^([^a-zA-Z0-9]{2})")) return expression.Substring(0, 2); - if (Regex.IsMatch(expression, @"^([^a-zA-Z0-9]{1})")) return expression.Substring(0, 1); - } - return null; - } - - private bool EvaluateOperator(object left, object right, IOperator op) - { - var leftResult = _compileResultFactory.Create(left); - var rightResult = _compileResultFactory.Create(right); - var result = op.Apply(leftResult, rightResult); - if (result.DataType != DataType.Boolean) - { - throw new ArgumentException("Illegal operator in expression"); - } - return (bool)result.Result; - } - - public bool TryConvertToDouble(object op, out double d) - { - if (op is double || op is int) - { - d = Convert.ToDouble(op); - return true; - } - else if (op is DateTime) - { - d = ((DateTime) op).ToOADate(); - return true; - } - else if (op != null) - { - if (double.TryParse(op.ToString(), out d)) - { - return true; - } - } - d = 0; - return false; - } - - public bool Evaluate(object left, string expression) - { - if (expression == string.Empty) - { - return left == null; - } - var operatorCandidate = GetNonAlphanumericStartChars(expression); - if (!string.IsNullOrEmpty(operatorCandidate) && operatorCandidate != "-") - { - IOperator op; - if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out op)) - { - var right = expression.Replace(operatorCandidate, string.Empty); - if (left == null && right == string.Empty) - { - return op.Operator == Operators.Equals; - } - if (left == null ^ right == string.Empty) - { - return op.Operator == Operators.NotEqualTo; - } - double leftNum, rightNum; - DateTime date; - bool leftIsNumeric = TryConvertToDouble(left, out leftNum); - bool rightIsNumeric = double.TryParse(right, out rightNum); - bool rightIsDate = DateTime.TryParse(right, out date); - if (leftIsNumeric && rightIsNumeric) - { - return EvaluateOperator(leftNum, rightNum, op); - } - if (leftIsNumeric && rightIsDate) - { - return EvaluateOperator(leftNum, date.ToOADate(), op); - } - if (leftIsNumeric != rightIsNumeric) - { - return op.Operator == Operators.NotEqualTo; - } - return EvaluateOperator(left, right, op); - } - } - return _wildCardValueMatcher.IsMatch(expression, left) == 0; - } + private string GetNonAlphanumericStartChars(string expression) { + if (!string.IsNullOrEmpty(expression)) { + if (Regex.IsMatch(expression, "^([^a-zA-Z0-9]{2})")) { + return expression.Substring(0, 2); + } + if (Regex.IsMatch(expression, "^([^a-zA-Z0-9]{1})")) { + return expression.Substring(0, 1); + } } + return null; + } + + private bool EvaluateOperator(object left, object right, IOperator op) { + var leftResult = _compileResultFactory.Create(left); + var rightResult = _compileResultFactory.Create(right); + var result = op.Apply(leftResult, rightResult); + if (result.DataType != DataType.Boolean) { + throw new ArgumentException("Illegal operator in expression"); + } + return (bool)result.Result; + } + + public bool TryConvertToDouble(object op, out double d) { + if (op is double || op is int) { + d = Convert.ToDouble(op); + return true; + } + if (op is DateTime) { + d = ((DateTime)op).ToOADate(); + return true; + } + if (op != null) { + if (double.TryParse(op.ToString(), out d)) { + return true; + } + } + d = 0; + return false; + } + + public bool Evaluate(object left, string expression) { + if (expression == string.Empty) { + return left == null; + } + var operatorCandidate = GetNonAlphanumericStartChars(expression); + if (!string.IsNullOrEmpty(operatorCandidate) && operatorCandidate != "-") { + IOperator op; + if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out op)) { + var right = expression.Replace(operatorCandidate, string.Empty); + if (left == null && right == string.Empty) { + return op.Operator == Operators.Equals; + } + if (left == null ^ right == string.Empty) { + return op.Operator == Operators.NotEqualTo; + } + double leftNum, + rightNum; + DateTime date; + bool leftIsNumeric = TryConvertToDouble(left, out leftNum); + bool rightIsNumeric = double.TryParse(right, out rightNum); + bool rightIsDate = DateTime.TryParse(right, out date); + if (leftIsNumeric && rightIsNumeric) { + return EvaluateOperator(leftNum, rightNum, op); + } + if (leftIsNumeric && rightIsDate) { + return EvaluateOperator(leftNum, date.ToOADate(), op); + } + if (leftIsNumeric != rightIsNumeric) { + return op.Operator == Operators.NotEqualTo; + } + return EvaluateOperator(left, right, op); + } + } + return _wildCardValueMatcher.IsMatch(expression, left) == 0; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs index 3025aa9..b5bc0cf 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencies.cs
@@ -13,70 +13,59 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class FormulaDependencies - { - public FormulaDependencies() - : this(new FormulaDependencyFactory()) - { +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - } +public class FormulaDependencies { + public FormulaDependencies() + : this(new()) {} - public FormulaDependencies(FormulaDependencyFactory formulaDependencyFactory) - { - _formulaDependencyFactory = formulaDependencyFactory; - } + public FormulaDependencies(FormulaDependencyFactory formulaDependencyFactory) { + _formulaDependencyFactory = formulaDependencyFactory; + } - private readonly FormulaDependencyFactory _formulaDependencyFactory; - private readonly Dictionary<string, FormulaDependency> _dependencies = new Dictionary<string, FormulaDependency>(); + private readonly FormulaDependencyFactory _formulaDependencyFactory; + private readonly Dictionary<string, FormulaDependency> _dependencies = new(); - public IEnumerable<KeyValuePair<string, FormulaDependency>> Dependencies { get { return _dependencies; } } + public IEnumerable<KeyValuePair<string, FormulaDependency>> Dependencies => _dependencies; - public void AddFormulaScope(ParsingScope parsingScope) - { - //var dependency = _formulaDependencyFactory.Create(parsingScope); - //var address = parsingScope.Address.ToString(); - //if (!_dependencies.ContainsKey(address)) - //{ - // _dependencies.Add(address, dependency); - //} - //if (parsingScope.Parent != null) - //{ - // var parentAddress = parsingScope.Parent.Address.ToString(); - // if (_dependencies.ContainsKey(parentAddress)) - // { - // var parent = _dependencies[parentAddress]; - // parent.AddReferenceTo(parsingScope.Address); - // dependency.AddReferenceFrom(parent.Address); - // } - //} - } + public void AddFormulaScope(ParsingScope parsingScope) { + //var dependency = _formulaDependencyFactory.Create(parsingScope); + //var address = parsingScope.Address.ToString(); + //if (!_dependencies.ContainsKey(address)) + //{ + // _dependencies.Add(address, dependency); + //} + //if (parsingScope.Parent != null) + //{ + // var parentAddress = parsingScope.Parent.Address.ToString(); + // if (_dependencies.ContainsKey(parentAddress)) + // { + // var parent = _dependencies[parentAddress]; + // parent.AddReferenceTo(parsingScope.Address); + // dependency.AddReferenceFrom(parent.Address); + // } + //} + } - public void Clear() - { - _dependencies.Clear(); - } - } + public void Clear() { + _dependencies.Clear(); + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependency.cs b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependency.cs index da6fb9d..c337019 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependency.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependency.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,60 +13,55 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class FormulaDependency - { - public FormulaDependency(ParsingScope scope) - { - ScopeId = scope.ScopeId; - Address = scope.Address; - } - public Guid ScopeId { get; private set; } +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - public RangeAddress Address { get; private set; } +public class FormulaDependency { + public FormulaDependency(ParsingScope scope) { + ScopeId = scope.ScopeId; + Address = scope.Address; + } - private List<RangeAddress> _referencedBy = new List<RangeAddress>(); + public Guid ScopeId { get; private set; } - private List<RangeAddress> _references = new List<RangeAddress>(); + public RangeAddress Address { get; private set; } - public virtual void AddReferenceFrom(RangeAddress rangeAddress) - { - if (Address.CollidesWith(rangeAddress) || _references.Exists(x => x.CollidesWith(rangeAddress))) - { - throw new CircularReferenceException("Circular reference detected at " + rangeAddress.ToString()); - } - _referencedBy.Add(rangeAddress); - } + private List<RangeAddress> _referencedBy = new(); - public virtual void AddReferenceTo(RangeAddress rangeAddress) - { - if (Address.CollidesWith(rangeAddress) || _referencedBy.Exists(x => x.CollidesWith(rangeAddress))) - { - throw new CircularReferenceException("Circular reference detected at " + rangeAddress.ToString()); - } - _references.Add(rangeAddress); - } + private List<RangeAddress> _references = new(); + + public virtual void AddReferenceFrom(RangeAddress rangeAddress) { + if (Address.CollidesWith(rangeAddress) + || _references.Exists(x => x.CollidesWith(rangeAddress))) { + throw new CircularReferenceException("Circular reference detected at " + rangeAddress); } + _referencedBy.Add(rangeAddress); + } + + public virtual void AddReferenceTo(RangeAddress rangeAddress) { + if (Address.CollidesWith(rangeAddress) + || _referencedBy.Exists(x => x.CollidesWith(rangeAddress))) { + throw new CircularReferenceException("Circular reference detected at " + rangeAddress); + } + _references.Add(rangeAddress); + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs index a6e6205..9eb1f6d 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/FormulaDependencyFactory.cs
@@ -13,33 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class FormulaDependencyFactory - { - public virtual FormulaDependency Create(ParsingScope scope) - { - return new FormulaDependency(scope); - } - } +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; + +public class FormulaDependencyFactory { + public virtual FormulaDependency Create(ParsingScope scope) { + return new(scope); + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs b/EPPlus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs index d1de754..238743a 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/IndexToAddressTranslator.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,90 +13,74 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing; + using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class IndexToAddressTranslator - { - public IndexToAddressTranslator(ExcelDataProvider excelDataProvider) - : this(excelDataProvider, ExcelReferenceType.AbsoluteRowAndColumn) - { +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - } +public class IndexToAddressTranslator { + public IndexToAddressTranslator(ExcelDataProvider excelDataProvider) + : this(excelDataProvider, ExcelReferenceType.AbsoluteRowAndColumn) {} - public IndexToAddressTranslator(ExcelDataProvider excelDataProvider, ExcelReferenceType referenceType) - { - Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); - _excelDataProvider = excelDataProvider; - _excelReferenceType = referenceType; - } + public IndexToAddressTranslator( + ExcelDataProvider excelDataProvider, + ExcelReferenceType referenceType) { + Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); + _excelDataProvider = excelDataProvider; + _excelReferenceType = referenceType; + } - private readonly ExcelDataProvider _excelDataProvider; - private readonly ExcelReferenceType _excelReferenceType; + private readonly ExcelDataProvider _excelDataProvider; + private readonly ExcelReferenceType _excelReferenceType; - protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) - { - - if (iColumnNumber < 1) - { - //throw new Exception("Column number is out of range"); - return "#REF!"; - } - - string sCol = ""; - do - { - sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol; - iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26; - } - while (iColumnNumber > 0); - return fixedCol ? "$" + sCol : sCol; - } - - public string ToAddress(int col, int row) - { - var fixedCol = _excelReferenceType == ExcelReferenceType.AbsoluteRowAndColumn || - _excelReferenceType == ExcelReferenceType.RelativeRowAbsolutColumn; - var colString = GetColumnLetter(col, fixedCol); - return colString + GetRowNumber(row); - } - - private string GetRowNumber(int rowNo) - { - var retVal = rowNo < (_excelDataProvider.ExcelMaxRows) ? rowNo.ToString() : string.Empty; - if (!string.IsNullOrEmpty(retVal)) - { - switch (_excelReferenceType) - { - case ExcelReferenceType.AbsoluteRowAndColumn: - case ExcelReferenceType.AbsoluteRowRelativeColumn: - return "$" + retVal; - default: - return retVal; - } - } - return retVal; - } + protected internal static string GetColumnLetter(int iColumnNumber, bool fixedCol) { + if (iColumnNumber < 1) { + //throw new Exception("Column number is out of range"); + return "#REF!"; } + + string sCol = ""; + do { + sCol = ((char)('A' + ((iColumnNumber - 1) % 26))) + sCol; + iColumnNumber = (iColumnNumber - ((iColumnNumber - 1) % 26)) / 26; + } while (iColumnNumber > 0); + return fixedCol ? "$" + sCol : sCol; + } + + public string ToAddress(int col, int row) { + var fixedCol = + _excelReferenceType == ExcelReferenceType.AbsoluteRowAndColumn + || _excelReferenceType == ExcelReferenceType.RelativeRowAbsolutColumn; + var colString = GetColumnLetter(col, fixedCol); + return colString + GetRowNumber(row); + } + + private string GetRowNumber(int rowNo) { + var retVal = rowNo < (_excelDataProvider.ExcelMaxRows) ? rowNo.ToString() : string.Empty; + if (!string.IsNullOrEmpty(retVal)) { + switch (_excelReferenceType) { + case ExcelReferenceType.AbsoluteRowAndColumn: + case ExcelReferenceType.AbsoluteRowRelativeColumn: + return "$" + retVal; + default: + return retVal; + } + } + return retVal; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs b/EPPlus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs index 41200ca..d2e0f3e 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/LookupValueMatcher.cs
@@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class LookupValueMatcher : ValueMatcher - { - protected override int CompareObjectToString(object o1, string o2) - { - return IncompatibleOperands; - } - } +public class LookupValueMatcher : ValueMatcher { + protected override int CompareObjectToString(object o1, string o2) { + return IncompatibleOperands; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs b/EPPlus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs index b5a1094..31b6f2a 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/NumericExpressionEvaluator.cs
@@ -13,101 +13,87 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; using System.Text.RegularExpressions; using OfficeOpenXml.FormulaParsing.Excel.Operators; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class NumericExpressionEvaluator - { - private ValueMatcher _valueMatcher; - private CompileResultFactory _compileResultFactory; +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - public NumericExpressionEvaluator() - : this(new ValueMatcher(), new CompileResultFactory()) - { +public class NumericExpressionEvaluator { + private ValueMatcher _valueMatcher; + private CompileResultFactory _compileResultFactory; - } + public NumericExpressionEvaluator() + : this(new(), new()) {} - public NumericExpressionEvaluator(ValueMatcher valueMatcher, CompileResultFactory compileResultFactory) - { - _valueMatcher = valueMatcher; - _compileResultFactory = compileResultFactory; - } + public NumericExpressionEvaluator( + ValueMatcher valueMatcher, + CompileResultFactory compileResultFactory) { + _valueMatcher = valueMatcher; + _compileResultFactory = compileResultFactory; + } - private string GetNonNumericStartChars(string expression) - { - if (!string.IsNullOrEmpty(expression)) - { - if (Regex.IsMatch(expression, @"^([^\d]{2})")) return expression.Substring(0, 2); - if (Regex.IsMatch(expression, @"^([^\d]{1})")) return expression.Substring(0, 1); - } - return null; - } - - public double? OperandAsDouble(object op) - { - if (op is double || op is int) - { - return Convert.ToDouble(op); - } - if (op != null) - { - double output; - if (double.TryParse(op.ToString(), out output)) - { - return output; - } - } - return null; - } - - public bool Evaluate(object left, string expression) - { - var operatorCandidate = GetNonNumericStartChars(expression); - var leftNum = OperandAsDouble(left); - if (!string.IsNullOrEmpty(operatorCandidate) && leftNum != null) - { - IOperator op; - if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out op)) - { - var numericCandidate = expression.Replace(operatorCandidate, string.Empty); - double d; - if (double.TryParse(numericCandidate, out d)) - { - var leftResult = _compileResultFactory.Create(leftNum); - var rightResult = _compileResultFactory.Create(d); - var result = op.Apply(leftResult, rightResult); - if (result.DataType != DataType.Boolean) - { - throw new ArgumentException("Illegal operator in expression"); - } - return (bool)result.Result; - } - } - } - return _valueMatcher.IsMatch(left, expression) == 0; - } + private string GetNonNumericStartChars(string expression) { + if (!string.IsNullOrEmpty(expression)) { + if (Regex.IsMatch(expression, @"^([^\d]{2})")) { + return expression.Substring(0, 2); + } + if (Regex.IsMatch(expression, @"^([^\d]{1})")) { + return expression.Substring(0, 1); + } } + return null; + } + + public double? OperandAsDouble(object op) { + if (op is double || op is int) { + return Convert.ToDouble(op); + } + if (op != null) { + double output; + if (double.TryParse(op.ToString(), out output)) { + return output; + } + } + return null; + } + + public bool Evaluate(object left, string expression) { + var operatorCandidate = GetNonNumericStartChars(expression); + var leftNum = OperandAsDouble(left); + if (!string.IsNullOrEmpty(operatorCandidate) && leftNum != null) { + IOperator op; + if (OperatorsDict.Instance.TryGetValue(operatorCandidate, out op)) { + var numericCandidate = expression.Replace(operatorCandidate, string.Empty); + double d; + if (double.TryParse(numericCandidate, out d)) { + var leftResult = _compileResultFactory.Create(leftNum); + var rightResult = _compileResultFactory.Create(d); + var result = op.Apply(leftResult, rightResult); + if (result.DataType != DataType.Boolean) { + throw new ArgumentException("Illegal operator in expression"); + } + return (bool)result.Result; + } + } + } + return _valueMatcher.IsMatch(left, expression) == 0; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs index 114e80a..5a19ff9 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddress.cs
@@ -13,77 +13,64 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class RangeAddress - { - public RangeAddress() - { - Address = string.Empty; - } +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - internal string Address { get; set; } +public class RangeAddress { + public RangeAddress() { + Address = string.Empty; + } - public string Worksheet { get; internal set; } + internal string Address { get; set; } - public int FromCol { get; internal set; } + public string Worksheet { get; internal set; } - public int ToCol { get; internal set; } + public int FromCol { get; internal set; } - public int FromRow { get; internal set; } + public int ToCol { get; internal set; } - public int ToRow { get; internal set; } + public int FromRow { get; internal set; } - public override string ToString() - { - return Address; - } + public int ToRow { get; internal set; } - private static RangeAddress _empty = new RangeAddress(); - public static RangeAddress Empty - { - get { return _empty; } - } + public override string ToString() { + return Address; + } - /// <summary> - /// Returns true if this range collides (full or partly) with the supplied range - /// </summary> - /// <param name="other">The range to check</param> - /// <returns></returns> - public bool CollidesWith(RangeAddress other) - { - if (other.Worksheet != Worksheet) - { - return false; - } - if (other.FromRow > ToRow || other.FromCol > ToCol - || - FromRow > other.ToRow || FromCol > other.ToCol) - { - return false; - } - return true; - } + private static RangeAddress _empty = new(); + + public static RangeAddress Empty => _empty; + + /// <summary> + /// Returns true if this range collides (full or partly) with the supplied range + /// </summary> + /// <param name="other">The range to check</param> + /// <returns></returns> + public bool CollidesWith(RangeAddress other) { + if (other.Worksheet != Worksheet) { + return false; } + if (other.FromRow > ToRow + || other.FromCol > ToCol + || FromRow > other.ToRow + || FromCol > other.ToCol) { + return false; + } + return true; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs index 2e8b710..a2ae075 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/RangeAddressFactory.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,151 +13,144 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing; + using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class RangeAddressFactory - { - private readonly ExcelDataProvider _excelDataProvider; - private readonly AddressTranslator _addressTranslator; - private readonly IndexToAddressTranslator _indexToAddressTranslator; +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - public RangeAddressFactory(ExcelDataProvider excelDataProvider) - : this(excelDataProvider, new AddressTranslator(excelDataProvider), new IndexToAddressTranslator(excelDataProvider, ExcelReferenceType.RelativeRowAndColumn)) - { - - - } +public class RangeAddressFactory { + private readonly ExcelDataProvider _excelDataProvider; + private readonly AddressTranslator _addressTranslator; + private readonly IndexToAddressTranslator _indexToAddressTranslator; - public RangeAddressFactory(ExcelDataProvider excelDataProvider, AddressTranslator addressTranslator, IndexToAddressTranslator indexToAddressTranslator) - { - Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); - Require.That(addressTranslator).Named("addressTranslator").IsNotNull(); - Require.That(indexToAddressTranslator).Named("indexToAddressTranslator").IsNotNull(); - _excelDataProvider = excelDataProvider; - _addressTranslator = addressTranslator; - _indexToAddressTranslator = indexToAddressTranslator; - } + public RangeAddressFactory(ExcelDataProvider excelDataProvider) + : this( + excelDataProvider, + new(excelDataProvider), + new(excelDataProvider, ExcelReferenceType.RelativeRowAndColumn)) {} - public RangeAddress Create(int col, int row) - { - return Create(string.Empty, col, row); - } + public RangeAddressFactory( + ExcelDataProvider excelDataProvider, + AddressTranslator addressTranslator, + IndexToAddressTranslator indexToAddressTranslator) { + Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); + Require.That(addressTranslator).Named("addressTranslator").IsNotNull(); + Require.That(indexToAddressTranslator).Named("indexToAddressTranslator").IsNotNull(); + _excelDataProvider = excelDataProvider; + _addressTranslator = addressTranslator; + _indexToAddressTranslator = indexToAddressTranslator; + } - public RangeAddress Create(string worksheetName, int col, int row) - { - return new RangeAddress() - { - Address = _indexToAddressTranslator.ToAddress(col, row), - Worksheet = worksheetName, - FromCol = col, - ToCol = col, - FromRow = row, - ToRow = row - }; - } + public RangeAddress Create(int col, int row) { + return Create(string.Empty, col, row); + } - /// <summary> - /// - /// </summary> - /// <param name="worksheetName">will be used if no worksheet name is specified in <paramref name="address"/></param> - /// <param name="address">address of a range</param> - /// <returns></returns> - public RangeAddress Create(string worksheetName, string address) - { - Require.That(address).Named("range").IsNotNullOrEmpty(); - //var addressInfo = ExcelAddressInfo.Parse(address); - var adr = new ExcelAddressBase(address); - var sheet = string.IsNullOrEmpty(adr.WorkSheet) ? worksheetName : adr.WorkSheet; - var dim = _excelDataProvider.GetDimensionEnd(adr.WorkSheet); - var rangeAddress = new RangeAddress() - { - Address = adr.Address, - Worksheet = sheet, - FromRow = adr._fromRow, - FromCol = adr._fromCol, - ToRow = (dim != null && adr._toRow > dim.Row) ? dim.Row : adr._toRow, - ToCol = adr._toCol - }; + public RangeAddress Create(string worksheetName, int col, int row) { + return new() { + Address = _indexToAddressTranslator.ToAddress(col, row), + Worksheet = worksheetName, + FromCol = col, + ToCol = col, + FromRow = row, + ToRow = row, + }; + } - //if (addressInfo.IsMultipleCells) - //{ - // HandleMultipleCellAddress(rangeAddress, addressInfo); - //} - //else - //{ - // HandleSingleCellAddress(rangeAddress, addressInfo); - //} - return rangeAddress; - } + /// <summary> + /// + /// </summary> + /// <param name="worksheetName">will be used if no worksheet name is specified in <paramref name="address"/></param> + /// <param name="address">address of a range</param> + /// <returns></returns> + public RangeAddress Create(string worksheetName, string address) { + Require.That(address).Named("range").IsNotNullOrEmpty(); + //var addressInfo = ExcelAddressInfo.Parse(address); + var adr = new ExcelAddressBase(address); + var sheet = string.IsNullOrEmpty(adr.WorkSheet) ? worksheetName : adr.WorkSheet; + var dim = _excelDataProvider.GetDimensionEnd(adr.WorkSheet); + var rangeAddress = new RangeAddress { + Address = adr.Address, + Worksheet = sheet, + FromRow = adr._fromRow, + FromCol = adr._fromCol, + ToRow = (dim != null && adr._toRow > dim.Row) ? dim.Row : adr._toRow, + ToCol = adr._toCol, + }; - public RangeAddress Create(string range) - { - Require.That(range).Named("range").IsNotNullOrEmpty(); - //var addressInfo = ExcelAddressInfo.Parse(range); - var adr = new ExcelAddressBase(range); - var rangeAddress = new RangeAddress() - { - Address = adr.Address, - Worksheet = adr.WorkSheet ?? "", - FromRow = adr._fromRow, - FromCol = adr._fromCol, - ToRow = adr._toRow, - ToCol = adr._toCol - }; - - //if (addressInfo.IsMultipleCells) - //{ - // HandleMultipleCellAddress(rangeAddress, addressInfo); - //} - //else - //{ - // HandleSingleCellAddress(rangeAddress, addressInfo); - //} - return rangeAddress; - } + //if (addressInfo.IsMultipleCells) + //{ + // HandleMultipleCellAddress(rangeAddress, addressInfo); + //} + //else + //{ + // HandleSingleCellAddress(rangeAddress, addressInfo); + //} + return rangeAddress; + } - private void HandleSingleCellAddress(RangeAddress rangeAddress, ExcelAddressInfo addressInfo) - { - int col, row; - _addressTranslator.ToColAndRow(addressInfo.StartCell, out col, out row); - rangeAddress.FromCol = col; - rangeAddress.ToCol = col; - rangeAddress.FromRow = row; - rangeAddress.ToRow = row; - } + public RangeAddress Create(string range) { + Require.That(range).Named("range").IsNotNullOrEmpty(); + //var addressInfo = ExcelAddressInfo.Parse(range); + var adr = new ExcelAddressBase(range); + var rangeAddress = new RangeAddress { + Address = adr.Address, + Worksheet = adr.WorkSheet ?? "", + FromRow = adr._fromRow, + FromCol = adr._fromCol, + ToRow = adr._toRow, + ToCol = adr._toCol, + }; - private void HandleMultipleCellAddress(RangeAddress rangeAddress, ExcelAddressInfo addressInfo) - { - int fromCol, fromRow; - _addressTranslator.ToColAndRow(addressInfo.StartCell, out fromCol, out fromRow); - int toCol, toRow; - _addressTranslator.ToColAndRow(addressInfo.EndCell, out toCol, out toRow, AddressTranslator.RangeCalculationBehaviour.LastPart); - rangeAddress.FromCol = fromCol; - rangeAddress.ToCol = toCol; - rangeAddress.FromRow = fromRow; - rangeAddress.ToRow = toRow; - } - } + //if (addressInfo.IsMultipleCells) + //{ + // HandleMultipleCellAddress(rangeAddress, addressInfo); + //} + //else + //{ + // HandleSingleCellAddress(rangeAddress, addressInfo); + //} + return rangeAddress; + } + + private void HandleSingleCellAddress(RangeAddress rangeAddress, ExcelAddressInfo addressInfo) { + int col, + row; + _addressTranslator.ToColAndRow(addressInfo.StartCell, out col, out row); + rangeAddress.FromCol = col; + rangeAddress.ToCol = col; + rangeAddress.FromRow = row; + rangeAddress.ToRow = row; + } + + private void HandleMultipleCellAddress(RangeAddress rangeAddress, ExcelAddressInfo addressInfo) { + int fromCol, + fromRow; + _addressTranslator.ToColAndRow(addressInfo.StartCell, out fromCol, out fromRow); + int toCol, + toRow; + _addressTranslator.ToColAndRow( + addressInfo.EndCell, + out toCol, + out toRow, + AddressTranslator.RangeCalculationBehaviour.LastPart); + rangeAddress.FromCol = fromCol; + rangeAddress.ToCol = toCol; + rangeAddress.FromRow = fromRow; + rangeAddress.ToRow = toRow; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/ValueMatcher.cs b/EPPlus/FormulaParsing/ExcelUtilities/ValueMatcher.cs index 2e8fd2a..aeb4a47 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/ValueMatcher.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/ValueMatcher.cs
@@ -13,98 +13,86 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class ValueMatcher - { - public const int IncompatibleOperands = -2; +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; - public virtual int IsMatch(object o1, object o2) - { - if (o1 != null && o2 == null) return 1; - if (o1 == null && o2 != null) return -1; - if (o1 == null && o2 == null) return 0; - //Handle ranges and defined names - o1 = CheckGetRange(o1); - o2 = CheckGetRange(o2); +public class ValueMatcher { + public const int IncompatibleOperands = -2; - if (o1 is string && o2 is string) - { - return CompareStringToString(o1.ToString().ToLower(), o2.ToString().ToLower()); - } - else if( o1.GetType() == typeof(string)) - { - return CompareStringToObject(o1.ToString(), o2); - } - else if (o2.GetType() == typeof(string)) - { - return CompareObjectToString(o1, o2.ToString()); - } - return Convert.ToDouble(o1).CompareTo(Convert.ToDouble(o2)); - } - - private static object CheckGetRange(object v) - { - if (v is ExcelDataProvider.IRangeInfo) - { - var r = ((ExcelDataProvider.IRangeInfo)v); - if (r.GetNCells() > 1) - { - v = ExcelErrorValue.Create(eErrorType.NA); - } - v = r.GetOffset(0, 0); - } - else if (v is ExcelDataProvider.INameInfo) - { - var n = ((ExcelDataProvider.INameInfo)v); - v = CheckGetRange(n); - } - return v; - } - - protected virtual int CompareStringToString(string s1, string s2) - { - return s1.CompareTo(s2); - } - - protected virtual int CompareStringToObject(string o1, object o2) - { - double d1; - if (double.TryParse(o1, out d1)) - { - return d1.CompareTo(Convert.ToDouble(o2)); - } - return IncompatibleOperands; - } - - protected virtual int CompareObjectToString(object o1, string o2) - { - double d2; - if (double.TryParse(o2, out d2)) - { - return Convert.ToDouble(o1).CompareTo(d2); - } - return IncompatibleOperands; - } + public virtual int IsMatch(object o1, object o2) { + if (o1 != null && o2 == null) { + return 1; } + if (o1 == null && o2 != null) { + return -1; + } + if (o1 == null && o2 == null) { + return 0; + } + //Handle ranges and defined names + o1 = CheckGetRange(o1); + o2 = CheckGetRange(o2); + + if (o1 is string && o2 is string) { + return CompareStringToString(o1.ToString().ToLower(), o2.ToString().ToLower()); + } + if (o1.GetType() == typeof(string)) { + return CompareStringToObject(o1.ToString(), o2); + } + if (o2.GetType() == typeof(string)) { + return CompareObjectToString(o1, o2.ToString()); + } + return Convert.ToDouble(o1).CompareTo(Convert.ToDouble(o2)); + } + + private static object CheckGetRange(object v) { + if (v is ExcelDataProvider.IRangeInfo) { + var r = ((ExcelDataProvider.IRangeInfo)v); + if (r.GetNCells() > 1) { + v = ExcelErrorValue.Create(eErrorType.Na); + } + v = r.GetOffset(0, 0); + } else if (v is ExcelDataProvider.INameInfo) { + var n = ((ExcelDataProvider.INameInfo)v); + v = CheckGetRange(n); + } + return v; + } + + protected virtual int CompareStringToString(string s1, string s2) { + return s1.CompareTo(s2); + } + + protected virtual int CompareStringToObject(string o1, object o2) { + double d1; + if (double.TryParse(o1, out d1)) { + return d1.CompareTo(Convert.ToDouble(o2)); + } + return IncompatibleOperands; + } + + protected virtual int CompareObjectToString(object o1, string o2) { + double d2; + if (double.TryParse(o2, out d2)) { + return Convert.ToDouble(o1).CompareTo(d2); + } + return IncompatibleOperands; + } }
diff --git a/EPPlus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs b/EPPlus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs index bfdbb51..15a1754 100644 --- a/EPPlus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs +++ b/EPPlus/FormulaParsing/ExcelUtilities/WildCardValueMatcher.cs
@@ -13,45 +13,37 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using System.Text.RegularExpressions; -namespace OfficeOpenXml.FormulaParsing.ExcelUtilities -{ - public class WildCardValueMatcher : ValueMatcher - { - protected override int CompareStringToString(string s1, string s2) - { - if (s1.Contains("*") || s1.Contains("?")) - { - var regexPattern = Regex.Escape(s1); - regexPattern = string.Format("^{0}$", regexPattern); - regexPattern = regexPattern.Replace(@"\*", ".*"); - regexPattern = regexPattern.Replace(@"\?", "."); - if (Regex.IsMatch(s2, regexPattern)) - { - return 0; - } - } - return base.CompareStringToString(s1, s2); - } +namespace OfficeOpenXml.FormulaParsing.ExcelUtilities; + +public class WildCardValueMatcher : ValueMatcher { + protected override int CompareStringToString(string s1, string s2) { + if (s1.Contains("*") || s1.Contains("?")) { + var regexPattern = Regex.Escape(s1); + regexPattern = string.Format("^{0}$", regexPattern); + regexPattern = regexPattern.Replace(@"\*", ".*"); + regexPattern = regexPattern.Replace(@"\?", "."); + if (Regex.IsMatch(s2, regexPattern)) { + return 0; + } } + return base.CompareStringToString(s1, s2); + } }
diff --git a/EPPlus/FormulaParsing/ExcelValues.cs b/EPPlus/FormulaParsing/ExcelValues.cs index 57be38f..d8fceeb 100644 --- a/EPPlus/FormulaParsing/ExcelValues.cs +++ b/EPPlus/FormulaParsing/ExcelValues.cs
@@ -1,207 +1,206 @@ -using System; +using System; using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Text; -namespace OfficeOpenXml -{ +namespace OfficeOpenXml; + +/// <summary> +/// Represents the errortypes in excel +/// </summary> +public enum eErrorType { + /// <summary> + /// Division by zero + /// </summary> + Div0, + + /// <summary> + /// Not applicable + /// </summary> + Na, + + /// <summary> + /// Name error + /// </summary> + Name, + + /// <summary> + /// Null error + /// </summary> + Null, + + /// <summary> + /// Num error + /// </summary> + Num, + + /// <summary> + /// Reference error + /// </summary> + Ref, + + /// <summary> + /// Value error + /// </summary> + Value, + + // Bug G0004 + /// <summary> + /// Error error // Google Bug G0004 + /// </summary> + Error, + + // Bug G0005 + /// <summary> + /// ErrorValueIsNullOrEmpty error // Google Bug G0005 + /// </summary> + ErrorValueIsNullOrEmpty, +} + +/// <summary> +/// Represents an Excel error. +/// </summary> +/// <seealso cref="eErrorType"/> +public class ExcelErrorValue { + /// <summary> + /// Handles the convertion between <see cref="eErrorType"/> and the string values + /// used by Excel. + /// </summary> + public static class Values { + public const string Div0 = "#DIV/0!"; + public const string Na = "#N/A"; + public const string Name = "#NAME?"; + public const string Null = "#NULL!"; + public const string Num = "#NUM!"; + public const string Ref = "#REF!"; + public const string Value = "#VALUE!"; + public const string Error = "#ERROR!"; // Bug G0004 + public const string ErrorValueIsNullOrEmpty = "#ERRORVALUEISNULLOREMPTY!"; // Bug G0005 + + private static Dictionary<string, eErrorType> _values = new() { + { Div0, eErrorType.Div0 }, + { Na, eErrorType.Na }, + { Name, eErrorType.Name }, + { Null, eErrorType.Null }, + { Num, eErrorType.Num }, + { Ref, eErrorType.Ref }, + { Value, eErrorType.Value }, + { Error, eErrorType.Error }, // Bug G0004 + { + ErrorValueIsNullOrEmpty, + eErrorType.ErrorValueIsNullOrEmpty + } // Bug G0005 + , + }; + /// <summary> - /// Represents the errortypes in excel + /// Returns true if the supplied <paramref name="candidate"/> is an excel error. /// </summary> - public enum eErrorType - { - /// <summary> - /// Division by zero - /// </summary> - Div0, - /// <summary> - /// Not applicable - /// </summary> - NA, - /// <summary> - /// Name error - /// </summary> - Name, - /// <summary> - /// Null error - /// </summary> - Null, - /// <summary> - /// Num error - /// </summary> - Num, - /// <summary> - /// Reference error - /// </summary> - Ref, - /// <summary> - /// Value error - /// </summary> - Value, - // Bug G0004 - /// <summary> - /// Error error // Google Bug G0004 - /// </summary> - Error, - // Bug G0005 - /// <summary> - /// ErrorValueIsNullOrEmpty error // Google Bug G0005 - /// </summary> - ErrorValueIsNullOrEmpty + /// <param name="candidate"></param> + /// <returns></returns> + public static bool IsErrorValue(object candidate) { + if (candidate == null || !(candidate is ExcelErrorValue)) { + return false; + } + var candidateString = candidate.ToString(); + return (!string.IsNullOrEmpty(candidateString) && _values.ContainsKey(candidateString)); } /// <summary> - /// Represents an Excel error. + /// Returns true if the supplied <paramref name="candidate"/> is an excel error. /// </summary> - /// <seealso cref="eErrorType"/> - public class ExcelErrorValue - { - /// <summary> - /// Handles the convertion between <see cref="eErrorType"/> and the string values - /// used by Excel. - /// </summary> - public static class Values - { - public const string Div0 = "#DIV/0!"; - public const string NA = "#N/A"; - public const string Name = "#NAME?"; - public const string Null = "#NULL!"; - public const string Num = "#NUM!"; - public const string Ref = "#REF!"; - public const string Value = "#VALUE!"; - public const string Error = "#ERROR!"; // Bug G0004 - public const string ErrorValueIsNullOrEmpty = "#ERRORVALUEISNULLOREMPTY!"; // Bug G0005 - - private static Dictionary<string, eErrorType> _values = new Dictionary<string, eErrorType>() - { - {Div0, eErrorType.Div0}, - {NA, eErrorType.NA}, - {Name, eErrorType.Name}, - {Null, eErrorType.Null}, - {Num, eErrorType.Num}, - {Ref, eErrorType.Ref}, - {Value, eErrorType.Value}, - {Error, eErrorType.Error}, // Bug G0004 - {ErrorValueIsNullOrEmpty, eErrorType.ErrorValueIsNullOrEmpty} // Bug G0005 - }; - - /// <summary> - /// Returns true if the supplied <paramref name="candidate"/> is an excel error. - /// </summary> - /// <param name="candidate"></param> - /// <returns></returns> - public static bool IsErrorValue(object candidate) - { - if(candidate == null || !(candidate is ExcelErrorValue)) return false; - var candidateString = candidate.ToString(); - return (!string.IsNullOrEmpty(candidateString) && _values.ContainsKey(candidateString)); - } - - /// <summary> - /// Returns true if the supplied <paramref name="candidate"/> is an excel error. - /// </summary> - /// <param name="candidate"></param> - /// <returns></returns> - public static bool StringIsErrorValue(string candidate) - { - return (!string.IsNullOrEmpty(candidate) && _values.ContainsKey(candidate)); - } - - /// <summary> - /// Converts a string to an <see cref="eErrorType"/> - /// </summary> - /// <param name="val"></param> - /// <returns></returns> - /// <exception cref="ArgumentException">Thrown if the supplied value is not an Excel error</exception> - public static eErrorType ToErrorType(string val) - { - if (string.IsNullOrEmpty(val) || !_values.ContainsKey(val)) - { - throw new ArgumentException("Invalid error code " + (val ?? "<empty>")); - } - return _values[val]; - } - } - - internal static ExcelErrorValue Create(eErrorType errorType) - { - return new ExcelErrorValue(errorType); - } - - internal static ExcelErrorValue Parse(string val) - { - if (string.IsNullOrEmpty(val)) // Google Bug G0005 - { - val = Values.ErrorValueIsNullOrEmpty; - } - - if (Values.StringIsErrorValue(val)) - { - return new ExcelErrorValue(Values.ToErrorType(val)); - } - if(string.IsNullOrEmpty(val)) throw new ArgumentNullException("val"); - throw new ArgumentException("Not a valid error value: " + val); - } - - private ExcelErrorValue(eErrorType type) - { - Type=type; - } - - /// <summary> - /// The error type - /// </summary> - public eErrorType Type { get; private set; } - - /// <summary> - /// Returns the string representation of the error type - /// </summary> - /// <returns></returns> - public override string ToString() - { - switch(Type) - { - case eErrorType.Div0: - return Values.Div0; - case eErrorType.NA: - return Values.NA; - case eErrorType.Name: - return Values.Name; - case eErrorType.Null: - return Values.Null; - case eErrorType.Num: - return Values.Num; - case eErrorType.Ref: - return Values.Ref; - case eErrorType.Value: - return Values.Value; - case eErrorType.Error: // Bug G0004 - return Values.Error; - case eErrorType.ErrorValueIsNullOrEmpty: // Bug G0005 - return Values.ErrorValueIsNullOrEmpty; - default: - throw(new ArgumentException("Invalid errortype")); - } - } - public static ExcelErrorValue operator +(object v1, ExcelErrorValue v2) - { - return v2; - } - public static ExcelErrorValue operator +(ExcelErrorValue v1, ExcelErrorValue v2) - { - return v1; - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - - public override bool Equals(object obj) - { - if (!(obj is ExcelErrorValue)) return false; - return ((ExcelErrorValue) obj).ToString() == this.ToString(); - } + /// <param name="candidate"></param> + /// <returns></returns> + public static bool StringIsErrorValue(string candidate) { + return (!string.IsNullOrEmpty(candidate) && _values.ContainsKey(candidate)); } + + /// <summary> + /// Converts a string to an <see cref="eErrorType"/> + /// </summary> + /// <param name="val"></param> + /// <returns></returns> + /// <exception cref="ArgumentException">Thrown if the supplied value is not an Excel error</exception> + public static eErrorType ToErrorType(string val) { + if (string.IsNullOrEmpty(val) || !_values.ContainsKey(val)) { + throw new ArgumentException("Invalid error code " + (val ?? "<empty>")); + } + return _values[val]; + } + } + + internal static ExcelErrorValue Create(eErrorType errorType) { + return new(errorType); + } + + internal static ExcelErrorValue Parse(string val) { + if (string.IsNullOrEmpty( + val)) // Google Bug G0005 + { + val = Values.ErrorValueIsNullOrEmpty; + } + + if (Values.StringIsErrorValue(val)) { + return new(Values.ToErrorType(val)); + } + if (string.IsNullOrEmpty(val)) { + throw new ArgumentNullException("val"); + } + throw new ArgumentException("Not a valid error value: " + val); + } + + private ExcelErrorValue(eErrorType type) { + Type = type; + } + + /// <summary> + /// The error type + /// </summary> + public eErrorType Type { get; private set; } + + /// <summary> + /// Returns the string representation of the error type + /// </summary> + /// <returns></returns> + public override string ToString() { + switch (Type) { + case eErrorType.Div0: + return Values.Div0; + case eErrorType.Na: + return Values.Na; + case eErrorType.Name: + return Values.Name; + case eErrorType.Null: + return Values.Null; + case eErrorType.Num: + return Values.Num; + case eErrorType.Ref: + return Values.Ref; + case eErrorType.Value: + return Values.Value; + case eErrorType.Error: // Bug G0004 + return Values.Error; + case eErrorType.ErrorValueIsNullOrEmpty: // Bug G0005 + return Values.ErrorValueIsNullOrEmpty; + default: + throw (new ArgumentException("Invalid errortype")); + } + } + + public static ExcelErrorValue operator +(object v1, ExcelErrorValue v2) { + return v2; + } + + public static ExcelErrorValue operator +(ExcelErrorValue v1, ExcelErrorValue v2) { + return v1; + } + + public override int GetHashCode() { + return base.GetHashCode(); + } + + public override bool Equals(object obj) { + if (!(obj is ExcelErrorValue)) { + return false; + } + return ((ExcelErrorValue)obj).ToString() == ToString(); + } }
diff --git a/EPPlus/FormulaParsing/Exceptions/CircularReferenceException.cs b/EPPlus/FormulaParsing/Exceptions/CircularReferenceException.cs index 5ffc5ed..90dad5b 100644 --- a/EPPlus/FormulaParsing/Exceptions/CircularReferenceException.cs +++ b/EPPlus/FormulaParsing/Exceptions/CircularReferenceException.cs
@@ -13,34 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Exceptions -{ - public class CircularReferenceException : Exception - { - public CircularReferenceException(string message) - : base(message) - { +namespace OfficeOpenXml.FormulaParsing.Exceptions; - } - } +public class CircularReferenceException : Exception { + public CircularReferenceException(string message) + : base(message) {} }
diff --git a/EPPlus/FormulaParsing/Exceptions/ExcelErrorCodes.cs b/EPPlus/FormulaParsing/Exceptions/ExcelErrorCodes.cs index 34333de..f182e8a 100644 --- a/EPPlus/FormulaParsing/Exceptions/ExcelErrorCodes.cs +++ b/EPPlus/FormulaParsing/Exceptions/ExcelErrorCodes.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,94 +13,73 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Exceptions -{ - public class ExcelErrorCodes - { - private ExcelErrorCodes(string code) - { - Code = code; - } +namespace OfficeOpenXml.FormulaParsing.Exceptions; - public string Code - { - get; - private set; - } +public class ExcelErrorCodes { + private ExcelErrorCodes(string code) { + Code = code; + } - public override int GetHashCode() - { - return Code.GetHashCode(); - } + public string Code { get; private set; } - public override bool Equals(object obj) - { - if (obj is ExcelErrorCodes) - { - return ((ExcelErrorCodes)obj).Code.Equals(Code); - } - return false; - } + public override int GetHashCode() { + return Code.GetHashCode(); + } - public static bool operator == (ExcelErrorCodes c1, ExcelErrorCodes c2) - { - return c1.Code.Equals(c2.Code); - } - - public static bool operator !=(ExcelErrorCodes c1, ExcelErrorCodes c2) - { - return !c1.Code.Equals(c2.Code); - } - - private static readonly IEnumerable<string> Codes = new List<string> { Value.Code, Name.Code, NoValueAvaliable.Code }; - - public static bool IsErrorCode(object valueToTest) - { - if (valueToTest == null) - { - return false; - } - var candidate = valueToTest.ToString(); - if (Codes.FirstOrDefault(x => x == candidate) != null) - { - return true; - } - return false; - } - - public static ExcelErrorCodes Value - { - get { return new ExcelErrorCodes("#VALUE!"); } - } - - public static ExcelErrorCodes Name - { - get { return new ExcelErrorCodes("#NAME?"); } - } - - public static ExcelErrorCodes NoValueAvaliable - { - get { return new ExcelErrorCodes("#N/A"); } - } + public override bool Equals(object obj) { + if (obj is ExcelErrorCodes) { + return ((ExcelErrorCodes)obj).Code.Equals(Code); } + return false; + } + + public static bool operator ==(ExcelErrorCodes c1, ExcelErrorCodes c2) { + return c1.Code.Equals(c2.Code); + } + + public static bool operator !=(ExcelErrorCodes c1, ExcelErrorCodes c2) { + return !c1.Code.Equals(c2.Code); + } + + private static readonly IEnumerable<string> Codes = new List<string> { + Value.Code, + Name.Code, + NoValueAvaliable.Code, + }; + + public static bool IsErrorCode(object valueToTest) { + if (valueToTest == null) { + return false; + } + var candidate = valueToTest.ToString(); + if (Codes.FirstOrDefault(x => x == candidate) != null) { + return true; + } + return false; + } + + public static ExcelErrorCodes Value => new("#VALUE!"); + + public static ExcelErrorCodes Name => new("#NAME?"); + + public static ExcelErrorCodes NoValueAvaliable => new("#N/A"); }
diff --git a/EPPlus/FormulaParsing/Exceptions/ExcelErrorValueException.cs b/EPPlus/FormulaParsing/Exceptions/ExcelErrorValueException.cs index dcc2239..4341ed0 100644 --- a/EPPlus/FormulaParsing/Exceptions/ExcelErrorValueException.cs +++ b/EPPlus/FormulaParsing/Exceptions/ExcelErrorValueException.cs
@@ -1,40 +1,27 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Exceptions -{ - /// <summary> - /// This Exception represents an Excel error. When this exception is thrown - /// from an Excel function, the ErrorValue code will be set as the value of the - /// parsed cell. - /// </summary> - /// <seealso cref="ExcelErrorValue"/> - public class ExcelErrorValueException : Exception - { - - public ExcelErrorValueException(ExcelErrorValue error) - : this(error.ToString(), error) - { - - } +namespace OfficeOpenXml.FormulaParsing.Exceptions; - public ExcelErrorValueException(string message, ExcelErrorValue error) - : base(message) - { - ErrorValue = error; - } +/// <summary> +/// This Exception represents an Excel error. When this exception is thrown +/// from an Excel function, the ErrorValue code will be set as the value of the +/// parsed cell. +/// </summary> +/// <seealso cref="ExcelErrorValue"/> +public class ExcelErrorValueException : Exception { + public ExcelErrorValueException(ExcelErrorValue error) + : this(error.ToString(), error) {} - public ExcelErrorValueException(eErrorType errorType) - : this(ExcelErrorValue.Create(errorType)) - { - - } + public ExcelErrorValueException(string message, ExcelErrorValue error) + : base(message) { + ErrorValue = error; + } - /// <summary> - /// The error value - /// </summary> - public ExcelErrorValue ErrorValue { get; private set; } - } + public ExcelErrorValueException(eErrorType errorType) + : this(ExcelErrorValue.Create(errorType)) {} + + /// <summary> + /// The error value + /// </summary> + public ExcelErrorValue ErrorValue { get; private set; } }
diff --git a/EPPlus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs b/EPPlus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs index 4c26ba8..f4852c0 100644 --- a/EPPlus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs +++ b/EPPlus/FormulaParsing/Exceptions/UnrecognizedTokenException.cs
@@ -13,35 +13,28 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing.Exceptions -{ - public class UnrecognizedTokenException : Exception - { - public UnrecognizedTokenException(Token token) - : base( "Unrecognized token: " + token.Value) - { +namespace OfficeOpenXml.FormulaParsing.Exceptions; - } - } +public class UnrecognizedTokenException : Exception { + public UnrecognizedTokenException(Token token) + : base("Unrecognized token: " + token.Value) {} }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/AtomicExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/AtomicExpression.cs index 5467137..0ad249e 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/AtomicExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/AtomicExpression.cs
@@ -13,39 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public abstract class AtomicExpression : Expression - { - public AtomicExpression(string expression) - : base(expression) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - } +public abstract class AtomicExpression : Expression { + public AtomicExpression(string expression) + : base(expression) {} - public override bool IsGroupedExpression - { - get { return false; } - } - } + public override bool IsGroupedExpression => false; }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/BooleanExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/BooleanExpression.cs index 216248f..dce6b0f 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/BooleanExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/BooleanExpression.cs
@@ -13,48 +13,37 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class BooleanExpression : AtomicExpression - { - private bool? _precompiledValue; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public BooleanExpression(string expression) - : base(expression) - { +public class BooleanExpression : AtomicExpression { + private bool? _precompiledValue; - } + public BooleanExpression(string expression) + : base(expression) {} - public BooleanExpression(bool value) - : base(value ? "true" : "false") - { - _precompiledValue = value; - } + public BooleanExpression(bool value) + : base(value ? "true" : "false") { + _precompiledValue = value; + } - public override CompileResult Compile() - { - var result = _precompiledValue ?? bool.Parse(ExpressionString); - return new CompileResult(result, DataType.Boolean); - } - } + public override CompileResult Compile() { + var result = _precompiledValue ?? bool.Parse(ExpressionString); + return new(result, DataType.Boolean); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs index 7abc32e..1014610 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileResult.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,147 +13,108 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; -using System.Text.RegularExpressions; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class CompileResult - { - private static CompileResult _empty = new CompileResult(null, DataType.Empty); - public static CompileResult Empty - { - get { return _empty; } - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public CompileResult(object result, DataType dataType) - { - Result = result; - DataType = dataType; - } +public class CompileResult { + private static CompileResult _empty = new(null, DataType.Empty); - public CompileResult(eErrorType errorType) - { - Result = ExcelErrorValue.Create(errorType); - DataType = DataType.ExcelError; - } + public static CompileResult Empty => _empty; - public CompileResult(ExcelErrorValue errorValue) - { - Require.Argument(errorValue).IsNotNull("errorValue"); - Result = errorValue; - DataType = DataType.ExcelError; - } - public object Result - { - get; - private set; - } - public object ResultValue - { - get - { - var r = Result as ExcelDataProvider.IRangeInfo; - if (r == null) - { - return Result; - } - else - { - return r.GetValue(r.Address._fromRow, r.Address._fromCol); - } - } - } - public double ResultNumeric - { - get - { - if (IsNumeric) - { - return Result == null ? 0 : Convert.ToDouble(Result); - } - else if(Result is DateTime) - { - return ((DateTime)Result).ToOADate(); - } - else if(Result is TimeSpan) - { - return new DateTime(((TimeSpan)Result).Ticks).ToOADate(); - } - else if (IsNumericString) - { - try - { - return double.Parse(Result.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture); - } - catch (Exception) - { - return 0; - } - } - else if (Result is ExcelDataProvider.IRangeInfo) - { - var c = ((ExcelDataProvider.IRangeInfo)Result).FirstOrDefault(); - if (c == null) - { - return 0; - } - else - { - return c.ValueDoubleLogical; - } - } - else - { - return 0; - } - } - } + public CompileResult(object result, DataType dataType) { + Result = result; + DataType = dataType; + } - public DataType DataType - { - get; - private set; - } - - public bool IsNumeric - { - get - { - return DataType == DataType.Decimal || DataType == DataType.Integer || DataType == DataType.Empty || DataType == DataType.Boolean || DataType == DataType.Date; - } - } + public CompileResult(eErrorType errorType) { + Result = ExcelErrorValue.Create(errorType); + DataType = DataType.ExcelError; + } - public bool IsNumericString - { - get - { - return DataType == DataType.String && ConvertUtil.IsNumericString(Result); - } - } + public CompileResult(ExcelErrorValue errorValue) { + Require.Argument(errorValue).IsNotNull("errorValue"); + Result = errorValue; + DataType = DataType.ExcelError; + } - public bool IsResultOfSubtotal { get; set; } + public object Result { get; private set; } - public bool IsHiddenCell { get; set; } + public object ResultValue { + get { + var r = Result as ExcelDataProvider.IRangeInfo; + if (r == null) { + return Result; + } + return r.GetValue(r.Address._fromRow, r.Address._fromCol); } + } + + public double ResultNumeric { + get { + if (IsNumeric) { + return Result == null ? 0 : Convert.ToDouble(Result); + } + if (Result is DateTime) { + return ((DateTime)Result).ToOADate(); + } + if (Result is TimeSpan) { + return new DateTime(((TimeSpan)Result).Ticks).ToOADate(); + } + if (IsNumericString) { + try { + return double.Parse(Result.ToString(), NumberStyles.Float, CultureInfo.InvariantCulture); + } catch (Exception) { + return 0; + } + } + if (Result is ExcelDataProvider.IRangeInfo) { + var c = ((ExcelDataProvider.IRangeInfo)Result).FirstOrDefault(); + if (c == null) { + return 0; + } + return c.ValueDoubleLogical; + } + return 0; + } + } + + public DataType DataType { get; private set; } + + public bool IsNumeric { + get { + return DataType == DataType.Decimal + || DataType == DataType.Integer + || DataType == DataType.Empty + || DataType == DataType.Boolean + || DataType == DataType.Date; + } + } + + public bool IsNumericString { + get { return DataType == DataType.String && ConvertUtil.IsNumericString(Result); } + } + + public bool IsResultOfSubtotal { get; set; } + + public bool IsHiddenCell { get; set; } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs index ab313c4..af6f09f 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileResultFactory.cs
@@ -13,66 +13,55 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class CompileResultFactory - { - public virtual CompileResult Create(object obj) - { - if ((obj is ExcelDataProvider.INameInfo)) - { - obj = ((ExcelDataProvider.INameInfo)obj).Value; - } - if (obj is ExcelDataProvider.IRangeInfo) - { - obj = ((ExcelDataProvider.IRangeInfo)obj).GetOffset(0, 0); - } - if (obj == null) return new CompileResult(null, DataType.Empty); - if (obj.GetType().Equals(typeof(string))) - { - return new CompileResult(obj, DataType.String); - } - if (obj.GetType().Equals(typeof(double)) || obj is decimal) - { - return new CompileResult(obj, DataType.Decimal); - } - if (obj.GetType().Equals(typeof(int)) || obj is long || obj is short) - { - return new CompileResult(obj, DataType.Integer); - } - if (obj.GetType().Equals(typeof(bool))) - { - return new CompileResult(obj, DataType.Boolean); - } - if (obj.GetType().Equals(typeof (ExcelErrorValue))) - { - return new CompileResult(obj, DataType.ExcelError); - } - if (obj.GetType().Equals(typeof(System.DateTime))) - { - return new CompileResult(((System.DateTime)obj).ToOADate(), DataType.Date); - } - throw new ArgumentException("Non supported type " + obj.GetType().FullName); - } +using System; + +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; + +public class CompileResultFactory { + public virtual CompileResult Create(object obj) { + if ((obj is ExcelDataProvider.INameInfo)) { + obj = ((ExcelDataProvider.INameInfo)obj).Value; } + if (obj is ExcelDataProvider.IRangeInfo) { + obj = ((ExcelDataProvider.IRangeInfo)obj).GetOffset(0, 0); + } + if (obj == null) { + return new(null, DataType.Empty); + } + if (obj.GetType().Equals(typeof(string))) { + return new(obj, DataType.String); + } + if (obj.GetType().Equals(typeof(double)) || obj is decimal) { + return new(obj, DataType.Decimal); + } + if (obj.GetType().Equals(typeof(int)) || obj is long || obj is short) { + return new(obj, DataType.Integer); + } + if (obj.GetType().Equals(typeof(bool))) { + return new(obj, DataType.Boolean); + } + if (obj.GetType().Equals(typeof(ExcelErrorValue))) { + return new(obj, DataType.ExcelError); + } + if (obj.GetType().Equals(typeof(DateTime))) { + return new(((DateTime)obj).ToOADate(), DataType.Date); + } + throw new ArgumentException("Non supported type " + obj.GetType().FullName); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs index 01138c0..0eab4ab 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategy.cs
@@ -13,37 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy -{ - public abstract class CompileStrategy - { - protected readonly Expression _expression; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy; - public CompileStrategy(Expression expression) - { - _expression = expression; - } +public abstract class CompileStrategy { + protected readonly Expression _expression; - public abstract Expression Compile(); - } + public CompileStrategy(Expression expression) { + _expression = expression; + } + + public abstract Expression Compile(); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs index 9d7fb1f..944a3bf 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/CompileStrategyFactory.cs
@@ -13,41 +13,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.Excel.Operators; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy -{ - public class CompileStrategyFactory : ICompileStrategyFactory - { - public CompileStrategy Create(Expression expression) - { - if (expression.Operator.Operator == Operators.Concat) - { - return new StringConcatStrategy(expression); - } - else - { - return new DefaultCompileStrategy(expression); - } - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy; + +public class CompileStrategyFactory : ICompileStrategyFactory { + public CompileStrategy Create(Expression expression) { + if (expression.Operator.Operator == Operators.Concat) { + return new StringConcatStrategy(expression); } + return new DefaultCompileStrategy(expression); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs index 3fd8155..27475d1 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/DefaultCompileStrategy.cs
@@ -13,38 +13,29 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy -{ - public class DefaultCompileStrategy : CompileStrategy - { - public DefaultCompileStrategy(Expression expression) - : base(expression) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy; - } - public override Expression Compile() - { - return _expression.MergeWithNext(); - } - } +public class DefaultCompileStrategy : CompileStrategy { + public DefaultCompileStrategy(Expression expression) + : base(expression) {} + + public override Expression Compile() { + return _expression.MergeWithNext(); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs index 26a5263..16a53a4 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/ICompileStrategyFactory.cs
@@ -13,30 +13,24 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy -{ - public interface ICompileStrategyFactory - { - CompileStrategy Create(Expression expression); - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy; + +public interface ICompileStrategyFactory { + CompileStrategy Create(Expression expression); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs index 9bc1134..4403ab8 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/CompileStrategy/StringConcatStrategy.cs
@@ -13,50 +13,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy -{ - public class StringConcatStrategy : CompileStrategy - { - public StringConcatStrategy(Expression expression) - : base(expression) - { - - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy; - public override Expression Compile() - { - var newExp = _expression is ExcelAddressExpression ? _expression : ExpressionConverter.Instance.ToStringExpression(_expression); - newExp.Prev = _expression.Prev; - newExp.Next = _expression.Next; - if (_expression.Prev != null) - { - _expression.Prev.Next = newExp; - } - if (_expression.Next != null) - { - _expression.Next.Prev = newExp; - } - return newExp.MergeWithNext(); - } +public class StringConcatStrategy : CompileStrategy { + public StringConcatStrategy(Expression expression) + : base(expression) {} + + public override Expression Compile() { + var newExp = + _expression is ExcelAddressExpression + ? _expression + : ExpressionConverter.Instance.ToStringExpression(_expression); + newExp.Prev = _expression.Prev; + newExp.Next = _expression.Next; + if (_expression.Prev != null) { + _expression.Prev.Next = newExp; } + if (_expression.Next != null) { + _expression.Next.Prev = newExp; + } + return newExp.MergeWithNext(); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs b/EPPlus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs index 17a9e0c..00fe9c6 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ConstantExpressions.cs
@@ -1,31 +1,22 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public static class ConstantExpressions - { - public static Expression Percent - { - get { return new ConstantExpression("Percent", () => new CompileResult(0.01, DataType.Decimal)); } - } - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public class ConstantExpression : AtomicExpression - { - private readonly Func<CompileResult> _factoryMethod; +public static class ConstantExpressions { + public static Expression Percent { + get { return new ConstantExpression("Percent", () => new(0.01, DataType.Decimal)); } + } +} - public ConstantExpression(string title, Func<CompileResult> factoryMethod) - : base(title) - { - _factoryMethod = factoryMethod; - } +public class ConstantExpression : AtomicExpression { + private readonly Func<CompileResult> _factoryMethod; - public override CompileResult Compile() - { - return _factoryMethod(); - } - } + public ConstantExpression(string title, Func<CompileResult> factoryMethod) + : base(title) { + _factoryMethod = factoryMethod; + } + + public override CompileResult Compile() { + return _factoryMethod(); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/DataType.cs b/EPPlus/FormulaParsing/ExpressionGraph/DataType.cs index b115b08..4751df3 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/DataType.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/DataType.cs
@@ -13,40 +13,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public enum DataType - { - Integer, - Decimal, - String, - Boolean, - Date, - Time, - Enumerable, - LookupArray, - ExcelAddress, - ExcelError, - Empty - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; + +public enum DataType { + Integer, + Decimal, + String, + Boolean, + Date, + Time, + Enumerable, + LookupArray, + ExcelAddress, + ExcelError, + Empty, }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/DateExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/DateExpression.cs index 056efc5..12e9342 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/DateExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/DateExpression.cs
@@ -13,41 +13,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class DateExpression : AtomicExpression - { - public DateExpression(string expression) - : base(expression) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - } +public class DateExpression : AtomicExpression { + public DateExpression(string expression) + : base(expression) {} - public override CompileResult Compile() - { - var date = double.Parse(ExpressionString,CultureInfo.InvariantCulture); - return new CompileResult(DateTime.FromOADate(date), DataType.Date); - } - } + public override CompileResult Compile() { + var date = double.Parse(ExpressionString, CultureInfo.InvariantCulture); + return new(DateTime.FromOADate(date), DataType.Date); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/DecimalExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/DecimalExpression.cs index 6e3ba50..9c32645 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/DecimalExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/DecimalExpression.cs
@@ -1,5 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Globalization; + /******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * @@ -15,61 +15,48 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System.Linq; -using System.Text; -using System.Globalization; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class DecimalExpression : AtomicExpression - { - private readonly double? _compiledValue; - private readonly bool _negate; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public DecimalExpression(string expression) - : this(expression, false) - { - - } +public class DecimalExpression : AtomicExpression { + private readonly double? _compiledValue; + private readonly bool _negate; - public DecimalExpression(string expression, bool negate) - : base(expression) - { - _negate = negate; - } + public DecimalExpression(string expression) + : this(expression, false) {} - public DecimalExpression(double compiledValue) - : base(compiledValue.ToString(CultureInfo.InvariantCulture)) - { - _compiledValue = compiledValue; - } + public DecimalExpression(string expression, bool negate) + : base(expression) { + _negate = negate; + } - public override CompileResult Compile() - { - double result = _compiledValue.HasValue ? _compiledValue.Value : double.Parse(ExpressionString, CultureInfo.InvariantCulture); - result = _negate ? result * -1 : result; - return new CompileResult(result, DataType.Decimal); - } + public DecimalExpression(double compiledValue) + : base(compiledValue.ToString(CultureInfo.InvariantCulture)) { + _compiledValue = compiledValue; + } - public bool IsNegated - { - get { return _negate; } - } + public override CompileResult Compile() { + double result = _compiledValue.HasValue + ? _compiledValue.Value + : double.Parse(ExpressionString, CultureInfo.InvariantCulture); + result = _negate ? result * -1 : result; + return new(result, DataType.Decimal); + } - } + public bool IsNegated => _negate; }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs index 345c915..56b0fa8 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/EnumerableExpression.cs
@@ -13,61 +13,47 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class EnumerableExpression : Expression - { - public EnumerableExpression() - : this(new ExpressionCompiler()) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - } +public class EnumerableExpression : Expression { + public EnumerableExpression() + : this(new ExpressionCompiler()) {} - public EnumerableExpression(IExpressionCompiler expressionCompiler) - { - _expressionCompiler = expressionCompiler; - } + public EnumerableExpression(IExpressionCompiler expressionCompiler) { + _expressionCompiler = expressionCompiler; + } - private readonly IExpressionCompiler _expressionCompiler; + private readonly IExpressionCompiler _expressionCompiler; - public override bool IsGroupedExpression - { - get { return false; } - } + public override bool IsGroupedExpression => false; - public override Expression PrepareForNextChild() - { - return this; - } + public override Expression PrepareForNextChild() { + return this; + } - public override CompileResult Compile() - { - var result = new List<object>(); - foreach (var childExpression in Children) - { - result.Add(_expressionCompiler.Compile(new List<Expression>{ childExpression }).Result); - } - return new CompileResult(result, DataType.Enumerable); - } + public override CompileResult Compile() { + var result = new List<object>(); + foreach (var childExpression in Children) { + result.Add(_expressionCompiler.Compile(new List<Expression> { childExpression }).Result); } + return new(result, DataType.Enumerable); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs index 186c726..4f68d2c 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ExcelAddressExpression.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,116 +13,101 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; + using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using OfficeOpenXml.FormulaParsing.Exceptions; -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class ExcelAddressExpression : AtomicExpression - { - private readonly ExcelDataProvider _excelDataProvider; - private readonly ParsingContext _parsingContext; - private readonly RangeAddressFactory _rangeAddressFactory; - private readonly bool _negate; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public ExcelAddressExpression(string expression, ExcelDataProvider excelDataProvider, ParsingContext parsingContext) - : this(expression, excelDataProvider, parsingContext, new RangeAddressFactory(excelDataProvider), false) - { +public class ExcelAddressExpression : AtomicExpression { + private readonly ExcelDataProvider _excelDataProvider; + private readonly ParsingContext _parsingContext; + private readonly RangeAddressFactory _rangeAddressFactory; + private readonly bool _negate; - } - public ExcelAddressExpression(string expression, ExcelDataProvider excelDataProvider, ParsingContext parsingContext, bool negate) - : this(expression, excelDataProvider, parsingContext, new RangeAddressFactory(excelDataProvider), negate) - { + public ExcelAddressExpression( + string expression, + ExcelDataProvider excelDataProvider, + ParsingContext parsingContext) + : this(expression, excelDataProvider, parsingContext, new(excelDataProvider), false) {} - } + public ExcelAddressExpression( + string expression, + ExcelDataProvider excelDataProvider, + ParsingContext parsingContext, + bool negate) + : this(expression, excelDataProvider, parsingContext, new(excelDataProvider), negate) {} - public ExcelAddressExpression(string expression, ExcelDataProvider excelDataProvider, ParsingContext parsingContext, RangeAddressFactory rangeAddressFactory, bool negate) - : base(expression) - { - Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); - Require.That(parsingContext).Named("parsingContext").IsNotNull(); - Require.That(rangeAddressFactory).Named("rangeAddressFactory").IsNotNull(); - _excelDataProvider = excelDataProvider; - _parsingContext = parsingContext; - _rangeAddressFactory = rangeAddressFactory; - _negate = negate; - } + public ExcelAddressExpression( + string expression, + ExcelDataProvider excelDataProvider, + ParsingContext parsingContext, + RangeAddressFactory rangeAddressFactory, + bool negate) + : base(expression) { + Require.That(excelDataProvider).Named("excelDataProvider").IsNotNull(); + Require.That(parsingContext).Named("parsingContext").IsNotNull(); + Require.That(rangeAddressFactory).Named("rangeAddressFactory").IsNotNull(); + _excelDataProvider = excelDataProvider; + _parsingContext = parsingContext; + _rangeAddressFactory = rangeAddressFactory; + _negate = negate; + } - public override bool IsGroupedExpression - { - get { return false; } - } + public override bool IsGroupedExpression => false; - public override CompileResult Compile() - { - if (ParentIsLookupFunction) - { - return new CompileResult(ExpressionString, DataType.ExcelAddress); - } - else - { - return CompileRangeValues(); - } - } - - private CompileResult CompileRangeValues() - { - var c = this._parsingContext.Scopes.Current; - var result = _excelDataProvider.GetRange(c.Address.Worksheet, c.Address.FromRow, c.Address.FromCol, ExpressionString); - - if (result == null || result.IsEmpty) - { - return CompileResult.Empty; - } - if (result.Address.Rows > 1 || result.Address.Columns > 1) - { - return new CompileResult(result, DataType.Enumerable); - } - else - { - return CompileSingleCell(result); - } - } - - private CompileResult CompileSingleCell(ExcelDataProvider.IRangeInfo result) - { - var cell = result.First(); - var factory = new CompileResultFactory(); - var compileResult = factory.Create(cell.Value); - if (_negate && compileResult.IsNumeric) - { - compileResult = new CompileResult(compileResult.ResultNumeric * -1, compileResult.DataType); - } - compileResult.IsHiddenCell = cell.IsHiddenRow; - return compileResult; - } - - public bool IsNegated - { - get { return _negate; } - } - + public override CompileResult Compile() { + if (ParentIsLookupFunction) { + return new(ExpressionString, DataType.ExcelAddress); } + return CompileRangeValues(); + } + + private CompileResult CompileRangeValues() { + var c = _parsingContext.Scopes.Current; + var result = _excelDataProvider.GetRange( + c.Address.Worksheet, + c.Address.FromRow, + c.Address.FromCol, + ExpressionString); + + if (result == null || result.IsEmpty) { + return CompileResult.Empty; + } + if (result.Address.Rows > 1 || result.Address.Columns > 1) { + return new(result, DataType.Enumerable); + } + return CompileSingleCell(result); + } + + private CompileResult CompileSingleCell(ExcelDataProvider.IRangeInfo result) { + var cell = result.First(); + var factory = new CompileResultFactory(); + var compileResult = factory.Create(cell.Value); + if (_negate && compileResult.IsNumeric) { + compileResult = new(compileResult.ResultNumeric * -1, compileResult.DataType); + } + compileResult.IsHiddenCell = cell.IsHiddenRow; + return compileResult; + } + + public bool IsNegated { + get { return _negate; } + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs index d25e446..fcf4ddd 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ExcelErrorExpression.cs
@@ -13,62 +13,46 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class ExcelErrorExpression : Expression - { - ExcelErrorValue _error; - public ExcelErrorExpression(string expression, ExcelErrorValue error) - : base(expression) - { - _error = error; - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public ExcelErrorExpression(ExcelErrorValue error) - : this(error.ToString(), error) - { - - } +public class ExcelErrorExpression : Expression { + private ExcelErrorValue _error; - public override bool IsGroupedExpression - { - get { return false; } - } + public ExcelErrorExpression(string expression, ExcelErrorValue error) + : base(expression) { + _error = error; + } - public override CompileResult Compile() - { - return new CompileResult(_error, DataType.ExcelError); - //if (ParentIsLookupFunction) - //{ - // return new CompileResult(ExpressionString, DataType.ExcelError); - //} - //else - //{ - // return CompileRangeValues(); - //} - } - } + public ExcelErrorExpression(ExcelErrorValue error) + : this(error.ToString(), error) {} + + public override bool IsGroupedExpression => false; + + public override CompileResult Compile() { + return new(_error, DataType.ExcelError); + //if (ParentIsLookupFunction) + //{ + // return new CompileResult(ExpressionString, DataType.ExcelError); + //} + //else + //{ + // return CompileRangeValues(); + //} + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs b/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs index 277b78a..e32e3f0 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/Expression.cs
@@ -13,116 +13,97 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Operators; -using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public abstract class Expression - { - public string ExpressionString { get; private set; } - private readonly List<Expression> _children = new List<Expression>(); - public IEnumerable<Expression> Children { get { return _children; } } - public Expression Next { get; set; } - public Expression Prev { get; set; } - public IOperator Operator { get; set; } - public abstract bool IsGroupedExpression { get; } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public Expression() - { +public abstract class Expression { + public string ExpressionString { get; private set; } - } + private readonly List<Expression> _children = new(); - public Expression(string expression) - { - ExpressionString = expression; - Operator = null; - } + public IEnumerable<Expression> Children => _children; - public virtual bool ParentIsLookupFunction - { - get; - set; - } + public Expression Next { get; set; } - public virtual bool HasChildren - { - get { return _children.Any(); } - } + public Expression Prev { get; set; } - public virtual Expression PrepareForNextChild() - { - return this; - } + public IOperator Operator { get; set; } - public virtual Expression AddChild(Expression child) - { - if (_children.Any()) - { - var last = _children.Last(); - child.Prev = last; - last.Next = child; - } - _children.Add(child); - return child; - } + public abstract bool IsGroupedExpression { get; } - public virtual Expression MergeWithNext() - { - var expression = this; - if (Next != null && Operator != null) - { - var result = Operator.Apply(Compile(), Next.Compile()); - expression = ExpressionConverter.Instance.FromCompileResult(result); - if (expression is ExcelErrorExpression) - { - expression.Next = null; - expression.Prev = null; - return expression; - } - if (Next != null) - { - expression.Operator = Next.Operator; - } - else - { - expression.Operator = null; - } - expression.Next = Next.Next; - if (expression.Next != null) expression.Next.Prev = expression; - expression.Prev = Prev; - } - else - { - throw (new FormatException("Invalid formula syntax. Operator missing expression.")); - } - if (Prev != null) - { - Prev.Next = expression; - } - return expression; - } + public Expression() {} - public abstract CompileResult Compile(); + public Expression(string expression) { + ExpressionString = expression; + Operator = null; + } + public virtual bool ParentIsLookupFunction { get; set; } + + public virtual bool HasChildren => _children.Any(); + + public virtual Expression PrepareForNextChild() { + return this; + } + + public virtual Expression AddChild(Expression child) { + if (_children.Any()) { + var last = _children.Last(); + child.Prev = last; + last.Next = child; } + _children.Add(child); + return child; + } + + public virtual Expression MergeWithNext() { + var expression = this; + if (Next != null && Operator != null) { + var result = Operator.Apply(Compile(), Next.Compile()); + expression = ExpressionConverter.Instance.FromCompileResult(result); + if (expression is ExcelErrorExpression) { + expression.Next = null; + expression.Prev = null; + return expression; + } + if (Next != null) { + expression.Operator = Next.Operator; + } else { + expression.Operator = null; + } + expression.Next = Next.Next; + if (expression.Next != null) { + expression.Next.Prev = expression; + } + expression.Prev = Prev; + } else { + throw (new FormatException("Invalid formula syntax. Operator missing expression.")); + } + if (Prev != null) { + Prev.Next = expression; + } + return expression; + } + + public abstract CompileResult Compile(); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs index e92aa75..49a4ecf 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionCompiler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,145 +13,133 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel.Operators; using OfficeOpenXml.FormulaParsing.ExpressionGraph.CompileStrategy; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class ExpressionCompiler : IExpressionCompiler - { - private IEnumerable<Expression> _expressions; - private IExpressionConverter _expressionConverter; - private ICompileStrategyFactory _compileStrategyFactory; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public ExpressionCompiler() - : this(new ExpressionConverter(), new CompileStrategyFactory()) - { - - } +public class ExpressionCompiler : IExpressionCompiler { + private IEnumerable<Expression> _expressions; + private IExpressionConverter _expressionConverter; + private ICompileStrategyFactory _compileStrategyFactory; - public ExpressionCompiler(IExpressionConverter expressionConverter, ICompileStrategyFactory compileStrategyFactory) - { - _expressionConverter = expressionConverter; - _compileStrategyFactory = compileStrategyFactory; - } + public ExpressionCompiler() + : this(new ExpressionConverter(), new CompileStrategyFactory()) {} - public CompileResult Compile(IEnumerable<Expression> expressions) - { - _expressions = expressions; - return PerformCompilation(); - } - public CompileResult Compile(string worksheet, int row, int column, IEnumerable<Expression> expressions) - { - _expressions = expressions; - return PerformCompilation(worksheet, row, column); - } + public ExpressionCompiler( + IExpressionConverter expressionConverter, + ICompileStrategyFactory compileStrategyFactory) { + _expressionConverter = expressionConverter; + _compileStrategyFactory = compileStrategyFactory; + } - private CompileResult PerformCompilation(string worksheet="", int row=-1, int column=-1) - { - var compiledExpressions = HandleGroupedExpressions(); - while(compiledExpressions.Any(x => x.Operator != null)) - { - var prec = FindLowestPrecedence(); - compiledExpressions = HandlePrecedenceLevel(prec); - } - if (_expressions.Any()) - { - return compiledExpressions.First().Compile(); - } - return CompileResult.Empty; - } + public CompileResult Compile(IEnumerable<Expression> expressions) { + _expressions = expressions; + return PerformCompilation(); + } - private IEnumerable<Expression> HandleGroupedExpressions() - { - if (!_expressions.Any()) return Enumerable.Empty<Expression>(); - var first = _expressions.First(); - var groupedExpressions = _expressions.Where(x => x.IsGroupedExpression); - foreach(var groupedExpression in groupedExpressions) - { - var result = groupedExpression.Compile(); - if (result == CompileResult.Empty) continue; - var newExp = _expressionConverter.FromCompileResult(result); - newExp.Operator = groupedExpression.Operator; - newExp.Prev = groupedExpression.Prev; - newExp.Next = groupedExpression.Next; - if (groupedExpression.Prev != null) - { - groupedExpression.Prev.Next = newExp; - } - if (groupedExpression.Next != null) - { - groupedExpression.Next.Prev = newExp; - } - if (groupedExpression == first) - { - first = newExp; - } - } - return RefreshList(first); - } + public CompileResult Compile( + string worksheet, + int row, + int column, + IEnumerable<Expression> expressions) { + _expressions = expressions; + return PerformCompilation(worksheet, row, column); + } - private IEnumerable<Expression> HandlePrecedenceLevel(int precedence) - { - var first = _expressions.First(); - var expressionsToHandle = _expressions.Where(x => x.Operator != null && x.Operator.Precedence == precedence); - var last = expressionsToHandle.Last(); - var expression = expressionsToHandle.First(); - do - { - var strategy = _compileStrategyFactory.Create(expression); - var compiledExpression = strategy.Compile(); - if(compiledExpression is ExcelErrorExpression) - { - return RefreshList(compiledExpression); - } - if (expression == first) - { - first = compiledExpression; - } - - expression = compiledExpression; - } - while (expression != null && expression.Operator != null && expression.Operator.Precedence == precedence); - return RefreshList(first); - } - - private int FindLowestPrecedence() - { - return _expressions.Where(x => x.Operator != null).Min(x => x.Operator.Precedence); - } - - private IEnumerable<Expression> RefreshList(Expression first) - { - var resultList = new List<Expression>(); - var exp = first; - resultList.Add(exp); - while (exp.Next != null) - { - resultList.Add(exp.Next); - exp = exp.Next; - } - _expressions = resultList; - return resultList; - } + private CompileResult PerformCompilation(string worksheet = "", int row = -1, int column = -1) { + var compiledExpressions = HandleGroupedExpressions(); + while (compiledExpressions.Any(x => x.Operator != null)) { + var prec = FindLowestPrecedence(); + compiledExpressions = HandlePrecedenceLevel(prec); } + if (_expressions.Any()) { + return compiledExpressions.First().Compile(); + } + return CompileResult.Empty; + } + + private IEnumerable<Expression> HandleGroupedExpressions() { + if (!_expressions.Any()) { + return Enumerable.Empty<Expression>(); + } + var first = _expressions.First(); + var groupedExpressions = _expressions.Where(x => x.IsGroupedExpression); + foreach (var groupedExpression in groupedExpressions) { + var result = groupedExpression.Compile(); + if (result == CompileResult.Empty) { + continue; + } + var newExp = _expressionConverter.FromCompileResult(result); + newExp.Operator = groupedExpression.Operator; + newExp.Prev = groupedExpression.Prev; + newExp.Next = groupedExpression.Next; + if (groupedExpression.Prev != null) { + groupedExpression.Prev.Next = newExp; + } + if (groupedExpression.Next != null) { + groupedExpression.Next.Prev = newExp; + } + if (groupedExpression == first) { + first = newExp; + } + } + return RefreshList(first); + } + + private IEnumerable<Expression> HandlePrecedenceLevel(int precedence) { + var first = _expressions.First(); + var expressionsToHandle = _expressions.Where(x => + x.Operator != null && x.Operator.Precedence == precedence); + var last = expressionsToHandle.Last(); + var expression = expressionsToHandle.First(); + do { + var strategy = _compileStrategyFactory.Create(expression); + var compiledExpression = strategy.Compile(); + if (compiledExpression is ExcelErrorExpression) { + return RefreshList(compiledExpression); + } + if (expression == first) { + first = compiledExpression; + } + + expression = compiledExpression; + } while (expression != null + && expression.Operator != null + && expression.Operator.Precedence == precedence); + return RefreshList(first); + } + + private int FindLowestPrecedence() { + return _expressions.Where(x => x.Operator != null).Min(x => x.Operator.Precedence); + } + + private IEnumerable<Expression> RefreshList(Expression first) { + var resultList = new List<Expression>(); + var exp = first; + resultList.Add(exp); + while (exp.Next != null) { + resultList.Add(exp.Next); + exp = exp.Next; + } + _expressions = resultList; + return resultList; + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs index a3a4248..339b757 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionConverter.cs
@@ -13,83 +13,73 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class ExpressionConverter : IExpressionConverter - { - public StringExpression ToStringExpression(Expression expression) - { - var result = expression.Compile(); - var newExp = new StringExpression(result.Result.ToString()); - newExp.Operator = expression.Operator; - return newExp; - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public Expression FromCompileResult(CompileResult compileResult) - { - switch (compileResult.DataType) - { - case DataType.Integer: - return compileResult.Result is string - ? new IntegerExpression(compileResult.Result.ToString()) - : new IntegerExpression(Convert.ToDouble(compileResult.Result)); - case DataType.String: - return new StringExpression(compileResult.Result.ToString()); - case DataType.Decimal: - return compileResult.Result is string - ? new DecimalExpression(compileResult.Result.ToString()) - : new DecimalExpression(((double) compileResult.Result)); - case DataType.Boolean: - return compileResult.Result is string - ? new BooleanExpression(compileResult.Result.ToString()) - : new BooleanExpression((bool) compileResult.Result); - //case DataType.Enumerable: - // return - case DataType.ExcelError: - //throw (new OfficeOpenXml.FormulaParsing.Exceptions.ExcelErrorValueException((ExcelErrorValue)compileResult.Result)); //Added JK - return compileResult.Result is string - ? new ExcelErrorExpression(compileResult.Result.ToString(), - ExcelErrorValue.Parse(compileResult.Result.ToString())) - : new ExcelErrorExpression((ExcelErrorValue) compileResult.Result); - case DataType.Empty: - return new IntegerExpression(0); //Added JK +public class ExpressionConverter : IExpressionConverter { + public StringExpression ToStringExpression(Expression expression) { + var result = expression.Compile(); + var newExp = new StringExpression(result.Result.ToString()); + newExp.Operator = expression.Operator; + return newExp; + } - } - return null; - } - - private static IExpressionConverter _instance; - public static IExpressionConverter Instance - { - get - { - if (_instance == null) - { - _instance = new ExpressionConverter(); - } - return _instance; - } - } + public Expression FromCompileResult(CompileResult compileResult) { + switch (compileResult.DataType) { + case DataType.Integer: + return compileResult.Result is string + ? new(compileResult.Result.ToString()) + : new IntegerExpression(Convert.ToDouble(compileResult.Result)); + case DataType.String: + return new StringExpression(compileResult.Result.ToString()); + case DataType.Decimal: + return compileResult.Result is string + ? new(compileResult.Result.ToString()) + : new DecimalExpression(((double)compileResult.Result)); + case DataType.Boolean: + return compileResult.Result is string + ? new(compileResult.Result.ToString()) + : new BooleanExpression((bool)compileResult.Result); + //case DataType.Enumerable: + // return + case DataType.ExcelError: + //throw (new OfficeOpenXml.FormulaParsing.Exceptions.ExcelErrorValueException((ExcelErrorValue)compileResult.Result)); //Added JK + return compileResult.Result is string + ? new( + compileResult.Result.ToString(), + ExcelErrorValue.Parse(compileResult.Result.ToString())) + : new ExcelErrorExpression((ExcelErrorValue)compileResult.Result); + case DataType.Empty: + return new IntegerExpression(0); //Added JK } + return null; + } + + private static IExpressionConverter _instance; + + public static IExpressionConverter Instance { + get { + if (_instance == null) { + _instance = new ExpressionConverter(); + } + return _instance; + } + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs index 8347352..742d50c 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionFactory.cs
@@ -13,69 +13,63 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing; + using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class ExpressionFactory : IExpressionFactory - { - private readonly ExcelDataProvider _excelDataProvider; - private readonly ParsingContext _parsingContext; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public ExpressionFactory(ExcelDataProvider excelDataProvider, ParsingContext context) - { - _excelDataProvider = excelDataProvider; - _parsingContext = context; - } +public class ExpressionFactory : IExpressionFactory { + private readonly ExcelDataProvider _excelDataProvider; + private readonly ParsingContext _parsingContext; + public ExpressionFactory(ExcelDataProvider excelDataProvider, ParsingContext context) { + _excelDataProvider = excelDataProvider; + _parsingContext = context; + } - public Expression Create(Token token) - { - switch (token.TokenType) - { - case TokenType.Integer: - return new IntegerExpression(token.Value, token.IsNegated); - case TokenType.String: - return new StringExpression(token.Value); - case TokenType.Decimal: - return new DecimalExpression(token.Value, token.IsNegated); - case TokenType.Boolean: - return new BooleanExpression(token.Value); - case TokenType.ExcelAddress: - return new ExcelAddressExpression(token.Value, _excelDataProvider, _parsingContext, token.IsNegated); - case TokenType.InvalidReference: - return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Ref)); - case TokenType.NumericError: - return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Num)); - case TokenType.ValueDataTypeError: - return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Value)); - case TokenType.Null: - return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Null)); - case TokenType.NameValue: - return new NamedValueExpression(token.Value, _parsingContext); - default: - return new StringExpression(token.Value); - } - } + public Expression Create(Token token) { + switch (token.TokenType) { + case TokenType.Integer: + return new IntegerExpression(token.Value, token.IsNegated); + case TokenType.String: + return new StringExpression(token.Value); + case TokenType.Decimal: + return new DecimalExpression(token.Value, token.IsNegated); + case TokenType.Boolean: + return new BooleanExpression(token.Value); + case TokenType.ExcelAddress: + return new ExcelAddressExpression( + token.Value, + _excelDataProvider, + _parsingContext, + token.IsNegated); + case TokenType.InvalidReference: + return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Ref)); + case TokenType.NumericError: + return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Num)); + case TokenType.ValueDataTypeError: + return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Value)); + case TokenType.Null: + return new ExcelErrorExpression(token.Value, ExcelErrorValue.Create(eErrorType.Null)); + case TokenType.NameValue: + return new NamedValueExpression(token.Value, _parsingContext); + default: + return new StringExpression(token.Value); } + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs index 04c6509..d9388aa 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraph.cs
@@ -13,59 +13,52 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class ExpressionGraph - { - private List<Expression> _expressions = new List<Expression>(); - public IEnumerable<Expression> Expressions { get { return _expressions; } } - public Expression Current { get; private set; } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public Expression Add(Expression expression) - { - _expressions.Add(expression); - if (Current != null) - { - Current.Next = expression; - expression.Prev = Current; - } - Current = expression; - return expression; - } +public class ExpressionGraph { + private List<Expression> _expressions = new(); - public void Reset() - { - _expressions.Clear(); - Current = null; - } + public IEnumerable<Expression> Expressions => _expressions; - public void Remove(Expression item) - { - if (item == Current) - { - Current = item.Prev ?? item.Next; - } - _expressions.Remove(item); - } + public Expression Current { get; private set; } + + public Expression Add(Expression expression) { + _expressions.Add(expression); + if (Current != null) { + Current.Next = expression; + expression.Prev = Current; } + Current = expression; + return expression; + } + + public void Reset() { + _expressions.Clear(); + Current = null; + } + + public void Remove(Expression item) { + if (item == Current) { + Current = item.Prev ?? item.Next; + } + _expressions.Remove(item); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs index 3f77158..de2f384 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/ExpressionGraphBuilder.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,240 +13,185 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Operators; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -using OfficeOpenXml.FormulaParsing.Excel; -using OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class ExpressionGraphBuilder :IExpressionGraphBuilder - { - private readonly ExpressionGraph _graph = new ExpressionGraph(); - private readonly IExpressionFactory _expressionFactory; - private readonly ParsingContext _parsingContext; - private int _tokenIndex = 0; - private bool _negateNextExpression; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public ExpressionGraphBuilder(ExcelDataProvider excelDataProvider, ParsingContext parsingContext) - : this(new ExpressionFactory(excelDataProvider, parsingContext), parsingContext) - { +public class ExpressionGraphBuilder : IExpressionGraphBuilder { + private readonly ExpressionGraph _graph = new(); + private readonly IExpressionFactory _expressionFactory; + private readonly ParsingContext _parsingContext; + private int _tokenIndex; + private bool _negateNextExpression; + public ExpressionGraphBuilder(ExcelDataProvider excelDataProvider, ParsingContext parsingContext) + : this(new ExpressionFactory(excelDataProvider, parsingContext), parsingContext) {} + + public ExpressionGraphBuilder( + IExpressionFactory expressionFactory, + ParsingContext parsingContext) { + _expressionFactory = expressionFactory; + _parsingContext = parsingContext; + } + + public ExpressionGraph Build(IEnumerable<Token> tokens) { + _tokenIndex = 0; + _graph.Reset(); + var tokensArr = tokens != null ? tokens.ToArray() : new Token[0]; + BuildUp(tokensArr, null); + return _graph; + } + + private void BuildUp(Token[] tokens, Expression parent) { + while (_tokenIndex < tokens.Length) { + var token = tokens[_tokenIndex]; + IOperator op = null; + if (token.TokenType == TokenType.Operator + && OperatorsDict.Instance.TryGetValue(token.Value, out op)) { + SetOperatorOnExpression(parent, op); + } else if (token.TokenType == TokenType.Function) { + BuildFunctionExpression(tokens, parent, token.Value); + } else if (token.TokenType == TokenType.OpeningEnumerable) { + _tokenIndex++; + BuildEnumerableExpression(tokens, parent); + } else if (token.TokenType == TokenType.OpeningParenthesis) { + _tokenIndex++; + BuildGroupExpression(tokens, parent); + //if (parent is FunctionExpression) + //{ + // return; + //} + } else if (token.TokenType == TokenType.ClosingParenthesis + || token.TokenType == TokenType.ClosingEnumerable) { + break; + } else if (token.TokenType == TokenType.Negator) { + _negateNextExpression = true; + } else if (token.TokenType == TokenType.Percent) { + SetOperatorOnExpression(parent, Operator.Percent); + if (parent == null) { + _graph.Add(ConstantExpressions.Percent); + } else { + parent.AddChild(ConstantExpressions.Percent); } - - public ExpressionGraphBuilder(IExpressionFactory expressionFactory, ParsingContext parsingContext) - { - _expressionFactory = expressionFactory; - _parsingContext = parsingContext; - } - - public ExpressionGraph Build(IEnumerable<Token> tokens) - { - _tokenIndex = 0; - _graph.Reset(); - var tokensArr = tokens != null ? tokens.ToArray() : new Token[0]; - BuildUp(tokensArr, null); - return _graph; - } - - private void BuildUp(Token[] tokens, Expression parent) - { - while (_tokenIndex < tokens.Length) - { - var token = tokens[_tokenIndex]; - IOperator op = null; - if (token.TokenType == TokenType.Operator && OperatorsDict.Instance.TryGetValue(token.Value, out op)) - { - SetOperatorOnExpression(parent, op); - } - else if (token.TokenType == TokenType.Function) - { - BuildFunctionExpression(tokens, parent, token.Value); - } - else if (token.TokenType == TokenType.OpeningEnumerable) - { - _tokenIndex++; - BuildEnumerableExpression(tokens, parent); - } - else if (token.TokenType == TokenType.OpeningParenthesis) - { - _tokenIndex++; - BuildGroupExpression(tokens, parent); - //if (parent is FunctionExpression) - //{ - // return; - //} - } - else if (token.TokenType == TokenType.ClosingParenthesis || token.TokenType == TokenType.ClosingEnumerable) - { - break; - } - else if (token.TokenType == TokenType.Negator) - { - _negateNextExpression = true; - } - else if(token.TokenType == TokenType.Percent) - { - SetOperatorOnExpression(parent, Operator.Percent); - if (parent == null) - { - _graph.Add(ConstantExpressions.Percent); - } - else - { - parent.AddChild(ConstantExpressions.Percent); - } - } - else - { - CreateAndAppendExpression(ref parent, token); - } - _tokenIndex++; - } - } - - private void BuildEnumerableExpression(Token[] tokens, Expression parent) - { - if (parent == null) - { - _graph.Add(new EnumerableExpression()); - BuildUp(tokens, _graph.Current); - } - else - { - var enumerableExpression = new EnumerableExpression(); - parent.AddChild(enumerableExpression); - BuildUp(tokens, enumerableExpression); - } - } - - private void CreateAndAppendExpression(ref Expression parent, Token token) - { - if (IsWaste(token)) return; - if (parent != null && - (token.TokenType == TokenType.Comma || token.TokenType == TokenType.SemiColon)) - { - parent = parent.PrepareForNextChild(); - return; - } - if (_negateNextExpression) - { - token.Negate(); - _negateNextExpression = false; - } - var expression = _expressionFactory.Create(token); - if (parent == null) - { - _graph.Add(expression); - } - else - { - parent.AddChild(expression); - } - } - - private bool IsWaste(Token token) - { - if (token.TokenType == TokenType.String) - { - return true; - } - return false; - } - - private void BuildFunctionExpression(Token[] tokens, Expression parent, string funcName) - { - if (parent == null) - { - _graph.Add(new FunctionExpression(funcName, _parsingContext, _negateNextExpression)); - _negateNextExpression = false; - HandleFunctionArguments(tokens, _graph.Current); - } - else - { - var func = new FunctionExpression(funcName, _parsingContext, _negateNextExpression); - _negateNextExpression = false; - parent.AddChild(func); - HandleFunctionArguments(tokens, func); - } - } - - private void HandleFunctionArguments(Token[] tokens, Expression function) - { - _tokenIndex++; - var token = tokens.ElementAt(_tokenIndex); - if (token.TokenType != TokenType.OpeningParenthesis) - { - throw new ExcelErrorValueException(eErrorType.Value); - } - _tokenIndex++; - BuildUp(tokens, function.Children.First()); - } - - private void BuildGroupExpression(Token[] tokens, Expression parent) - { - if (parent == null) - { - _graph.Add(new GroupExpression(_negateNextExpression)); - _negateNextExpression = false; - BuildUp(tokens, _graph.Current); - } - else - { - if (parent.IsGroupedExpression || parent is FunctionArgumentExpression) - { - var newGroupExpression = new GroupExpression(_negateNextExpression); - _negateNextExpression = false; - parent.AddChild(newGroupExpression); - BuildUp(tokens, newGroupExpression); - } - BuildUp(tokens, parent); - } - } - - private void SetOperatorOnExpression(Expression parent, IOperator op) - { - if (parent == null) - { - _graph.Current.Operator = op; - } - else - { - Expression candidate; - if (parent is FunctionArgumentExpression) - { - candidate = parent.Children.Last(); - } - else - { - candidate = parent.Children.Last(); - if (candidate is FunctionArgumentExpression) - { - candidate = candidate.Children.Last(); - } - } - candidate.Operator = op; - } - } + } else { + CreateAndAppendExpression(ref parent, token); + } + _tokenIndex++; } + } + + private void BuildEnumerableExpression(Token[] tokens, Expression parent) { + if (parent == null) { + _graph.Add(new EnumerableExpression()); + BuildUp(tokens, _graph.Current); + } else { + var enumerableExpression = new EnumerableExpression(); + parent.AddChild(enumerableExpression); + BuildUp(tokens, enumerableExpression); + } + } + + private void CreateAndAppendExpression(ref Expression parent, Token token) { + if (IsWaste(token)) { + return; + } + if (parent != null + && (token.TokenType == TokenType.Comma || token.TokenType == TokenType.SemiColon)) { + parent = parent.PrepareForNextChild(); + return; + } + if (_negateNextExpression) { + token.Negate(); + _negateNextExpression = false; + } + var expression = _expressionFactory.Create(token); + if (parent == null) { + _graph.Add(expression); + } else { + parent.AddChild(expression); + } + } + + private bool IsWaste(Token token) { + if (token.TokenType == TokenType.String) { + return true; + } + return false; + } + + private void BuildFunctionExpression(Token[] tokens, Expression parent, string funcName) { + if (parent == null) { + _graph.Add(new FunctionExpression(funcName, _parsingContext, _negateNextExpression)); + _negateNextExpression = false; + HandleFunctionArguments(tokens, _graph.Current); + } else { + var func = new FunctionExpression(funcName, _parsingContext, _negateNextExpression); + _negateNextExpression = false; + parent.AddChild(func); + HandleFunctionArguments(tokens, func); + } + } + + private void HandleFunctionArguments(Token[] tokens, Expression function) { + _tokenIndex++; + var token = tokens.ElementAt(_tokenIndex); + if (token.TokenType != TokenType.OpeningParenthesis) { + throw new ExcelErrorValueException(eErrorType.Value); + } + _tokenIndex++; + BuildUp(tokens, function.Children.First()); + } + + private void BuildGroupExpression(Token[] tokens, Expression parent) { + if (parent == null) { + _graph.Add(new GroupExpression(_negateNextExpression)); + _negateNextExpression = false; + BuildUp(tokens, _graph.Current); + } else { + if (parent.IsGroupedExpression || parent is FunctionArgumentExpression) { + var newGroupExpression = new GroupExpression(_negateNextExpression); + _negateNextExpression = false; + parent.AddChild(newGroupExpression); + BuildUp(tokens, newGroupExpression); + } + BuildUp(tokens, parent); + } + } + + private void SetOperatorOnExpression(Expression parent, IOperator op) { + if (parent == null) { + _graph.Current.Operator = op; + } else { + Expression candidate; + if (parent is FunctionArgumentExpression) { + candidate = parent.Children.Last(); + } else { + candidate = parent.Children.Last(); + if (candidate is FunctionArgumentExpression) { + candidate = candidate.Children.Last(); + } + } + candidate.Operator = op; + } + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs index ba5aee0..0123e1d 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionArgumentExpression.cs
@@ -13,62 +13,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class FunctionArgumentExpression : GroupExpression - { - private readonly Expression _function; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public FunctionArgumentExpression(Expression function) - : base(false) - { - _function = function; - } +public class FunctionArgumentExpression : GroupExpression { + private readonly Expression _function; - public override bool ParentIsLookupFunction - { - get - { - return base.ParentIsLookupFunction; - } - set - { - base.ParentIsLookupFunction = value; - foreach (var child in Children) - { - child.ParentIsLookupFunction = value; - } - } - } + public FunctionArgumentExpression(Expression function) + : base(false) { + _function = function; + } - public override bool IsGroupedExpression - { - get { return false; } - } - - public override Expression PrepareForNextChild() - { - return _function.PrepareForNextChild(); - } + public override bool ParentIsLookupFunction { + get => base.ParentIsLookupFunction; + set { + base.ParentIsLookupFunction = value; + foreach (var child in Children) { + child.ParentIsLookupFunction = value; + } } + } + + public override bool IsGroupedExpression => false; + + public override Expression PrepareForNextChild() { + return _function.PrepareForNextChild(); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs index 40a8544..ebc2918 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/DefaultCompiler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,57 +13,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel; using OfficeOpenXml.FormulaParsing.Excel.Functions; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - public class DefaultCompiler : FunctionCompiler - { - public DefaultCompiler(ExcelFunction function) - : base(function) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - } +public class DefaultCompiler : FunctionCompiler { + public DefaultCompiler(ExcelFunction function) + : base(function) {} - public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) - { - var args = new List<FunctionArgument>(); - Function.BeforeInvoke(context); - foreach (var child in children) - { - var compileResult = child.Compile(); - if (compileResult.IsResultOfSubtotal) - { - var arg = new FunctionArgument(compileResult.Result); - arg.SetExcelStateFlag(ExcelCellState.IsResultOfSubtotal); - args.Add(arg); - } - else - { - BuildFunctionArguments(compileResult.Result, args); - } - } - return Function.Execute(args, context); - } + public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) { + var args = new List<FunctionArgument>(); + Function.BeforeInvoke(context); + foreach (var child in children) { + var compileResult = child.Compile(); + if (compileResult.IsResultOfSubtotal) { + var arg = new FunctionArgument(compileResult.Result); + arg.SetExcelStateFlag(ExcelCellState.IsResultOfSubtotal); + args.Add(arg); + } else { + BuildFunctionArguments(compileResult.Result, args); + } } + return Function.Execute(args, context); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs index ffa4cac..303821a 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/ErrorHandlingFunctionCompiler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,59 +13,46 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - public class ErrorHandlingFunctionCompiler : FunctionCompiler - { - public ErrorHandlingFunctionCompiler(ExcelFunction function) - : base(function) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - } - public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) - { - var args = new List<FunctionArgument>(); - Function.BeforeInvoke(context); - foreach (var child in children) - { - try - { - var arg = child.Compile(); - BuildFunctionArguments(arg != null ? arg.Result : null, args); - } - catch (ExcelErrorValueException efe) - { - return ((ErrorHandlingFunction)Function).HandleError(efe.ErrorValue.ToString()); - } - catch// (Exception e) - { - return ((ErrorHandlingFunction)Function).HandleError(ExcelErrorValue.Values.Value); - } - - } - return Function.Execute(args, context); - } +public class ErrorHandlingFunctionCompiler : FunctionCompiler { + public ErrorHandlingFunctionCompiler(ExcelFunction function) + : base(function) {} + + public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) { + var args = new List<FunctionArgument>(); + Function.BeforeInvoke(context); + foreach (var child in children) { + try { + var arg = child.Compile(); + BuildFunctionArguments(arg != null ? arg.Result : null, args); + } catch (ExcelErrorValueException efe) { + return ((ErrorHandlingFunction)Function).HandleError(efe.ErrorValue.ToString()); + } catch // (Exception e) + { + return ((ErrorHandlingFunction)Function).HandleError(ExcelErrorValue.Values.Value); + } } + return Function.Execute(args, context); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs index 63a8b22..cb164b0 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompiler.cs
@@ -13,63 +13,48 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; -using System.Collections; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - public abstract class FunctionCompiler - { - protected ExcelFunction Function - { - get; - private set; - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - public FunctionCompiler(ExcelFunction function) - { - Require.That(function).Named("function").IsNotNull(); - Function = function; - } +public abstract class FunctionCompiler { + protected ExcelFunction Function { get; private set; } - protected void BuildFunctionArguments(object result, List<FunctionArgument> args) - { - if (result is IEnumerable<object> && !(result is ExcelDataProvider.IRangeInfo)) - { - var argList = new List<FunctionArgument>(); - var objects = result as IEnumerable<object>; - foreach (var arg in objects) - { - BuildFunctionArguments(arg, argList); - } - args.Add(new FunctionArgument(argList)); - } - else - { - args.Add(new FunctionArgument(result)); - } - } + public FunctionCompiler(ExcelFunction function) { + Require.That(function).Named("function").IsNotNull(); + Function = function; + } - public abstract CompileResult Compile(IEnumerable<Expression> children, ParsingContext context); + protected void BuildFunctionArguments(object result, List<FunctionArgument> args) { + if (result is IEnumerable<object> && !(result is ExcelDataProvider.IRangeInfo)) { + var argList = new List<FunctionArgument>(); + var objects = result as IEnumerable<object>; + foreach (var arg in objects) { + BuildFunctionArguments(arg, argList); + } + args.Add(new(argList)); + } else { + args.Add(new(result)); } + } + + public abstract CompileResult Compile(IEnumerable<Expression> children, ParsingContext context); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs index 1bf7693..0f54dcc 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/FunctionCompilerFactory.cs
@@ -13,55 +13,55 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - public class FunctionCompilerFactory - { - private readonly Dictionary<Type, FunctionCompiler> _specialCompilers = new Dictionary<Type, FunctionCompiler>(); +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - public FunctionCompilerFactory(FunctionRepository repository) - { - _specialCompilers.Add(typeof(If), new IfFunctionCompiler(repository.GetFunction("if"))); - _specialCompilers.Add(typeof(IfError), new IfErrorFunctionCompiler(repository.GetFunction("iferror"))); - _specialCompilers.Add(typeof(IfNa), new IfNaFunctionCompiler(repository.GetFunction("ifna"))); - } +public class FunctionCompilerFactory { + private readonly Dictionary<Type, FunctionCompiler> _specialCompilers = new(); - private FunctionCompiler GetCompilerByType(ExcelFunction function) - { - var funcType = function.GetType(); - if (_specialCompilers.ContainsKey(funcType)) - { - return _specialCompilers[funcType]; - } - return new DefaultCompiler(function); - } - public virtual FunctionCompiler Create(ExcelFunction function) - { - if (function.IsLookupFuction) return new LookupFunctionCompiler(function); - if (function.IsErrorHandlingFunction) return new ErrorHandlingFunctionCompiler(function); - return GetCompilerByType(function); - } + public FunctionCompilerFactory(FunctionRepository repository) { + _specialCompilers.Add(typeof(If), new IfFunctionCompiler(repository.GetFunction("if"))); + _specialCompilers.Add( + typeof(IfError), + new IfErrorFunctionCompiler(repository.GetFunction("iferror"))); + _specialCompilers.Add(typeof(IfNa), new IfNaFunctionCompiler(repository.GetFunction("ifna"))); + } + + private FunctionCompiler GetCompilerByType(ExcelFunction function) { + var funcType = function.GetType(); + if (_specialCompilers.ContainsKey(funcType)) { + return _specialCompilers[funcType]; } + return new DefaultCompiler(function); + } + + public virtual FunctionCompiler Create(ExcelFunction function) { + if (function.IsLookupFuction) { + return new LookupFunctionCompiler(function); + } + if (function.IsErrorHandlingFunction) { + return new ErrorHandlingFunctionCompiler(function); + } + return GetCompilerByType(function); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs index a409632..e809ea5 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfErrorFunctionCompiler.cs
@@ -1,48 +1,35 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - public class IfErrorFunctionCompiler : FunctionCompiler - { - public IfErrorFunctionCompiler(ExcelFunction function) - : base(function) - { - Require.That(function).Named("function").IsNotNull(); - - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) - { - if (children.Count() != 2) throw new ExcelErrorValueException(eErrorType.Value); - var args = new List<FunctionArgument>(); - Function.BeforeInvoke(context); - var firstChild = children.First(); - var lastChild = children.ElementAt(1); - try - { - var result = firstChild.Compile(); - if (result.DataType == DataType.ExcelError) - { - args.Add(new FunctionArgument(lastChild.Compile().Result)); - } - else - { - args.Add(new FunctionArgument(result.Result)); - } - - } - catch (ExcelErrorValueException) - { - args.Add(new FunctionArgument(lastChild.Compile().Result)); - } - return Function.Execute(args, context); - } +public class IfErrorFunctionCompiler : FunctionCompiler { + public IfErrorFunctionCompiler(ExcelFunction function) + : base(function) { + Require.That(function).Named("function").IsNotNull(); + } + + public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) { + if (children.Count() != 2) { + throw new ExcelErrorValueException(eErrorType.Value); } + var args = new List<FunctionArgument>(); + Function.BeforeInvoke(context); + var firstChild = children.First(); + var lastChild = children.ElementAt(1); + try { + var result = firstChild.Compile(); + if (result.DataType == DataType.ExcelError) { + args.Add(new(lastChild.Compile().Result)); + } else { + args.Add(new(result.Result)); + } + } catch (ExcelErrorValueException) { + args.Add(new(lastChild.Compile().Result)); + } + return Function.Execute(args, context); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs index ffe70ad..0818ce5 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfFunctionCompiler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,102 +13,92 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2014-01-27 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Excel.Functions.Logical; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.Utilities; +using OfficeOpenXml.Utils; +using Require = OfficeOpenXml.FormulaParsing.Utilities.Require; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - /// <summary> - /// Why do the If function require a compiler of its own you might ask;) - /// - /// It is because it only needs to evaluate one of the two last expressions. This - /// compiler handles this - it ignores the irrelevant expression. - /// </summary> - public class IfFunctionCompiler : FunctionCompiler - { - public IfFunctionCompiler(ExcelFunction function) - : base(function) - { - Require.That(function).Named("function").IsNotNull(); - if (!(function is If)) throw new ArgumentException("function must be of type If"); - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) - { - if(children.Count() < 3) throw new ExcelErrorValueException(eErrorType.Value); - var args = new List<FunctionArgument>(); - Function.BeforeInvoke(context); - var firstChild = children.ElementAt(0); - var v = firstChild.Compile().Result; - - /**** Handle names and ranges ****/ - if (v is ExcelDataProvider.INameInfo) - { - v = ((ExcelDataProvider.INameInfo)v).Value; - } - - if (v is ExcelDataProvider.IRangeInfo) - { - var r=((ExcelDataProvider.IRangeInfo)v); - if(r.GetNCells()>1) - { - throw(new ArgumentException("Logical can't be more than one cell")); - } - v = r.GetOffset(0, 0); - } - bool boolVal; - if(v is bool) - { - boolVal = (bool)v; - } - else - { - if(OfficeOpenXml.Utils.ConvertUtil.IsNumeric(v)) - { - boolVal = OfficeOpenXml.Utils.ConvertUtil.GetValueDouble(v)!=0; - } - else - { - throw (new ArgumentException("Invalid logical test")); - } - } - /**** End Handle names and ranges ****/ - - args.Add(new FunctionArgument(boolVal)); - if (boolVal) - { - var val = children.ElementAt(1).Compile().Result; - args.Add(new FunctionArgument(val)); - args.Add(new FunctionArgument(null)); - } - else - { - var val = children.ElementAt(2).Compile().Result; - args.Add(new FunctionArgument(null)); - args.Add(new FunctionArgument(val)); - } - return Function.Execute(args, context); - } +/// <summary> +/// Why do the If function require a compiler of its own you might ask;) +/// +/// It is because it only needs to evaluate one of the two last expressions. This +/// compiler handles this - it ignores the irrelevant expression. +/// </summary> +public class IfFunctionCompiler : FunctionCompiler { + public IfFunctionCompiler(ExcelFunction function) + : base(function) { + Require.That(function).Named("function").IsNotNull(); + if (!(function is If)) { + throw new ArgumentException("function must be of type If"); } + } + + public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) { + if (children.Count() < 3) { + throw new ExcelErrorValueException(eErrorType.Value); + } + var args = new List<FunctionArgument>(); + Function.BeforeInvoke(context); + var firstChild = children.ElementAt(0); + var v = firstChild.Compile().Result; + + /**** Handle names and ranges ****/ + if (v is ExcelDataProvider.INameInfo) { + v = ((ExcelDataProvider.INameInfo)v).Value; + } + + if (v is ExcelDataProvider.IRangeInfo) { + var r = ((ExcelDataProvider.IRangeInfo)v); + if (r.GetNCells() > 1) { + throw (new ArgumentException("Logical can't be more than one cell")); + } + v = r.GetOffset(0, 0); + } + bool boolVal; + if (v is bool) { + boolVal = (bool)v; + } else { + if (ConvertUtil.IsNumeric(v)) { + boolVal = ConvertUtil.GetValueDouble(v) != 0; + } else { + throw (new ArgumentException("Invalid logical test")); + } + } + /**** End Handle names and ranges ****/ + + args.Add(new(boolVal)); + if (boolVal) { + var val = children.ElementAt(1).Compile().Result; + args.Add(new(val)); + args.Add(new(null)); + } else { + var val = children.ElementAt(2).Compile().Result; + args.Add(new(null)); + args.Add(new(val)); + } + return Function.Execute(args, context); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs index ecfff31..55f15b2 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/IfNaFunctionCompiler.cs
@@ -1,46 +1,33 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - public class IfNaFunctionCompiler : FunctionCompiler - { - public IfNaFunctionCompiler(ExcelFunction function) - :base(function) - { - - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) - { - if (children.Count() != 2) throw new ExcelErrorValueException(eErrorType.Value); - var args = new List<FunctionArgument>(); - Function.BeforeInvoke(context); - var firstChild = children.First(); - var lastChild = children.ElementAt(1); - try - { - var result = firstChild.Compile(); - if (result.DataType == DataType.ExcelError && (Equals(result.Result, - ExcelErrorValue.Create(eErrorType.NA)))) - { - args.Add(new FunctionArgument(lastChild.Compile().Result)); - } - else - { - args.Add(new FunctionArgument(result.Result)); - } +public class IfNaFunctionCompiler : FunctionCompiler { + public IfNaFunctionCompiler(ExcelFunction function) + : base(function) {} - } - catch (ExcelErrorValueException) - { - args.Add(new FunctionArgument(lastChild.Compile().Result)); - } - return Function.Execute(args, context); - } + public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) { + if (children.Count() != 2) { + throw new ExcelErrorValueException(eErrorType.Value); } + var args = new List<FunctionArgument>(); + Function.BeforeInvoke(context); + var firstChild = children.First(); + var lastChild = children.ElementAt(1); + try { + var result = firstChild.Compile(); + if (result.DataType == DataType.ExcelError + && (Equals(result.Result, ExcelErrorValue.Create(eErrorType.Na)))) { + args.Add(new(lastChild.Compile().Result)); + } else { + args.Add(new(result.Result)); + } + } catch (ExcelErrorValueException) { + args.Add(new(lastChild.Compile().Result)); + } + return Function.Execute(args, context); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs index 9440594..a350504 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionCompilers/LookupFunctionCompiler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,56 +13,44 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers -{ - public class LookupFunctionCompiler : FunctionCompiler - { - public LookupFunctionCompiler(ExcelFunction function) - : base(function) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; - } +public class LookupFunctionCompiler : FunctionCompiler { + public LookupFunctionCompiler(ExcelFunction function) + : base(function) {} - public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) - { - var args = new List<FunctionArgument>(); - Function.BeforeInvoke(context); - var firstChild = true; - foreach (var child in children) - { - if (!firstChild || Function.SkipArgumentEvaluation) - { - child.ParentIsLookupFunction = Function.IsLookupFuction; - } - else - { - firstChild = false; - } - var arg = child.Compile(); - BuildFunctionArguments(arg != null ? arg.Result : null, args); - } - return Function.Execute(args, context); - } + public override CompileResult Compile(IEnumerable<Expression> children, ParsingContext context) { + var args = new List<FunctionArgument>(); + Function.BeforeInvoke(context); + var firstChild = true; + foreach (var child in children) { + if (!firstChild || Function.SkipArgumentEvaluation) { + child.ParentIsLookupFunction = Function.IsLookupFuction; + } else { + firstChild = false; + } + var arg = child.Compile(); + BuildFunctionArguments(arg != null ? arg.Result : null, args); } + return Function.Execute(args, context); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/FunctionExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/FunctionExpression.cs index 24193ca..0f39bd5 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/FunctionExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/FunctionExpression.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,122 +13,98 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Globalization; + using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel; -using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.Exceptions; using OfficeOpenXml.FormulaParsing.ExpressionGraph.FunctionCompilers; -using OfficeOpenXml.Utils; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - /// <summary> - /// Expression that handles execution of a function. - /// </summary> - public class FunctionExpression : AtomicExpression - { - /// <summary> - /// Constructor - /// </summary> - /// <param name="expression">should be the of the function</param> - /// <param name="parsingContext"></param> - /// <param name="isNegated">True if the numeric result of the function should be negated.</param> - public FunctionExpression(string expression, ParsingContext parsingContext, bool isNegated) - : base(expression) - { - _parsingContext = parsingContext; - _functionCompilerFactory = new FunctionCompilerFactory(parsingContext.Configuration.FunctionRepository); - _isNegated = isNegated; - base.AddChild(new FunctionArgumentExpression(this)); +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; + +/// <summary> +/// Expression that handles execution of a function. +/// </summary> +public class FunctionExpression : AtomicExpression { + /// <summary> + /// Constructor + /// </summary> + /// <param name="expression">should be the of the function</param> + /// <param name="parsingContext"></param> + /// <param name="isNegated">True if the numeric result of the function should be negated.</param> + public FunctionExpression(string expression, ParsingContext parsingContext, bool isNegated) + : base(expression) { + _parsingContext = parsingContext; + _functionCompilerFactory = new(parsingContext.Configuration.FunctionRepository); + _isNegated = isNegated; + base.AddChild(new FunctionArgumentExpression(this)); + } + + private readonly ParsingContext _parsingContext; + private readonly FunctionCompilerFactory _functionCompilerFactory; + private readonly bool _isNegated; + + public override CompileResult Compile() { + try { + var function = _parsingContext.Configuration.FunctionRepository.GetFunction(ExpressionString); + if (function == null) { + if (_parsingContext.Debug) { + _parsingContext.Configuration.Logger.Log( + _parsingContext, + string.Format("'{0}' is not a supported function", ExpressionString)); } - - private readonly ParsingContext _parsingContext; - private readonly FunctionCompilerFactory _functionCompilerFactory; - private readonly bool _isNegated; - - - public override CompileResult Compile() - { - try - { - var function = _parsingContext.Configuration.FunctionRepository.GetFunction(ExpressionString); - if (function == null) - { - if (_parsingContext.Debug) - { - _parsingContext.Configuration.Logger.Log(_parsingContext, string.Format("'{0}' is not a supported function", ExpressionString)); - } - return new CompileResult(ExcelErrorValue.Create(eErrorType.Name), DataType.ExcelError); - } - if (_parsingContext.Debug) - { - _parsingContext.Configuration.Logger.LogFunction(ExpressionString); - } - var compiler = _functionCompilerFactory.Create(function); - var result = compiler.Compile(HasChildren ? Children : Enumerable.Empty<Expression>(), _parsingContext); - if (_isNegated) - { - if (!result.IsNumeric) - { - if (_parsingContext.Debug) - { - var msg = string.Format("Trying to negate a non-numeric value ({0}) in function '{1}'", - result.Result, ExpressionString); - _parsingContext.Configuration.Logger.Log(_parsingContext, msg); - } - return new CompileResult(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); - } - return new CompileResult(result.ResultNumeric * -1, result.DataType); - } - return result; - } - catch (ExcelErrorValueException e) - { - if (_parsingContext.Debug) - { - _parsingContext.Configuration.Logger.Log(_parsingContext, e); - } - return new CompileResult(e.ErrorValue, DataType.ExcelError); - } - + return new(ExcelErrorValue.Create(eErrorType.Name), DataType.ExcelError); + } + if (_parsingContext.Debug) { + _parsingContext.Configuration.Logger.LogFunction(ExpressionString); + } + var compiler = _functionCompilerFactory.Create(function); + var result = compiler.Compile( + HasChildren ? Children : Enumerable.Empty<Expression>(), + _parsingContext); + if (_isNegated) { + if (!result.IsNumeric) { + if (_parsingContext.Debug) { + var msg = string.Format( + "Trying to negate a non-numeric value ({0}) in function '{1}'", + result.Result, + ExpressionString); + _parsingContext.Configuration.Logger.Log(_parsingContext, msg); + } + return new(ExcelErrorValue.Create(eErrorType.Value), DataType.ExcelError); } - - public override Expression PrepareForNextChild() - { - return base.AddChild(new FunctionArgumentExpression(this)); - } - - public override bool HasChildren - { - get - { - return (Children.Any() && Children.First().Children.Any()); - } - } - - public override Expression AddChild(Expression child) - { - Children.Last().AddChild(child); - return child; - } + return new(result.ResultNumeric * -1, result.DataType); + } + return result; + } catch (ExcelErrorValueException e) { + if (_parsingContext.Debug) { + _parsingContext.Configuration.Logger.Log(_parsingContext, e); + } + return new(e.ErrorValue, DataType.ExcelError); } + } + + public override Expression PrepareForNextChild() { + return base.AddChild(new FunctionArgumentExpression(this)); + } + + public override bool HasChildren => (Children.Any() && Children.First().Children.Any()); + + public override Expression AddChild(Expression child) { + Children.Last().AddChild(child); + return child; + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/GroupExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/GroupExpression.cs index e8dba20..54df131 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/GroupExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/GroupExpression.cs
@@ -13,65 +13,45 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class GroupExpression : Expression - { - public GroupExpression(bool isNegated) - : this(isNegated, new ExpressionCompiler()) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - } +public class GroupExpression : Expression { + public GroupExpression(bool isNegated) + : this(isNegated, new ExpressionCompiler()) {} - public GroupExpression(bool isNegated, IExpressionCompiler expressionCompiler) - { - _expressionCompiler = expressionCompiler; - _isNegated = isNegated; - } + public GroupExpression(bool isNegated, IExpressionCompiler expressionCompiler) { + _expressionCompiler = expressionCompiler; + _isNegated = isNegated; + } - private readonly IExpressionCompiler _expressionCompiler; - private readonly bool _isNegated; + private readonly IExpressionCompiler _expressionCompiler; + private readonly bool _isNegated; - - public override CompileResult Compile() - { - var result = _expressionCompiler.Compile(Children); - if (result.IsNumeric && _isNegated) - { - return new CompileResult(result.ResultNumeric * -1, result.DataType); - } - return result; - } - - public override bool IsGroupedExpression - { - get { return true; } - } - - public bool IsNegated - { - get { return _isNegated; } - } - + public override CompileResult Compile() { + var result = _expressionCompiler.Compile(Children); + if (result.IsNumeric && _isNegated) { + return new(result.ResultNumeric * -1, result.DataType); } + return result; + } + + public override bool IsGroupedExpression => true; + + public bool IsNegated => _isNegated; }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs index 3fb39ee..c7ef8dd 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionCompiler.cs
@@ -13,30 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public interface IExpressionCompiler - { - CompileResult Compile(IEnumerable<Expression> expressions); - } +using System.Collections.Generic; + +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; + +public interface IExpressionCompiler { + CompileResult Compile(IEnumerable<Expression> expressions); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs index 660df97..0a1b901 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionConverter.cs
@@ -13,31 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public interface IExpressionConverter - { - StringExpression ToStringExpression(Expression expression); - Expression FromCompileResult(CompileResult compileResult); - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; + +public interface IExpressionConverter { + StringExpression ToStringExpression(Expression expression); + + Expression FromCompileResult(CompileResult compileResult); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs index 944b118..2e89b2a 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionFactory.cs
@@ -13,31 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public interface IExpressionFactory - { - Expression Create(Token token); - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; + +public interface IExpressionFactory { + Expression Create(Token token); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs index cb9e122..2fad667 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/IExpressionGraphBuilder.cs
@@ -13,31 +13,27 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public interface IExpressionGraphBuilder - { - ExpressionGraph Build(IEnumerable<Token> tokens); - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; + +public interface IExpressionGraphBuilder { + ExpressionGraph Build(IEnumerable<Token> tokens); }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/IntegerExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/IntegerExpression.cs index 4e57168..973b523 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/IntegerExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/IntegerExpression.cs
@@ -13,63 +13,51 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class IntegerExpression : AtomicExpression - { - private readonly double? _compiledValue; - private readonly bool _negate; +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - public IntegerExpression(string expression) - : this(expression, false) - { +public class IntegerExpression : AtomicExpression { + private readonly double? _compiledValue; + private readonly bool _negate; - } + public IntegerExpression(string expression) + : this(expression, false) {} - public IntegerExpression(string expression, bool negate) - : base(expression) - { - _negate = negate; - } + public IntegerExpression(string expression, bool negate) + : base(expression) { + _negate = negate; + } - public IntegerExpression(double val) - : base(val.ToString(CultureInfo.InvariantCulture)) - { - _compiledValue = Math.Floor(val); - } + public IntegerExpression(double val) + : base(val.ToString(CultureInfo.InvariantCulture)) { + _compiledValue = Math.Floor(val); + } - public override CompileResult Compile() - { - double result = _compiledValue.HasValue ? _compiledValue.Value : double.Parse(ExpressionString, CultureInfo.InvariantCulture); - result = _negate ? result*-1 : result; - return new CompileResult(result, DataType.Integer); - } + public override CompileResult Compile() { + double result = _compiledValue.HasValue + ? _compiledValue.Value + : double.Parse(ExpressionString, CultureInfo.InvariantCulture); + result = _negate ? result * -1 : result; + return new(result, DataType.Integer); + } - public bool IsNegated - { - get { return _negate; } - } - - } + public bool IsNegated => _negate; }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs index 3c54bc8..080f8a0 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/NamedValueExpression.cs
@@ -13,78 +13,62 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; + using System.Linq; -using System.Text; +using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class NamedValueExpression : AtomicExpression - { - public NamedValueExpression(string expression, ParsingContext parsingContext) - : base(expression) - { - _parsingContext = parsingContext; - } +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - private readonly ParsingContext _parsingContext; +public class NamedValueExpression : AtomicExpression { + public NamedValueExpression(string expression, ParsingContext parsingContext) + : base(expression) { + _parsingContext = parsingContext; + } - public override CompileResult Compile() - { - var c = this._parsingContext.Scopes.Current; - var name = _parsingContext.ExcelDataProvider.GetName(c.Address.Worksheet, ExpressionString); - //var result = _parsingContext.Parser.Parse(value.ToString()); + private readonly ParsingContext _parsingContext; - if (name == null) - { - throw (new Exceptions.ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Name))); - } - if (name.Value==null) - { - return null; - } - if (name.Value is ExcelDataProvider.IRangeInfo) - { - var range = (ExcelDataProvider.IRangeInfo)name.Value; - if (range.IsMulti) - { - return new CompileResult(name.Value, DataType.Enumerable); - } - else - { - if (range.IsEmpty) - { - return null; - } - var factory = new CompileResultFactory(); - return factory.Create(range.First().Value); - } - } - else - { - var factory = new CompileResultFactory(); - return factory.Create(name.Value); - } + public override CompileResult Compile() { + var c = _parsingContext.Scopes.Current; + var name = _parsingContext.ExcelDataProvider.GetName(c.Address.Worksheet, ExpressionString); + //var result = _parsingContext.Parser.Parse(value.ToString()); - - - //return new CompileResultFactory().Create(result); - } + if (name == null) { + throw (new ExcelErrorValueException(ExcelErrorValue.Create(eErrorType.Name))); } + if (name.Value == null) { + return null; + } + if (name.Value is ExcelDataProvider.IRangeInfo) { + var range = (ExcelDataProvider.IRangeInfo)name.Value; + if (range.IsMulti) { + return new(name.Value, DataType.Enumerable); + } + if (range.IsEmpty) { + return null; + } + var factory = new CompileResultFactory(); + return factory.Create(range.First().Value); + } + { + var factory = new CompileResultFactory(); + return factory.Create(name.Value); + } + + //return new CompileResultFactory().Create(result); + } }
diff --git a/EPPlus/FormulaParsing/ExpressionGraph/StringExpression.cs b/EPPlus/FormulaParsing/ExpressionGraph/StringExpression.cs index 52895cb..f3b29de 100644 --- a/EPPlus/FormulaParsing/ExpressionGraph/StringExpression.cs +++ b/EPPlus/FormulaParsing/ExpressionGraph/StringExpression.cs
@@ -13,39 +13,29 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.ExpressionGraph -{ - public class StringExpression : AtomicExpression - { - public StringExpression(string expression) - : base(expression) - { +namespace OfficeOpenXml.FormulaParsing.ExpressionGraph; - } +public class StringExpression : AtomicExpression { + public StringExpression(string expression) + : base(expression) {} - public override CompileResult Compile() - { - return new CompileResult(ExpressionString, DataType.String); - } - } + public override CompileResult Compile() { + return new(ExpressionString, DataType.String); + } }
diff --git a/EPPlus/FormulaParsing/FormulaParser.cs b/EPPlus/FormulaParsing/FormulaParser.cs index a7ad2d8..faa0536 100644 --- a/EPPlus/FormulaParsing/FormulaParser.cs +++ b/EPPlus/FormulaParsing/FormulaParser.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,214 +13,186 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; using System.Collections.Generic; using System.Linq; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using OfficeOpenXml.FormulaParsing.Utilities; using OfficeOpenXml.FormulaParsing.Exceptions; +using OfficeOpenXml.FormulaParsing.ExpressionGraph; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; +using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing -{ - public class FormulaParser - { - private readonly ParsingContext _parsingContext; - private readonly ExcelDataProvider _excelDataProvider; +namespace OfficeOpenXml.FormulaParsing; - public FormulaParser(ExcelDataProvider excelDataProvider) - : this(excelDataProvider, ParsingContext.Create()) - { - - } +public class FormulaParser { + private readonly ParsingContext _parsingContext; + private readonly ExcelDataProvider _excelDataProvider; - public FormulaParser(ExcelDataProvider excelDataProvider, ParsingContext parsingContext) - { - parsingContext.Parser = this; - parsingContext.ExcelDataProvider = excelDataProvider; - parsingContext.NameValueProvider = new EpplusNameValueProvider(excelDataProvider); - parsingContext.RangeAddressFactory = new RangeAddressFactory(excelDataProvider); - _parsingContext = parsingContext; - _excelDataProvider = excelDataProvider; - Configure(configuration => - { - configuration - .SetLexer(new Lexer(_parsingContext.Configuration.FunctionRepository, _parsingContext.NameValueProvider)) - .SetGraphBuilder(new ExpressionGraphBuilder(excelDataProvider, _parsingContext)) - .SetExpresionCompiler(new ExpressionCompiler()) - .FunctionRepository.LoadModule(new BuiltInFunctions()); - }); - } + public FormulaParser(ExcelDataProvider excelDataProvider) + : this(excelDataProvider, ParsingContext.Create()) {} - public void Configure(Action<ParsingConfiguration> configMethod) - { - configMethod.Invoke(_parsingContext.Configuration); - _lexer = _parsingContext.Configuration.Lexer ?? _lexer; - _graphBuilder = _parsingContext.Configuration.GraphBuilder ?? _graphBuilder; - _compiler = _parsingContext.Configuration.ExpressionCompiler ?? _compiler; - } + public FormulaParser(ExcelDataProvider excelDataProvider, ParsingContext parsingContext) { + parsingContext.Parser = this; + parsingContext.ExcelDataProvider = excelDataProvider; + parsingContext.NameValueProvider = new EpplusNameValueProvider(excelDataProvider); + parsingContext.RangeAddressFactory = new(excelDataProvider); + _parsingContext = parsingContext; + _excelDataProvider = excelDataProvider; + Configure(configuration => { + configuration + .SetLexer( + new Lexer( + _parsingContext.Configuration.FunctionRepository, + _parsingContext.NameValueProvider)) + .SetGraphBuilder(new ExpressionGraphBuilder(excelDataProvider, _parsingContext)) + .SetExpresionCompiler(new ExpressionCompiler()) + .FunctionRepository.LoadModule(new BuiltInFunctions()); + }); + } - private ILexer _lexer; - private IExpressionGraphBuilder _graphBuilder; - private IExpressionCompiler _compiler; + public void Configure(Action<ParsingConfiguration> configMethod) { + configMethod.Invoke(_parsingContext.Configuration); + _lexer = _parsingContext.Configuration.Lexer ?? _lexer; + _graphBuilder = _parsingContext.Configuration.GraphBuilder ?? _graphBuilder; + _compiler = _parsingContext.Configuration.ExpressionCompiler ?? _compiler; + } - public ILexer Lexer { get { return _lexer; } } - public IEnumerable<string> FunctionNames { get { return _parsingContext.Configuration.FunctionRepository.FunctionNames; } } + private ILexer _lexer; + private IExpressionGraphBuilder _graphBuilder; + private IExpressionCompiler _compiler; - internal virtual object Parse(string formula, RangeAddress rangeAddress) - { - using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) - { - var tokens = _lexer.Tokenize(formula); - var graph = _graphBuilder.Build(tokens); - if (graph.Expressions.Count() == 0) - { - return null; - } - return _compiler.Compile(graph.Expressions).Result; - } - } + public ILexer Lexer => _lexer; - internal virtual object Parse(IEnumerable<Token> tokens, string worksheet, string address) - { - var rangeAddress = _parsingContext.RangeAddressFactory.Create(address); - using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) - { - var graph = _graphBuilder.Build(tokens); - if (graph.Expressions.Count() == 0) - { - return null; - } - return _compiler.Compile(graph.Expressions).Result; - } - } - internal virtual object ParseCell(IEnumerable<Token> tokens, string worksheet, int row, int column) - { - var rangeAddress = _parsingContext.RangeAddressFactory.Create(worksheet, column, row); - using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) - { - // _parsingContext.Dependencies.AddFormulaScope(scope); - var graph = _graphBuilder.Build(tokens); - if (graph.Expressions.Count() == 0) - { - return 0d; - } - try - { - var compileResult = _compiler.Compile(graph.Expressions); - // quick solution for the fact that an excelrange can be returned. - var rangeInfo = compileResult.Result as ExcelDataProvider.IRangeInfo; - if (rangeInfo == null) - { - return compileResult.Result ?? 0d; - } - else - { - if (rangeInfo.IsEmpty) - { - return 0d; - } - if (!rangeInfo.IsMulti) - { - return rangeInfo.First().Value ?? 0d; - } - // ok to return multicell if it is a workbook scoped name. - if (string.IsNullOrEmpty(worksheet)) - { - return rangeInfo; - } - if (_parsingContext.Debug) - { - var msg = string.Format("A range with multiple cell was returned at row {0}, column {1}", - row, column); - _parsingContext.Configuration.Logger.Log(_parsingContext, msg); - } - return ExcelErrorValue.Create(eErrorType.Value); - } - } - catch(ExcelErrorValueException ex) - { - if (_parsingContext.Debug) - { - _parsingContext.Configuration.Logger.Log(_parsingContext, ex); - } - return ex.ErrorValue; - } - } - } + public IEnumerable<string> FunctionNames { + get { return _parsingContext.Configuration.FunctionRepository.FunctionNames; } + } - public virtual object Parse(string formula, string address) - { - return Parse(formula, _parsingContext.RangeAddressFactory.Create(address)); - } - - public virtual object Parse(string formula) - { - return Parse(formula, RangeAddress.Empty); - } - - public virtual object ParseAt(string address) - { - Require.That(address).Named("address").IsNotNullOrEmpty(); - var rangeAddress = _parsingContext.RangeAddressFactory.Create(address); - return ParseAt(rangeAddress.Worksheet, rangeAddress.FromRow, rangeAddress.FromCol); - } - - public virtual object ParseAt(string worksheetName, int row, int col) - { - var f = _excelDataProvider.GetRangeFormula(worksheetName, row, col); - if (string.IsNullOrEmpty(f)) - { - return _excelDataProvider.GetRangeValue(worksheetName, row, col); - } - else - { - return Parse(f, _parsingContext.RangeAddressFactory.Create(worksheetName,col,row)); - } - //var dataItem = _excelDataProvider.GetRangeValues(address).FirstOrDefault(); - //if (dataItem == null /*|| (dataItem.Value == null && dataItem.Formula == null)*/) return null; - //if (!string.IsNullOrEmpty(dataItem.Formula)) - //{ - // return Parse(dataItem.Formula, _parsingContext.RangeAddressFactory.Create(address)); - //} - //return Parse(dataItem.Value.ToString(), _parsingContext.RangeAddressFactory.Create(address)); - } - - - internal void InitNewCalc() - { - if(_excelDataProvider!=null) - { - _excelDataProvider.Reset(); - } - } - - // Praveen's Formula Parser - public ExpressionGraph.ExpressionGraph ParseToGraph(string formula) - { - using (var scope = _parsingContext.Scopes.NewScope(RangeAddress.Empty)) - { - var tokens = _lexer.Tokenize(formula); - var graph = _graphBuilder.Build(tokens); - return graph; - } - } + internal virtual object Parse(string formula, RangeAddress rangeAddress) { + using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) { + var tokens = _lexer.Tokenize(formula); + var graph = _graphBuilder.Build(tokens); + if (graph.Expressions.Count() == 0) { + return null; + } + return _compiler.Compile(graph.Expressions).Result; } + } + + internal virtual object Parse(IEnumerable<Token> tokens, string worksheet, string address) { + var rangeAddress = _parsingContext.RangeAddressFactory.Create(address); + using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) { + var graph = _graphBuilder.Build(tokens); + if (graph.Expressions.Count() == 0) { + return null; + } + return _compiler.Compile(graph.Expressions).Result; + } + } + + internal virtual object ParseCell( + IEnumerable<Token> tokens, + string worksheet, + int row, + int column) { + var rangeAddress = _parsingContext.RangeAddressFactory.Create(worksheet, column, row); + using (var scope = _parsingContext.Scopes.NewScope(rangeAddress)) { + // _parsingContext.Dependencies.AddFormulaScope(scope); + var graph = _graphBuilder.Build(tokens); + if (graph.Expressions.Count() == 0) { + return 0d; + } + try { + var compileResult = _compiler.Compile(graph.Expressions); + // quick solution for the fact that an excelrange can be returned. + var rangeInfo = compileResult.Result as ExcelDataProvider.IRangeInfo; + if (rangeInfo == null) { + return compileResult.Result ?? 0d; + } + if (rangeInfo.IsEmpty) { + return 0d; + } + if (!rangeInfo.IsMulti) { + return rangeInfo.First().Value ?? 0d; + } + // ok to return multicell if it is a workbook scoped name. + if (string.IsNullOrEmpty(worksheet)) { + return rangeInfo; + } + if (_parsingContext.Debug) { + var msg = string.Format( + "A range with multiple cell was returned at row {0}, column {1}", + row, + column); + _parsingContext.Configuration.Logger.Log(_parsingContext, msg); + } + return ExcelErrorValue.Create(eErrorType.Value); + } catch (ExcelErrorValueException ex) { + if (_parsingContext.Debug) { + _parsingContext.Configuration.Logger.Log(_parsingContext, ex); + } + return ex.ErrorValue; + } + } + } + + public virtual object Parse(string formula, string address) { + return Parse(formula, _parsingContext.RangeAddressFactory.Create(address)); + } + + public virtual object Parse(string formula) { + return Parse(formula, RangeAddress.Empty); + } + + public virtual object ParseAt(string address) { + Require.That(address).Named("address").IsNotNullOrEmpty(); + var rangeAddress = _parsingContext.RangeAddressFactory.Create(address); + return ParseAt(rangeAddress.Worksheet, rangeAddress.FromRow, rangeAddress.FromCol); + } + + public virtual object ParseAt(string worksheetName, int row, int col) { + var f = _excelDataProvider.GetRangeFormula(worksheetName, row, col); + if (string.IsNullOrEmpty(f)) { + return _excelDataProvider.GetRangeValue(worksheetName, row, col); + } + return Parse(f, _parsingContext.RangeAddressFactory.Create(worksheetName, col, row)); + //var dataItem = _excelDataProvider.GetRangeValues(address).FirstOrDefault(); + //if (dataItem == null /*|| (dataItem.Value == null && dataItem.Formula == null)*/) return null; + //if (!string.IsNullOrEmpty(dataItem.Formula)) + //{ + // return Parse(dataItem.Formula, _parsingContext.RangeAddressFactory.Create(address)); + //} + //return Parse(dataItem.Value.ToString(), _parsingContext.RangeAddressFactory.Create(address)); + } + + internal void InitNewCalc() { + if (_excelDataProvider != null) { + _excelDataProvider.Reset(); + } + } + + // Praveen's Formula Parser + public ExpressionGraph.ExpressionGraph ParseToGraph(string formula) { + using (var scope = _parsingContext.Scopes.NewScope(RangeAddress.Empty)) { + var tokens = _lexer.Tokenize(formula); + var graph = _graphBuilder.Build(tokens); + return graph; + } + } }
diff --git a/EPPlus/FormulaParsing/FormulaParserManager.cs b/EPPlus/FormulaParsing/FormulaParserManager.cs index 51a5234..9d7dc65 100644 --- a/EPPlus/FormulaParsing/FormulaParserManager.cs +++ b/EPPlus/FormulaParsing/FormulaParserManager.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,94 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; -using OfficeOpenXml.FormulaParsing.Logging; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing -{ - /// <summary> - /// Provides access to various functionality regarding - /// excel formula evaluation. - /// </summary> - public class FormulaParserManager - { - private readonly FormulaParser _parser; - internal FormulaParserManager(FormulaParser parser) - { - Require.That(parser).Named("parser").IsNotNull(); - _parser = parser; - } +namespace OfficeOpenXml.FormulaParsing; - /// <summary> - /// Loads a module containing custom functions to the formula parser. By using - /// this method you can add your own implementations of Excel functions, by - /// implementing a <see cref="IFunctionModule"/>. - /// </summary> - /// <param name="module">A <see cref="IFunctionModule"/> containing <see cref="ExcelFunction"/>s.</param> - public void LoadFunctionModule(IFunctionModule module) - { - _parser.Configure(x => x.FunctionRepository.LoadModule(module)); - } +/// <summary> +/// Provides access to various functionality regarding +/// excel formula evaluation. +/// </summary> +public class FormulaParserManager { + private readonly FormulaParser _parser; - /// <summary> - /// If the supplied <paramref name="functionName"/> does not exist, the supplied - /// <paramref name="functionImpl"/> implementation will be added to the formula parser. - /// If it exists, the existing function will be replaced by the supplied <paramref name="functionImpl">function implementation</paramref> - /// </summary> - /// <param name="functionName"></param> - /// <param name="functionImpl"></param> - public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) - { - _parser.Configure(x => x.FunctionRepository.AddOrReplaceFunction(functionName, functionImpl)); - } + internal FormulaParserManager(FormulaParser parser) { + Require.That(parser).Named("parser").IsNotNull(); + _parser = parser; + } - /// <summary> - /// Returns an enumeration of all functions implemented, both the built in functions - /// and functions added using the LoadFunctionModule method of this class. - /// </summary> - /// <returns>Function names in lower case</returns> - public IEnumerable<string> GetImplementedFunctionNames() - { - var fnList = _parser.FunctionNames.ToList(); - fnList.Sort((x, y) => String.Compare(x, y, System.StringComparison.Ordinal)); - return fnList; - } + /// <summary> + /// Loads a module containing custom functions to the formula parser. By using + /// this method you can add your own implementations of Excel functions, by + /// implementing a <see cref="IFunctionModule"/>. + /// </summary> + /// <param name="module">A <see cref="IFunctionModule"/> containing <see cref="ExcelFunction"/>s.</param> + public void LoadFunctionModule(IFunctionModule module) { + _parser.Configure(x => x.FunctionRepository.LoadModule(module)); + } - /// <summary> - /// Parses the supplied <paramref name="formula"/> and returns the result. - /// </summary> - /// <param name="formula"></param> - /// <returns></returns> - public object Parse(string formula) - { - return _parser.Parse(formula); - } + /// <summary> + /// If the supplied <paramref name="functionName"/> does not exist, the supplied + /// <paramref name="functionImpl"/> implementation will be added to the formula parser. + /// If it exists, the existing function will be replaced by the supplied <paramref name="functionImpl">function implementation</paramref> + /// </summary> + /// <param name="functionName"></param> + /// <param name="functionImpl"></param> + public void AddOrReplaceFunction(string functionName, ExcelFunction functionImpl) { + _parser.Configure(x => x.FunctionRepository.AddOrReplaceFunction(functionName, functionImpl)); + } - // Praveen's Parser Support - public ExpressionGraph.ExpressionGraph ParseToGraph(string formula) - { - return _parser.ParseToGraph(formula); - } - } + /// <summary> + /// Returns an enumeration of all functions implemented, both the built in functions + /// and functions added using the LoadFunctionModule method of this class. + /// </summary> + /// <returns>Function names in lower case</returns> + public IEnumerable<string> GetImplementedFunctionNames() { + var fnList = _parser.FunctionNames.ToList(); + fnList.Sort((x, y) => String.Compare(x, y, StringComparison.Ordinal)); + return fnList; + } + + /// <summary> + /// Parses the supplied <paramref name="formula"/> and returns the result. + /// </summary> + /// <param name="formula"></param> + /// <returns></returns> + public object Parse(string formula) { + return _parser.Parse(formula); + } + + // Praveen's Parser Support + public ExpressionGraph.ExpressionGraph ParseToGraph(string formula) { + return _parser.ParseToGraph(formula); + } }
diff --git a/EPPlus/FormulaParsing/INameValueProvider.cs b/EPPlus/FormulaParsing/INameValueProvider.cs index c93bf0d..0a227ae 100644 --- a/EPPlus/FormulaParsing/INameValueProvider.cs +++ b/EPPlus/FormulaParsing/INameValueProvider.cs
@@ -1,16 +1,9 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing -{ - public interface INameValueProvider - { - bool IsNamedValue(string key, string worksheet); +public interface INameValueProvider { + bool IsNamedValue(string key, string worksheet); - object GetNamedValue(string key); + object GetNamedValue(string key); - void Reload(); - } + void Reload(); }
diff --git a/EPPlus/FormulaParsing/IParsingLifetimeEventHandler.cs b/EPPlus/FormulaParsing/IParsingLifetimeEventHandler.cs index 1c6d31b..52fc794 100644 --- a/EPPlus/FormulaParsing/IParsingLifetimeEventHandler.cs +++ b/EPPlus/FormulaParsing/IParsingLifetimeEventHandler.cs
@@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing -{ - public interface IParsingLifetimeEventHandler - { - void ParsingCompleted(); - } +public interface IParsingLifetimeEventHandler { + void ParsingCompleted(); }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ILexer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ILexer.cs index 943fab4..ec3aef5 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/ILexer.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/ILexer.cs
@@ -13,31 +13,28 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public interface ILexer - { - IEnumerable<Token> Tokenize(string input); - IEnumerable<Token> Tokenize(string input, string worksheet); - } +using System.Collections.Generic; + +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; + +public interface ILexer { + IEnumerable<Token> Tokenize(string input); + + IEnumerable<Token> Tokenize(string input, string worksheet); }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs index 3a6ad48..488d4aa 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/ISourceCodeTokenizer.cs
@@ -13,30 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public interface ISourceCodeTokenizer - { - IEnumerable<Token> Tokenize(string input, string worksheet); - } +using System.Collections.Generic; + +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; + +public interface ISourceCodeTokenizer { + IEnumerable<Token> Tokenize(string input, string worksheet); }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs index 55e1a86..9f73dba 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/ISyntacticAnalyzer.cs
@@ -13,30 +13,26 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public interface ISyntacticAnalyzer - { - void Analyze(IEnumerable<Token> tokens); - } +using System.Collections.Generic; + +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; + +public interface ISyntacticAnalyzer { + void Analyze(IEnumerable<Token> tokens); }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs index d330ffe..ab5b170 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenFactory.cs
@@ -13,32 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public interface ITokenFactory - { - Token Create(IEnumerable<Token> tokens, string token); - Token Create(IEnumerable<Token> tokens, string token, string worksheet); - Token Create(string token, TokenType explicitTokenType); - } +using System.Collections.Generic; + +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; + +public interface ITokenFactory { + Token Create(IEnumerable<Token> tokens, string token); + + Token Create(IEnumerable<Token> tokens, string token, string worksheet); + + Token Create(string token, TokenType explicitTokenType); }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs index 6a7f6c4..1028a1c 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenIndexProvider.cs
@@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public interface ITokenIndexProvider - { - int Index { get; } +public interface ITokenIndexProvider { + int Index { get; } - void MoveIndexPointerForward(); - } + void MoveIndexPointerForward(); }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs index db3610b..91fb6b9 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/ITokenSeparatorProvider.cs
@@ -13,35 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public interface ITokenSeparatorProvider - { - IDictionary<string, Token> Tokens { get; } +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - bool IsOperator(string item); +public interface ITokenSeparatorProvider { + IDictionary<string, Token> Tokens { get; } - bool IsPossibleLastPartOfMultipleCharOperator(string part); + bool IsOperator(string item); - } + bool IsPossibleLastPartOfMultipleCharOperator(string part); }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/Lexer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/Lexer.cs index bc5ea18..35f4e8f 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/Lexer.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/Lexer.cs
@@ -13,56 +13,50 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Excel.Functions; + //using OfficeOpenXml.FormulaParsing.Excel.Functions; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class Lexer : ILexer - { - public Lexer(FunctionRepository functionRepository, INameValueProvider nameValueProvider) - :this(new SourceCodeTokenizer(functionRepository, nameValueProvider), new SyntacticAnalyzer()) - { +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - } +public class Lexer : ILexer { + public Lexer(FunctionRepository functionRepository, INameValueProvider nameValueProvider) + : this( + new SourceCodeTokenizer(functionRepository, nameValueProvider), + new SyntacticAnalyzer()) {} - public Lexer(ISourceCodeTokenizer tokenizer, ISyntacticAnalyzer analyzer) - { - _tokenizer = tokenizer; - _analyzer = analyzer; - } + public Lexer(ISourceCodeTokenizer tokenizer, ISyntacticAnalyzer analyzer) { + _tokenizer = tokenizer; + _analyzer = analyzer; + } - private readonly ISourceCodeTokenizer _tokenizer; - private readonly ISyntacticAnalyzer _analyzer; + private readonly ISourceCodeTokenizer _tokenizer; + private readonly ISyntacticAnalyzer _analyzer; - public IEnumerable<Token> Tokenize(string input) - { - return Tokenize(input, null); - } - public IEnumerable<Token> Tokenize(string input, string worksheet) - { - var tokens = _tokenizer.Tokenize(input, worksheet); - _analyzer.Analyze(tokens); - return tokens; - } - } + public IEnumerable<Token> Tokenize(string input) { + return Tokenize(input, null); + } + + public IEnumerable<Token> Tokenize(string input, string worksheet) { + var tokens = _tokenizer.Tokenize(input, worksheet); + _analyzer.Analyze(tokens); + return tokens; + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs index b8265a1..01e9bf9 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/SourceCodeTokenizer.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,341 +13,286 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using System.Text.RegularExpressions; using OfficeOpenXml.FormulaParsing.Excel.Functions; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class SourceCodeTokenizer : ISourceCodeTokenizer - { - public static ISourceCodeTokenizer Default - { - get { return new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty); } - } - public SourceCodeTokenizer(IFunctionNameProvider functionRepository, INameValueProvider nameValueProvider) - : this(new TokenFactory(functionRepository, nameValueProvider), new TokenSeparatorProvider()) - { +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - } - public SourceCodeTokenizer(ITokenFactory tokenFactory, ITokenSeparatorProvider tokenProvider) - { - _tokenFactory = tokenFactory; - _tokenProvider = tokenProvider; - } +public class SourceCodeTokenizer : ISourceCodeTokenizer { + public static ISourceCodeTokenizer Default => + new SourceCodeTokenizer(FunctionNameProvider.Empty, NameValueProvider.Empty); - private readonly ITokenSeparatorProvider _tokenProvider; - private readonly ITokenFactory _tokenFactory; + public SourceCodeTokenizer( + IFunctionNameProvider functionRepository, + INameValueProvider nameValueProvider) + : this( + new TokenFactory(functionRepository, nameValueProvider), + new TokenSeparatorProvider()) {} - public IEnumerable<Token> Tokenize(string input) - { - return Tokenize(input, null); - } - public IEnumerable<Token> Tokenize(string input, string worksheet) - { - if (string.IsNullOrEmpty(input)) - { - return Enumerable.Empty<Token>(); - } - // MA 1401: Ignore leading plus in formula. - input = input.TrimStart('+'); - var context = new TokenizerContext(input); + public SourceCodeTokenizer(ITokenFactory tokenFactory, ITokenSeparatorProvider tokenProvider) { + _tokenFactory = tokenFactory; + _tokenProvider = tokenProvider; + } - bool isSingleQuoteString = false; - for (int i = 0; i<context.FormulaChars.Length;i++) - { - var c = context.FormulaChars[i]; - Token tokenSeparator; - if (CharIsTokenSeparator(c, out tokenSeparator)) - { - if (context.IsInString) - { - if (IsDoubleQuote(tokenSeparator, i, context)) - { - i ++; - context.AppendToCurrentToken(c); - continue; - } - if(tokenSeparator.TokenType != TokenType.String) - { - context.AppendToCurrentToken(c); - continue; - } - // CHANGE 2 - if ((isSingleQuoteString && c != '\'') || (!isSingleQuoteString && c != '"')) - { - context.AppendToCurrentToken(c); - continue; - } - } - if (tokenSeparator.TokenType == TokenType.OpeningBracket) - { - context.AppendToCurrentToken(c); - context.BracketCount++; - continue; - } - if (tokenSeparator.TokenType == TokenType.ClosingBracket) - { - context.AppendToCurrentToken(c); - context.BracketCount--; - continue; - } - if (context.BracketCount > 0) - { - context.AppendToCurrentToken(c); - continue; - } - // two operators in sequence could be "<=" or ">=" - if (IsPartOfMultipleCharSeparator(context, c)) - { - var sOp = context.LastToken.Value + c.ToString(CultureInfo.InvariantCulture); - var op = _tokenProvider.Tokens[sOp]; - context.ReplaceLastToken(op); - context.NewToken(); - continue; - } - if (tokenSeparator.TokenType == TokenType.String) - { - // CHANGE3 : - isSingleQuoteString = (c == '\''); - if (context.LastToken != null && context.LastToken.TokenType == TokenType.OpeningEnumerable) - { - // context.AppendToCurrentToken(c); // Praveen's change of 10/28/2015 - context.ToggleIsInString(); - continue; - } - if (context.LastToken != null && context.LastToken.TokenType == TokenType.String) - { - context.AddToken(!context.CurrentTokenHasValue - ? new Token(string.Empty, TokenType.StringContent) - : new Token(context.CurrentToken, TokenType.StringContent)); - } - context.AddToken(new Token("\"", TokenType.String)); - context.ToggleIsInString(); - context.NewToken(); - continue; - } - if (context.CurrentTokenHasValue) - { - if (Regex.IsMatch(context.CurrentToken, "^\"*$")) - { - context.AddToken(_tokenFactory.Create(context.CurrentToken, TokenType.StringContent)); - } - else - { - context.AddToken(CreateToken(context, worksheet)); - } - - - //If the a next token is an opening parantheses and the previous token is interpeted as an address or name, then the currenct token is a function - if(tokenSeparator.TokenType==TokenType.OpeningParenthesis && (context.LastToken.TokenType==TokenType.ExcelAddress || context.LastToken.TokenType==TokenType.NameValue)) - { - context.LastToken.TokenType=TokenType.Function; - } - } - if (tokenSeparator.Value == "-") - { - if (TokenIsNegator(context)) - { - context.AddToken(new Token("-", TokenType.Negator)); - continue; - } - } - context.AddToken(tokenSeparator); - context.NewToken(); - continue; - } - context.AppendToCurrentToken(c); - } - if (context.CurrentTokenHasValue) - { - context.AddToken(CreateToken(context, worksheet)); - } + private readonly ITokenSeparatorProvider _tokenProvider; + private readonly ITokenFactory _tokenFactory; - CleanupTokens(context, _tokenProvider.Tokens); + public IEnumerable<Token> Tokenize(string input) { + return Tokenize(input, null); + } - return context.Result; - } - - private static bool IsDoubleQuote(Token tokenSeparator, int formulaCharIndex, TokenizerContext context) - { - return tokenSeparator.TokenType == TokenType.String && formulaCharIndex + 1 < context.FormulaChars.Length && context.FormulaChars[formulaCharIndex + 1] == '\"'; - } - - - private static void CleanupTokens(TokenizerContext context, IDictionary<string, Token> tokens) - { - for (int i = 0; i < context.Result.Count; i++) - { - var token=context.Result[i]; - if (token.TokenType == TokenType.Unrecognized) - { - if (i < context.Result.Count - 1) - { - if (context.Result[i+1].TokenType == TokenType.OpeningParenthesis) - { - token.TokenType = TokenType.Function; - } - else - { - token.TokenType = TokenType.NameValue; - } - } - else - { - token.TokenType = TokenType.NameValue; - } - } - else if (token.TokenType == TokenType.Function) - { - if (i < context.Result.Count - 1) - { - if (context.Result[i + 1].TokenType == TokenType.OpeningParenthesis) - { - token.TokenType = TokenType.Function; - } - else - { - token.TokenType = TokenType.Unrecognized; - } - } - else - { - token.TokenType = TokenType.Unrecognized; - } - } - else if ((token.TokenType == TokenType.Operator || token.TokenType == TokenType.Negator) && i < context.Result.Count - 1 && - (token.Value=="+" || token.Value=="-")) - { - if (i > 0 && token.Value == "+") //Remove any + with an opening parenthesis before. - { - if (context.Result[i - 1].TokenType == TokenType.OpeningParenthesis) - { - context.Result.RemoveAt(i); - SetNegatorOperator(context, i, tokens); - i--; - continue; - } - } - - var nextToken = context.Result[i + 1]; - if (nextToken.TokenType == TokenType.Operator || nextToken.TokenType == TokenType.Negator) - { - if (token.Value == "+" && (nextToken.Value=="+" || nextToken.Value == "-")) - { - //Remove first - context.Result.RemoveAt(i); - SetNegatorOperator(context, i, tokens); - i--; - } - else if (token.Value == "-" && nextToken.Value == "+") - { - //Remove second - context.Result.RemoveAt(i+1); - SetNegatorOperator(context, i, tokens); - i--; - } - else if (token.Value == "-" && nextToken.Value == "-") - { - //Remove first and set operator to + - context.Result.RemoveAt(i); - if (i == 0) - { - context.Result.RemoveAt(i+1); - i += 2; - } - else - { - //context.Result[i].TokenType = TokenType.Operator; - //context.Result[i].Value = "+"; - context.Result[i] = tokens["+"]; - SetNegatorOperator(context, i, tokens); - i--; - } - } - } - } - } - } - - private static void SetNegatorOperator(TokenizerContext context, int i, IDictionary<string, Token> tokens) - { - if (context.Result[i].Value == "-" && i > 0 && (context.Result[i].TokenType == TokenType.Operator || context.Result[i].TokenType == TokenType.Negator)) - { - if (TokenIsNegator(context.Result[i - 1])) - { - context.Result[i] = new Token("-", TokenType.Negator); - } - else - { - context.Result[i] = tokens["-"]; - } - } - } - - private static bool TokenIsNegator(TokenizerContext context) - { - return TokenIsNegator(context.LastToken); - } - private static bool TokenIsNegator(Token t) - { - return t == null - || - t.TokenType == TokenType.Operator - || - t.TokenType == TokenType.OpeningParenthesis - || - t.TokenType == TokenType.Comma - || - t.TokenType == TokenType.SemiColon - || - t.TokenType == TokenType.OpeningEnumerable; - } - - private bool IsPartOfMultipleCharSeparator(TokenizerContext context, char c) - { - var lastToken = context.LastToken != null ? context.LastToken.Value : string.Empty; - return _tokenProvider.IsOperator(lastToken) - && _tokenProvider.IsPossibleLastPartOfMultipleCharOperator(c.ToString(CultureInfo.InvariantCulture)) - && !context.CurrentTokenHasValue; - } - - private Token CreateToken(TokenizerContext context, string worksheet) - { - if (context.CurrentToken == "-") - { - if (context.LastToken == null && context.LastToken.TokenType == TokenType.Operator) - { - return new Token("-", TokenType.Negator); - } - } - return _tokenFactory.Create(context.Result, context.CurrentToken, worksheet); - } - - private bool CharIsTokenSeparator(char c, out Token token) - { - var result = _tokenProvider.Tokens.ContainsKey(c.ToString()); - token = result ? token = _tokenProvider.Tokens[c.ToString()] : null; - return result; - } + public IEnumerable<Token> Tokenize(string input, string worksheet) { + if (string.IsNullOrEmpty(input)) { + return Enumerable.Empty<Token>(); } + // MA 1401: Ignore leading plus in formula. + input = input.TrimStart('+'); + var context = new TokenizerContext(input); + + bool isSingleQuoteString = false; + for (int i = 0; i < context.FormulaChars.Length; i++) { + var c = context.FormulaChars[i]; + Token tokenSeparator; + if (CharIsTokenSeparator(c, out tokenSeparator)) { + if (context.IsInString) { + if (IsDoubleQuote(tokenSeparator, i, context)) { + i++; + context.AppendToCurrentToken(c); + continue; + } + if (tokenSeparator.TokenType != TokenType.String) { + context.AppendToCurrentToken(c); + continue; + } + // CHANGE 2 + if ((isSingleQuoteString && c != '\'') || (!isSingleQuoteString && c != '"')) { + context.AppendToCurrentToken(c); + continue; + } + } + if (tokenSeparator.TokenType == TokenType.OpeningBracket) { + context.AppendToCurrentToken(c); + context.BracketCount++; + continue; + } + if (tokenSeparator.TokenType == TokenType.ClosingBracket) { + context.AppendToCurrentToken(c); + context.BracketCount--; + continue; + } + if (context.BracketCount > 0) { + context.AppendToCurrentToken(c); + continue; + } + // two operators in sequence could be "<=" or ">=" + if (IsPartOfMultipleCharSeparator(context, c)) { + var sOp = context.LastToken.Value + c.ToString(CultureInfo.InvariantCulture); + var op = _tokenProvider.Tokens[sOp]; + context.ReplaceLastToken(op); + context.NewToken(); + continue; + } + if (tokenSeparator.TokenType == TokenType.String) { + // CHANGE3 : + isSingleQuoteString = (c == '\''); + if (context.LastToken != null + && context.LastToken.TokenType == TokenType.OpeningEnumerable) { + // context.AppendToCurrentToken(c); // Praveen's change of 10/28/2015 + context.ToggleIsInString(); + continue; + } + if (context.LastToken != null && context.LastToken.TokenType == TokenType.String) { + context.AddToken( + !context.CurrentTokenHasValue + ? new(string.Empty, TokenType.StringContent) + : new Token(context.CurrentToken, TokenType.StringContent)); + } + context.AddToken(new("\"", TokenType.String)); + context.ToggleIsInString(); + context.NewToken(); + continue; + } + if (context.CurrentTokenHasValue) { + if (Regex.IsMatch(context.CurrentToken, "^\"*$")) { + context.AddToken(_tokenFactory.Create(context.CurrentToken, TokenType.StringContent)); + } else { + context.AddToken(CreateToken(context, worksheet)); + } + + //If the a next token is an opening parantheses and the previous token is interpeted as an address or name, then the currenct token is a function + if (tokenSeparator.TokenType == TokenType.OpeningParenthesis + && (context.LastToken.TokenType == TokenType.ExcelAddress + || context.LastToken.TokenType == TokenType.NameValue)) { + context.LastToken.TokenType = TokenType.Function; + } + } + if (tokenSeparator.Value == "-") { + if (TokenIsNegator(context)) { + context.AddToken(new("-", TokenType.Negator)); + continue; + } + } + context.AddToken(tokenSeparator); + context.NewToken(); + continue; + } + context.AppendToCurrentToken(c); + } + if (context.CurrentTokenHasValue) { + context.AddToken(CreateToken(context, worksheet)); + } + + CleanupTokens(context, _tokenProvider.Tokens); + + return context.Result; + } + + private static bool IsDoubleQuote( + Token tokenSeparator, + int formulaCharIndex, + TokenizerContext context) { + return tokenSeparator.TokenType == TokenType.String + && formulaCharIndex + 1 < context.FormulaChars.Length + && context.FormulaChars[formulaCharIndex + 1] == '\"'; + } + + private static void CleanupTokens(TokenizerContext context, IDictionary<string, Token> tokens) { + for (int i = 0; i < context.Result.Count; i++) { + var token = context.Result[i]; + if (token.TokenType == TokenType.Unrecognized) { + if (i < context.Result.Count - 1) { + if (context.Result[i + 1].TokenType == TokenType.OpeningParenthesis) { + token.TokenType = TokenType.Function; + } else { + token.TokenType = TokenType.NameValue; + } + } else { + token.TokenType = TokenType.NameValue; + } + } else if (token.TokenType == TokenType.Function) { + if (i < context.Result.Count - 1) { + if (context.Result[i + 1].TokenType == TokenType.OpeningParenthesis) { + token.TokenType = TokenType.Function; + } else { + token.TokenType = TokenType.Unrecognized; + } + } else { + token.TokenType = TokenType.Unrecognized; + } + } else if ((token.TokenType == TokenType.Operator || token.TokenType == TokenType.Negator) + && i < context.Result.Count - 1 + && (token.Value == "+" || token.Value == "-")) { + if (i > 0 + && token.Value + == "+") //Remove any + with an opening parenthesis before. + { + if (context.Result[i - 1].TokenType == TokenType.OpeningParenthesis) { + context.Result.RemoveAt(i); + SetNegatorOperator(context, i, tokens); + i--; + continue; + } + } + + var nextToken = context.Result[i + 1]; + if (nextToken.TokenType == TokenType.Operator || nextToken.TokenType == TokenType.Negator) { + if (token.Value == "+" && (nextToken.Value == "+" || nextToken.Value == "-")) { + //Remove first + context.Result.RemoveAt(i); + SetNegatorOperator(context, i, tokens); + i--; + } else if (token.Value == "-" && nextToken.Value == "+") { + //Remove second + context.Result.RemoveAt(i + 1); + SetNegatorOperator(context, i, tokens); + i--; + } else if (token.Value == "-" && nextToken.Value == "-") { + //Remove first and set operator to + + context.Result.RemoveAt(i); + if (i == 0) { + context.Result.RemoveAt(i + 1); + i += 2; + } else { + //context.Result[i].TokenType = TokenType.Operator; + //context.Result[i].Value = "+"; + context.Result[i] = tokens["+"]; + SetNegatorOperator(context, i, tokens); + i--; + } + } + } + } + } + } + + private static void SetNegatorOperator( + TokenizerContext context, + int i, + IDictionary<string, Token> tokens) { + if (context.Result[i].Value == "-" + && i > 0 + && (context.Result[i].TokenType == TokenType.Operator + || context.Result[i].TokenType == TokenType.Negator)) { + if (TokenIsNegator(context.Result[i - 1])) { + context.Result[i] = new("-", TokenType.Negator); + } else { + context.Result[i] = tokens["-"]; + } + } + } + + private static bool TokenIsNegator(TokenizerContext context) { + return TokenIsNegator(context.LastToken); + } + + private static bool TokenIsNegator(Token t) { + return t == null + || t.TokenType == TokenType.Operator + || t.TokenType == TokenType.OpeningParenthesis + || t.TokenType == TokenType.Comma + || t.TokenType == TokenType.SemiColon + || t.TokenType == TokenType.OpeningEnumerable; + } + + private bool IsPartOfMultipleCharSeparator(TokenizerContext context, char c) { + var lastToken = context.LastToken != null ? context.LastToken.Value : string.Empty; + return _tokenProvider.IsOperator(lastToken) + && _tokenProvider.IsPossibleLastPartOfMultipleCharOperator( + c.ToString(CultureInfo.InvariantCulture)) + && !context.CurrentTokenHasValue; + } + + private Token CreateToken(TokenizerContext context, string worksheet) { + if (context.CurrentToken == "-") { + if (context.LastToken == null && context.LastToken.TokenType == TokenType.Operator) { + return new("-", TokenType.Negator); + } + } + return _tokenFactory.Create(context.Result, context.CurrentToken, worksheet); + } + + private bool CharIsTokenSeparator(char c, out Token token) { + var result = _tokenProvider.Tokens.ContainsKey(c.ToString()); + token = result ? token = _tokenProvider.Tokens[c.ToString()] : null; + return result; + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs b/EPPlus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs index 0666220..e771aaf 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/SyntacticAnalyzer.cs
@@ -13,90 +13,77 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.Exceptions; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class SyntacticAnalyzer : ISyntacticAnalyzer - { - private class AnalyzingContext - { - public int NumberOfOpenedParentheses { get; set; } - public int NumberOfClosedParentheses { get; set; } - public int OpenedStrings { get; set; } - public int ClosedStrings { get; set; } - public bool IsInString { get; set; } - } - public void Analyze(IEnumerable<Token> tokens) - { - var context = new AnalyzingContext(); - foreach (var token in tokens) - { - if (token.TokenType == TokenType.Unrecognized) - { - throw new UnrecognizedTokenException(token); - } - EnsureParenthesesAreWellFormed(token, context); - EnsureStringsAreWellFormed(token, context); - } - Validate(context); - } +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - private static void Validate(AnalyzingContext context) - { - if (context.NumberOfOpenedParentheses != context.NumberOfClosedParentheses) - { - throw new FormatException("Number of opened and closed parentheses does not match"); - } - if (context.OpenedStrings != context.ClosedStrings) - { - throw new FormatException("Unterminated string"); - } - } +public class SyntacticAnalyzer : ISyntacticAnalyzer { + private class AnalyzingContext { + public int NumberOfOpenedParentheses { get; set; } - private void EnsureParenthesesAreWellFormed(Token token, AnalyzingContext context) - { - if (token.TokenType == TokenType.OpeningParenthesis) - { - context.NumberOfOpenedParentheses++; - } - else if (token.TokenType == TokenType.ClosingParenthesis) - { - context.NumberOfClosedParentheses++; - } - } + public int NumberOfClosedParentheses { get; set; } - private void EnsureStringsAreWellFormed(Token token, AnalyzingContext context) - { - if (!context.IsInString && token.TokenType == TokenType.String) - { - context.IsInString = true; - context.OpenedStrings++; - } - else if (context.IsInString && token.TokenType == TokenType.String) - { - context.IsInString = false; - context.ClosedStrings++; - } - } + public int OpenedStrings { get; set; } + + public int ClosedStrings { get; set; } + + public bool IsInString { get; set; } + } + + public void Analyze(IEnumerable<Token> tokens) { + var context = new AnalyzingContext(); + foreach (var token in tokens) { + if (token.TokenType == TokenType.Unrecognized) { + throw new UnrecognizedTokenException(token); + } + EnsureParenthesesAreWellFormed(token, context); + EnsureStringsAreWellFormed(token, context); } + Validate(context); + } + + private static void Validate(AnalyzingContext context) { + if (context.NumberOfOpenedParentheses != context.NumberOfClosedParentheses) { + throw new FormatException("Number of opened and closed parentheses does not match"); + } + if (context.OpenedStrings != context.ClosedStrings) { + throw new FormatException("Unterminated string"); + } + } + + private void EnsureParenthesesAreWellFormed(Token token, AnalyzingContext context) { + if (token.TokenType == TokenType.OpeningParenthesis) { + context.NumberOfOpenedParentheses++; + } else if (token.TokenType == TokenType.ClosingParenthesis) { + context.NumberOfClosedParentheses++; + } + } + + private void EnsureStringsAreWellFormed(Token token, AnalyzingContext context) { + if (!context.IsInString && token.TokenType == TokenType.String) { + context.IsInString = true; + context.OpenedStrings++; + } else if (context.IsInString && token.TokenType == TokenType.String) { + context.IsInString = false; + context.ClosedStrings++; + } + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs b/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs index 1de9b99..f3faa0c 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs
@@ -13,63 +13,49 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class Token - { - public Token(string token, TokenType tokenType) - { - Value = token; - TokenType = tokenType; - } +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - public string Value { get; internal set; } +public class Token { + public Token(string token, TokenType tokenType) { + Value = token; + TokenType = tokenType; + } - public TokenType TokenType { get; internal set; } + public string Value { get; internal set; } - public void Append(string stringToAppend) - { - Value += stringToAppend; - } + public TokenType TokenType { get; internal set; } - public bool IsNegated { get; private set; } - - public void Negate() - { + public void Append(string stringToAppend) { + Value += stringToAppend; + } - if ( - TokenType == TokenType.Decimal - || - TokenType == TokenType.Integer - || - TokenType == TokenType.ExcelAddress) - { - IsNegated = true; - } - } - public override string ToString() - { - return TokenType.ToString() + ", " + Value; - } + public bool IsNegated { get; private set; } + + public void Negate() { + if (TokenType == TokenType.Decimal + || TokenType == TokenType.Integer + || TokenType == TokenType.ExcelAddress) { + IsNegated = true; } + } + + public override string ToString() { + return TokenType + ", " + Value; + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs index 3817df2..96c87a3 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenFactory.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,155 +13,129 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) * Jan Källman Replaced Adress validate 2013-03-01 * *******************************************************************************/ + using System; using System.Collections.Generic; using System.Globalization; using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing; using OfficeOpenXml.FormulaParsing.Excel.Functions; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.Utilities; -using OfficeOpenXml; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class TokenFactory : ITokenFactory - { - public TokenFactory(IFunctionNameProvider functionRepository, INameValueProvider nameValueProvider) - : this(new TokenSeparatorProvider(), nameValueProvider, functionRepository) - { +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - } +public class TokenFactory : ITokenFactory { + public TokenFactory( + IFunctionNameProvider functionRepository, + INameValueProvider nameValueProvider) + : this(new TokenSeparatorProvider(), nameValueProvider, functionRepository) {} - public TokenFactory(ITokenSeparatorProvider tokenSeparatorProvider, INameValueProvider nameValueProvider, IFunctionNameProvider functionNameProvider) - { - _tokenSeparatorProvider = tokenSeparatorProvider; - _functionNameProvider = functionNameProvider; - _nameValueProvider = nameValueProvider; - } + public TokenFactory( + ITokenSeparatorProvider tokenSeparatorProvider, + INameValueProvider nameValueProvider, + IFunctionNameProvider functionNameProvider) { + _tokenSeparatorProvider = tokenSeparatorProvider; + _functionNameProvider = functionNameProvider; + _nameValueProvider = nameValueProvider; + } - private readonly ITokenSeparatorProvider _tokenSeparatorProvider; - private readonly IFunctionNameProvider _functionNameProvider; - private readonly INameValueProvider _nameValueProvider; - public Token Create(IEnumerable<Token> tokens, string token) - { - return Create(tokens, token, null); - } - public Token Create(IEnumerable<Token> tokens, string token, string worksheet) - { - Token tokenSeparator = null; - if (_tokenSeparatorProvider.Tokens.TryGetValue(token, out tokenSeparator)) - { - return tokenSeparator; - } - var tokenList = (IList<Token>)tokens; - //Address with worksheet-string before /JK - if (token.StartsWith("!") && tokenList[tokenList.Count-1].TokenType == TokenType.String) - { - string addr = ""; - var i = tokenList.Count - 2; - if (i > 0) - { - if (tokenList[i].TokenType == TokenType.StringContent) - { - addr = "'" + tokenList[i].Value.Replace("'", "''") + "'"; - } - else - { - throw(new ArgumentException(string.Format("Invalid formula token sequence near {0}",token))); - } - //Remove the string tokens and content - tokenList.RemoveAt(tokenList.Count - 1); - tokenList.RemoveAt(tokenList.Count - 1); - tokenList.RemoveAt(tokenList.Count - 1); + private readonly ITokenSeparatorProvider _tokenSeparatorProvider; + private readonly IFunctionNameProvider _functionNameProvider; + private readonly INameValueProvider _nameValueProvider; - return new Token(addr + token, TokenType.ExcelAddress); - } - else - { - throw(new ArgumentException(string.Format("Invalid formula token sequence near {0}",token))); - } - - } + public Token Create(IEnumerable<Token> tokens, string token) { + return Create(tokens, token, null); + } - if (tokens.Any() && tokens.Last().TokenType == TokenType.String) - { - return new Token(token, TokenType.StringContent); - } - if (!string.IsNullOrEmpty(token)) - { - token = token.Trim(); - } - if (Regex.IsMatch(token, RegexConstants.Decimal)) - { - return new Token(token, TokenType.Decimal); - } - if(Regex.IsMatch(token, RegexConstants.Integer)) - { - return new Token(token, TokenType.Integer); - } - if (Regex.IsMatch(token, RegexConstants.Boolean, RegexOptions.IgnoreCase)) - { - return new Token(token, TokenType.Boolean); - } - if (token.ToUpper(CultureInfo.InvariantCulture).Contains("#REF!")) - { - return new Token(token, TokenType.InvalidReference); - } - if (token.ToUpper(CultureInfo.InvariantCulture) == "#NUM!") - { - return new Token(token, TokenType.NumericError); - } - if (token.ToUpper(CultureInfo.InvariantCulture) == "#VALUE!") - { - return new Token(token, TokenType.ValueDataTypeError); - } - if (token.ToUpper(CultureInfo.InvariantCulture) == "#NULL!") - { - return new Token(token, TokenType.Null); - } - if (_nameValueProvider != null && _nameValueProvider.IsNamedValue(token, worksheet)) - { - return new Token(token, TokenType.NameValue); - } - if (_functionNameProvider.IsFunctionName(token)) - { - return new Token(token, TokenType.Function); - } - if (tokenList.Count > 0 && tokenList[tokenList.Count - 1].TokenType == TokenType.OpeningEnumerable) - { - return new Token(token, TokenType.Enumerable); - } - var at = OfficeOpenXml.ExcelAddressBase.IsValid(token); - if (at==ExcelAddressBase.AddressType.InternalAddress) - { - return new Token(token.ToUpper(CultureInfo.InvariantCulture), TokenType.ExcelAddress); - } - return new Token(token, TokenType.Unrecognized); - - } - - public Token Create(string token, TokenType explicitTokenType) - { - return new Token(token, explicitTokenType); - } + public Token Create(IEnumerable<Token> tokens, string token, string worksheet) { + Token tokenSeparator = null; + if (_tokenSeparatorProvider.Tokens.TryGetValue(token, out tokenSeparator)) { + return tokenSeparator; } + var tokenList = (IList<Token>)tokens; + //Address with worksheet-string before /JK + if (token.StartsWith("!") && tokenList[tokenList.Count - 1].TokenType == TokenType.String) { + string addr = ""; + var i = tokenList.Count - 2; + if (i > 0) { + if (tokenList[i].TokenType == TokenType.StringContent) { + addr = "'" + tokenList[i].Value.Replace("'", "''") + "'"; + } else { + throw (new ArgumentException( + string.Format("Invalid formula token sequence near {0}", token))); + } + //Remove the string tokens and content + tokenList.RemoveAt(tokenList.Count - 1); + tokenList.RemoveAt(tokenList.Count - 1); + tokenList.RemoveAt(tokenList.Count - 1); + + return new(addr + token, TokenType.ExcelAddress); + } + throw (new ArgumentException( + string.Format("Invalid formula token sequence near {0}", token))); + } + + if (tokens.Any() && tokens.Last().TokenType == TokenType.String) { + return new(token, TokenType.StringContent); + } + if (!string.IsNullOrEmpty(token)) { + token = token.Trim(); + } + if (Regex.IsMatch(token, RegexConstants.Decimal)) { + return new(token, TokenType.Decimal); + } + if (Regex.IsMatch(token, RegexConstants.Integer)) { + return new(token, TokenType.Integer); + } + if (Regex.IsMatch(token, RegexConstants.Boolean, RegexOptions.IgnoreCase)) { + return new(token, TokenType.Boolean); + } + if (token.ToUpper(CultureInfo.InvariantCulture).Contains("#REF!")) { + return new(token, TokenType.InvalidReference); + } + if (token.ToUpper(CultureInfo.InvariantCulture) == "#NUM!") { + return new(token, TokenType.NumericError); + } + if (token.ToUpper(CultureInfo.InvariantCulture) == "#VALUE!") { + return new(token, TokenType.ValueDataTypeError); + } + if (token.ToUpper(CultureInfo.InvariantCulture) == "#NULL!") { + return new(token, TokenType.Null); + } + if (_nameValueProvider != null && _nameValueProvider.IsNamedValue(token, worksheet)) { + return new(token, TokenType.NameValue); + } + if (_functionNameProvider.IsFunctionName(token)) { + return new(token, TokenType.Function); + } + if (tokenList.Count > 0 + && tokenList[tokenList.Count - 1].TokenType == TokenType.OpeningEnumerable) { + return new(token, TokenType.Enumerable); + } + var at = ExcelAddressBase.IsValid(token); + if (at == ExcelAddressBase.AddressType.InternalAddress) { + return new(token.ToUpper(CultureInfo.InvariantCulture), TokenType.ExcelAddress); + } + return new(token, TokenType.Unrecognized); + } + + public Token Create(string token, TokenType explicitTokenType) { + return new(token, explicitTokenType); + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenHandler.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenHandler.cs index 8e86169..8c2a271 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenHandler.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenHandler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,146 +13,120 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2015-12-28 *******************************************************************************/ -using OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers; using System.Text.RegularExpressions; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class TokenHandler : ITokenIndexProvider - { - public TokenHandler(TokenizerContext context, ITokenFactory tokenFactory, ITokenSeparatorProvider tokenProvider) - { - _context = context; - _tokenFactory = tokenFactory; - _tokenProvider = tokenProvider; - } - - private readonly TokenizerContext _context; - private readonly ITokenSeparatorProvider _tokenProvider; - private readonly ITokenFactory _tokenFactory; - private int _tokenIndex = -1; - - public string Worksheet { get; set; } - - public bool HasMore() - { - return _tokenIndex < (_context.FormulaChars.Length - 1); - } - - public void Next() - { - _tokenIndex++; - Handle(); - } - - private void Handle() - { - var c = _context.FormulaChars[_tokenIndex]; - Token tokenSeparator; - if (CharIsTokenSeparator(c, out tokenSeparator)) - { - if (TokenSeparatorHandler.Handle(c, tokenSeparator, _context, this)) - { - return; - } - - if (_context.CurrentTokenHasValue) - { - if (Regex.IsMatch(_context.CurrentToken, "^\"*$")) - { - _context.AddToken(_tokenFactory.Create(_context.CurrentToken, TokenType.StringContent)); - } - else - { - _context.AddToken(CreateToken(_context, Worksheet)); - } - - - //If the a next token is an opening parantheses and the previous token is interpeted as an address or name, then the currenct token is a function - if (tokenSeparator.TokenType == TokenType.OpeningParenthesis && (_context.LastToken.TokenType == TokenType.ExcelAddress || _context.LastToken.TokenType == TokenType.NameValue)) - { - _context.LastToken.TokenType = TokenType.Function; - } - } - if (tokenSeparator.Value == "-") - { - if (TokenIsNegator(_context)) - { - _context.AddToken(new Token("-", TokenType.Negator)); - return; - } - } - _context.AddToken(tokenSeparator); - _context.NewToken(); - return; - } - _context.AppendToCurrentToken(c); - } - - private bool CharIsTokenSeparator(char c, out Token token) - { - var result = _tokenProvider.Tokens.ContainsKey(c.ToString()); - token = result ? token = _tokenProvider.Tokens[c.ToString()] : null; - return result; - } - - - - private static bool TokenIsNegator(TokenizerContext context) - { - return TokenIsNegator(context.LastToken); - } - private static bool TokenIsNegator(Token t) - { - return t == null - || - t.TokenType == TokenType.Operator - || - t.TokenType == TokenType.OpeningParenthesis - || - t.TokenType == TokenType.Comma - || - t.TokenType == TokenType.SemiColon - || - t.TokenType == TokenType.OpeningEnumerable; - } - - private Token CreateToken(TokenizerContext context, string worksheet) - { - if (context.CurrentToken == "-") - { - if (context.LastToken == null && context.LastToken.TokenType == TokenType.Operator) - { - return new Token("-", TokenType.Negator); - } - } - return _tokenFactory.Create(context.Result, context.CurrentToken, worksheet); - } - - int ITokenIndexProvider.Index - { - get { return _tokenIndex; } - } - - - void ITokenIndexProvider.MoveIndexPointerForward() - { - _tokenIndex++; - } +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis { + public class TokenHandler : ITokenIndexProvider { + public TokenHandler( + TokenizerContext context, + ITokenFactory tokenFactory, + ITokenSeparatorProvider tokenProvider) { + _context = context; + _tokenFactory = tokenFactory; + _tokenProvider = tokenProvider; } + + private readonly TokenizerContext _context; + private readonly ITokenSeparatorProvider _tokenProvider; + private readonly ITokenFactory _tokenFactory; + private int _tokenIndex = -1; + + public string Worksheet { get; set; } + + public bool HasMore() { + return _tokenIndex < (_context.FormulaChars.Length - 1); + } + + public void Next() { + _tokenIndex++; + Handle(); + } + + private void Handle() { + var c = _context.FormulaChars[_tokenIndex]; + Token tokenSeparator; + if (CharIsTokenSeparator(c, out tokenSeparator)) { + if (TokenSeparatorHandler.Handle(c, tokenSeparator, _context, this)) { + return; + } + + if (_context.CurrentTokenHasValue) { + if (Regex.IsMatch(_context.CurrentToken, "^\"*$")) { + _context.AddToken(_tokenFactory.Create(_context.CurrentToken, TokenType.StringContent)); + } else { + _context.AddToken(CreateToken(_context, Worksheet)); + } + + //If the a next token is an opening parantheses and the previous token is interpeted as an address or name, then the currenct token is a function + if (tokenSeparator.TokenType == TokenType.OpeningParenthesis + && (_context.LastToken.TokenType == TokenType.ExcelAddress + || _context.LastToken.TokenType == TokenType.NameValue)) { + _context.LastToken.TokenType = TokenType.Function; + } + } + if (tokenSeparator.Value == "-") { + if (TokenIsNegator(_context)) { + _context.AddToken(new Token("-", TokenType.Negator)); + return; + } + } + _context.AddToken(tokenSeparator); + _context.NewToken(); + return; + } + _context.AppendToCurrentToken(c); + } + + private bool CharIsTokenSeparator(char c, out Token token) { + var result = _tokenProvider.Tokens.ContainsKey(c.ToString()); + token = result ? token = _tokenProvider.Tokens[c.ToString()] : null; + return result; + } + + private static bool TokenIsNegator(TokenizerContext context) { + return TokenIsNegator(context.LastToken); + } + + private static bool TokenIsNegator(Token t) { + return t == null + || t.TokenType == TokenType.Operator + || t.TokenType == TokenType.OpeningParenthesis + || t.TokenType == TokenType.Comma + || t.TokenType == TokenType.SemiColon + || t.TokenType == TokenType.OpeningEnumerable; + } + + private Token CreateToken(TokenizerContext context, string worksheet) { + if (context.CurrentToken == "-") { + if (context.LastToken == null && context.LastToken.TokenType == TokenType.Operator) { + return new Token("-", TokenType.Negator); + } + } + return _tokenFactory.Create(context.Result, context.CurrentToken, worksheet); + } + + int ITokenIndexProvider.Index { + get { return _tokenIndex; } + } + + void ITokenIndexProvider.MoveIndexPointerForward() { + _tokenIndex++; + } + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/BracketHandler.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/BracketHandler.cs index 18aceb1..ea4236a 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/BracketHandler.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/BracketHandler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2015-12-28 @@ -33,30 +33,28 @@ using System.Linq; using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers -{ - public class BracketHandler : SeparatorHandler - { - public override bool Handle(char c, Token tokenSeparator, TokenizerContext context, ITokenIndexProvider tokenIndexProvider) - { - if (tokenSeparator.TokenType == TokenType.OpeningBracket) - { - context.AppendToCurrentToken(c); - context.BracketCount++; - return true; - } - if (tokenSeparator.TokenType == TokenType.ClosingBracket) - { - context.AppendToCurrentToken(c); - context.BracketCount--; - return true; - } - if (context.BracketCount > 0) - { - context.AppendToCurrentToken(c); - return true; - } - return false; - } +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers { + public class BracketHandler : SeparatorHandler { + public override bool Handle( + char c, + Token tokenSeparator, + TokenizerContext context, + ITokenIndexProvider tokenIndexProvider) { + if (tokenSeparator.TokenType == TokenType.OpeningBracket) { + context.AppendToCurrentToken(c); + context.BracketCount++; + return true; + } + if (tokenSeparator.TokenType == TokenType.ClosingBracket) { + context.AppendToCurrentToken(c); + context.BracketCount--; + return true; + } + if (context.BracketCount > 0) { + context.AppendToCurrentToken(c); + return true; + } + return false; } + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/MultipleCharSeparatorHandler.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/MultipleCharSeparatorHandler.cs index 82ee081..dc02369 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/MultipleCharSeparatorHandler.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/MultipleCharSeparatorHandler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2015-12-28 @@ -34,41 +34,39 @@ using System.Linq; using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers -{ - public class MultipleCharSeparatorHandler : SeparatorHandler - { - ITokenSeparatorProvider _tokenSeparatorProvider; +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers { + public class MultipleCharSeparatorHandler : SeparatorHandler { + ITokenSeparatorProvider _tokenSeparatorProvider; - public MultipleCharSeparatorHandler() - : this(new TokenSeparatorProvider()) - { + public MultipleCharSeparatorHandler() + : this(new TokenSeparatorProvider()) {} - } - public MultipleCharSeparatorHandler(ITokenSeparatorProvider tokenSeparatorProvider) - { - _tokenSeparatorProvider = tokenSeparatorProvider; - } - public override bool Handle(char c, Token tokenSeparator, TokenizerContext context, ITokenIndexProvider tokenIndexProvider) - { - // two operators in sequence could be "<=" or ">=" - if (IsPartOfMultipleCharSeparator(context, c)) - { - var sOp = context.LastToken.Value + c.ToString(CultureInfo.InvariantCulture); - var op = _tokenSeparatorProvider.Tokens[sOp]; - context.ReplaceLastToken(op); - context.NewToken(); - return true; - } - return false; - } - - private bool IsPartOfMultipleCharSeparator(TokenizerContext context, char c) - { - var lastToken = context.LastToken != null ? context.LastToken.Value : string.Empty; - return _tokenSeparatorProvider.IsOperator(lastToken) - && _tokenSeparatorProvider.IsPossibleLastPartOfMultipleCharOperator(c.ToString(CultureInfo.InvariantCulture)) - && !context.CurrentTokenHasValue; - } + public MultipleCharSeparatorHandler(ITokenSeparatorProvider tokenSeparatorProvider) { + _tokenSeparatorProvider = tokenSeparatorProvider; } + + public override bool Handle( + char c, + Token tokenSeparator, + TokenizerContext context, + ITokenIndexProvider tokenIndexProvider) { + // two operators in sequence could be "<=" or ">=" + if (IsPartOfMultipleCharSeparator(context, c)) { + var sOp = context.LastToken.Value + c.ToString(CultureInfo.InvariantCulture); + var op = _tokenSeparatorProvider.Tokens[sOp]; + context.ReplaceLastToken(op); + context.NewToken(); + return true; + } + return false; + } + + private bool IsPartOfMultipleCharSeparator(TokenizerContext context, char c) { + var lastToken = context.LastToken != null ? context.LastToken.Value : string.Empty; + return _tokenSeparatorProvider.IsOperator(lastToken) + && _tokenSeparatorProvider.IsPossibleLastPartOfMultipleCharOperator( + c.ToString(CultureInfo.InvariantCulture)) + && !context.CurrentTokenHasValue; + } + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SeparatorHandler.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SeparatorHandler.cs index b275b2b..702a12d 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SeparatorHandler.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SeparatorHandler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2015-12-28 @@ -33,16 +33,21 @@ using System.Linq; using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers -{ - public abstract class SeparatorHandler - { - protected bool IsDoubleQuote(Token tokenSeparator, int formulaCharIndex, TokenizerContext context) - { - return tokenSeparator.TokenType == TokenType.String && formulaCharIndex + 1 < context.FormulaChars.Length && context.FormulaChars[formulaCharIndex + 1] == '\"'; - } - - public abstract bool Handle(char c, Token tokenSeparator, TokenizerContext context, ITokenIndexProvider tokenIndexProvider); - +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers { + public abstract class SeparatorHandler { + protected bool IsDoubleQuote( + Token tokenSeparator, + int formulaCharIndex, + TokenizerContext context) { + return tokenSeparator.TokenType == TokenType.String + && formulaCharIndex + 1 < context.FormulaChars.Length + && context.FormulaChars[formulaCharIndex + 1] == '\"'; } + + public abstract bool Handle( + char c, + Token tokenSeparator, + TokenizerContext context, + ITokenIndexProvider tokenIndexProvider); + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SheetnameHandler.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SheetnameHandler.cs index 2147f8e..f435fb3 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SheetnameHandler.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/SheetnameHandler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2015-12-28 @@ -33,41 +33,38 @@ using System.Linq; using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers -{ - public class SheetnameHandler : SeparatorHandler - { - public override bool Handle(char c, Token tokenSeparator, TokenizerContext context, ITokenIndexProvider tokenIndexProvider) - { - if (context.IsInSheetName) - { - if (IsDoubleQuote(tokenSeparator, tokenIndexProvider.Index, context)) - { - tokenIndexProvider.MoveIndexPointerForward(); - context.AppendToCurrentToken(c); - return true; - } - if (tokenSeparator.TokenType != TokenType.WorksheetName) - { - context.AppendToCurrentToken(c); - return true; - } - } - - if (tokenSeparator.TokenType == TokenType.WorksheetName) - { - if (context.LastToken != null && context.LastToken.TokenType == TokenType.WorksheetName) - { - context.AddToken(!context.CurrentTokenHasValue - ? new Token(string.Empty, TokenType.WorksheetNameContent) - : new Token(context.CurrentToken, TokenType.WorksheetNameContent)); - } - context.AddToken(new Token("'", TokenType.WorksheetName)); - context.ToggleIsInSheetName(); - context.NewToken(); - return true; - } - return false; +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers { + public class SheetnameHandler : SeparatorHandler { + public override bool Handle( + char c, + Token tokenSeparator, + TokenizerContext context, + ITokenIndexProvider tokenIndexProvider) { + if (context.IsInSheetName) { + if (IsDoubleQuote(tokenSeparator, tokenIndexProvider.Index, context)) { + tokenIndexProvider.MoveIndexPointerForward(); + context.AppendToCurrentToken(c); + return true; } + if (tokenSeparator.TokenType != TokenType.WorksheetName) { + context.AppendToCurrentToken(c); + return true; + } + } + + if (tokenSeparator.TokenType == TokenType.WorksheetName) { + if (context.LastToken != null && context.LastToken.TokenType == TokenType.WorksheetName) { + context.AddToken( + !context.CurrentTokenHasValue + ? new Token(string.Empty, TokenType.WorksheetNameContent) + : new Token(context.CurrentToken, TokenType.WorksheetNameContent)); + } + context.AddToken(new Token("'", TokenType.WorksheetName)); + context.ToggleIsInSheetName(); + context.NewToken(); + return true; + } + return false; } + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/StringHandler.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/StringHandler.cs index ec4a24b..2ef629c 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/StringHandler.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/StringHandler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2015-12-28 @@ -33,47 +33,44 @@ using System.Linq; using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers -{ - public class StringHandler : SeparatorHandler - { - public override bool Handle(char c, Token tokenSeparator, TokenizerContext context, ITokenIndexProvider tokenIndexProvider) - { - if(context.IsInString) - { - if (IsDoubleQuote(tokenSeparator, tokenIndexProvider.Index, context)) - { - tokenIndexProvider.MoveIndexPointerForward(); - context.AppendToCurrentToken(c); - return true; - } - if (tokenSeparator.TokenType != TokenType.String) - { - context.AppendToCurrentToken(c); - return true; - } - } - - if (tokenSeparator.TokenType == TokenType.String) - { - if (context.LastToken != null && context.LastToken.TokenType == TokenType.OpeningEnumerable) - { - context.AppendToCurrentToken(c); - context.ToggleIsInString(); - return true; - } - if (context.LastToken != null && context.LastToken.TokenType == TokenType.String) - { - context.AddToken(!context.CurrentTokenHasValue - ? new Token(string.Empty, TokenType.StringContent) - : new Token(context.CurrentToken, TokenType.StringContent)); - } - context.AddToken(new Token("\"", TokenType.String)); - context.ToggleIsInString(); - context.NewToken(); - return true; - } - return false; +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers { + public class StringHandler : SeparatorHandler { + public override bool Handle( + char c, + Token tokenSeparator, + TokenizerContext context, + ITokenIndexProvider tokenIndexProvider) { + if (context.IsInString) { + if (IsDoubleQuote(tokenSeparator, tokenIndexProvider.Index, context)) { + tokenIndexProvider.MoveIndexPointerForward(); + context.AppendToCurrentToken(c); + return true; } + if (tokenSeparator.TokenType != TokenType.String) { + context.AppendToCurrentToken(c); + return true; + } + } + + if (tokenSeparator.TokenType == TokenType.String) { + if (context.LastToken != null + && context.LastToken.TokenType == TokenType.OpeningEnumerable) { + context.AppendToCurrentToken(c); + context.ToggleIsInString(); + return true; + } + if (context.LastToken != null && context.LastToken.TokenType == TokenType.String) { + context.AddToken( + !context.CurrentTokenHasValue + ? new Token(string.Empty, TokenType.StringContent) + : new Token(context.CurrentToken, TokenType.StringContent)); + } + context.AddToken(new Token("\"", TokenType.String)); + context.ToggleIsInString(); + context.NewToken(); + return true; + } + return false; } + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/TokenSeparatorHandler.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/TokenSeparatorHandler.cs index 4f78c94..8afb997 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/TokenSeparatorHandler.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorHandlers/TokenSeparatorHandler.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2015-12-28 @@ -33,40 +33,38 @@ using System.Linq; using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers -{ - /// <summary> - /// This class provides access to <see cref="SeparatorHandler"/>s - classes that exposes functionatlity - /// needed when parsing strings to tokens. - /// </summary> - public static class TokenSeparatorHandler - { - private static SeparatorHandler[] _handlers = new SeparatorHandler[] - { - new StringHandler(), - new BracketHandler(), - new SheetnameHandler(), - new MultipleCharSeparatorHandler() - }; +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis.TokenSeparatorHandlers { + /// <summary> + /// This class provides access to <see cref="SeparatorHandler"/>s - classes that exposes functionatlity + /// needed when parsing strings to tokens. + /// </summary> + public static class TokenSeparatorHandler { + private static SeparatorHandler[] _handlers = new SeparatorHandler[] { + new StringHandler(), + new BracketHandler(), + new SheetnameHandler(), + new MultipleCharSeparatorHandler(), + }; - /// <summary> - /// Handles a tokenseparator. - /// </summary> - /// <param name="c"></param> - /// <param name="tokenSeparator"></param> - /// <param name="context"></param> - /// <param name="tokenIndexProvider"></param> - /// <returns>Returns true if the tokenseparator was handled.</returns> - public static bool Handle(char c, Token tokenSeparator, TokenizerContext context, ITokenIndexProvider tokenIndexProvider) - { - foreach(var handler in _handlers) - { - if(handler.Handle(c, tokenSeparator, context, tokenIndexProvider)) - { - return true; - } - } - return false; + /// <summary> + /// Handles a tokenseparator. + /// </summary> + /// <param name="c"></param> + /// <param name="tokenSeparator"></param> + /// <param name="context"></param> + /// <param name="tokenIndexProvider"></param> + /// <returns>Returns true if the tokenseparator was handled.</returns> + public static bool Handle( + char c, + Token tokenSeparator, + TokenizerContext context, + ITokenIndexProvider tokenIndexProvider) { + foreach (var handler in _handlers) { + if (handler.Handle(c, tokenSeparator, context, tokenIndexProvider)) { + return true; } + } + return false; } + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs index d11ccd6..cddd2f3 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenSeparatorProvider.cs
@@ -13,82 +13,69 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class TokenSeparatorProvider : ITokenSeparatorProvider - { - private static readonly Dictionary<string, Token> _tokens; +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - static TokenSeparatorProvider() - { - _tokens = new Dictionary<string, Token>(); - _tokens.Add("+", new Token("+", TokenType.Operator)); - _tokens.Add("-", new Token("-", TokenType.Operator)); - _tokens.Add("*", new Token("*", TokenType.Operator)); - _tokens.Add("/", new Token("/", TokenType.Operator)); - _tokens.Add("^", new Token("^", TokenType.Operator)); - _tokens.Add("&", new Token("&", TokenType.Operator)); - _tokens.Add(">", new Token(">", TokenType.Operator)); - _tokens.Add("<", new Token("<", TokenType.Operator)); - _tokens.Add("=", new Token("=", TokenType.Operator)); - _tokens.Add("<=", new Token("<=", TokenType.Operator)); - _tokens.Add(">=", new Token(">=", TokenType.Operator)); - _tokens.Add("<>", new Token("<>", TokenType.Operator)); - _tokens.Add("(", new Token("(", TokenType.OpeningParenthesis)); - _tokens.Add(")", new Token(")", TokenType.ClosingParenthesis)); - _tokens.Add("{", new Token("{", TokenType.OpeningEnumerable)); - _tokens.Add("}", new Token("}", TokenType.ClosingEnumerable)); - _tokens.Add("'", new Token("'", TokenType.String)); - _tokens.Add("\"", new Token("\"", TokenType.String)); - _tokens.Add(",", new Token(",", TokenType.Comma)); - _tokens.Add(";", new Token(";", TokenType.SemiColon)); - _tokens.Add("[", new Token("[", TokenType.OpeningBracket)); - _tokens.Add("]", new Token("]", TokenType.ClosingBracket)); - _tokens.Add("%", new Token("%", TokenType.Percent)); - } +public class TokenSeparatorProvider : ITokenSeparatorProvider { + private static readonly Dictionary<string, Token> _tokens; - IDictionary<string, Token> ITokenSeparatorProvider.Tokens - { - get { return _tokens; } - } + static TokenSeparatorProvider() { + _tokens = new(); + _tokens.Add("+", new("+", TokenType.Operator)); + _tokens.Add("-", new("-", TokenType.Operator)); + _tokens.Add("*", new("*", TokenType.Operator)); + _tokens.Add("/", new("/", TokenType.Operator)); + _tokens.Add("^", new("^", TokenType.Operator)); + _tokens.Add("&", new("&", TokenType.Operator)); + _tokens.Add(">", new(">", TokenType.Operator)); + _tokens.Add("<", new("<", TokenType.Operator)); + _tokens.Add("=", new("=", TokenType.Operator)); + _tokens.Add("<=", new("<=", TokenType.Operator)); + _tokens.Add(">=", new(">=", TokenType.Operator)); + _tokens.Add("<>", new("<>", TokenType.Operator)); + _tokens.Add("(", new("(", TokenType.OpeningParenthesis)); + _tokens.Add(")", new(")", TokenType.ClosingParenthesis)); + _tokens.Add("{", new("{", TokenType.OpeningEnumerable)); + _tokens.Add("}", new("}", TokenType.ClosingEnumerable)); + _tokens.Add("'", new("'", TokenType.String)); + _tokens.Add("\"", new("\"", TokenType.String)); + _tokens.Add(",", new(",", TokenType.Comma)); + _tokens.Add(";", new(";", TokenType.SemiColon)); + _tokens.Add("[", new("[", TokenType.OpeningBracket)); + _tokens.Add("]", new("]", TokenType.ClosingBracket)); + _tokens.Add("%", new("%", TokenType.Percent)); + } - public bool IsOperator(string item) - { - Token token; - if (_tokens.TryGetValue(item, out token)) - { - if (token.TokenType == TokenType.Operator) - { - return true; - } - } - return false; - } + IDictionary<string, Token> ITokenSeparatorProvider.Tokens => _tokens; - public bool IsPossibleLastPartOfMultipleCharOperator(string part) - { - return part == "=" || part == ">"; - } + public bool IsOperator(string item) { + Token token; + if (_tokens.TryGetValue(item, out token)) { + if (token.TokenType == TokenType.Operator) { + return true; + } } + return false; + } + + public bool IsPossibleLastPartOfMultipleCharOperator(string part) { + return part == "=" || part == ">"; + } }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenType.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenType.cs index 5bcda9a..a698470 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenType.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenType.cs
@@ -13,54 +13,48 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public enum TokenType - { - Operator, - Negator, - OpeningParenthesis, - ClosingParenthesis, - OpeningEnumerable, - ClosingEnumerable, - OpeningBracket, - ClosingBracket, - Enumerable, - Comma, - SemiColon, - String, - StringContent, - Integer, - Boolean, - Decimal, - Percent, - Function, - ExcelAddress, - NameValue, - InvalidReference, - NumericError, - ValueDataTypeError, - Null, - Unrecognized - } +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; + +public enum TokenType { + Operator, + Negator, + OpeningParenthesis, + ClosingParenthesis, + OpeningEnumerable, + ClosingEnumerable, + OpeningBracket, + ClosingBracket, + Enumerable, + Comma, + SemiColon, + String, + StringContent, + Integer, + Boolean, + Decimal, + Percent, + Function, + ExcelAddress, + NameValue, + InvalidReference, + NumericError, + ValueDataTypeError, + Null, + Unrecognized, }
diff --git a/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs b/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs index 6a28142..e87ac14 100644 --- a/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs +++ b/EPPlus/FormulaParsing/LexicalAnalysis/TokenizerContext.cs
@@ -13,120 +13,92 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; + using System.Collections.Generic; using System.Linq; using System.Text; -namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis -{ - public class TokenizerContext - { - public TokenizerContext(string formula) - { - if (!string.IsNullOrEmpty(formula)) - { - _chars = formula.ToArray(); - } - _result = new List<Token>(); - _currentToken = new StringBuilder(); - } +namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis; - private char[] _chars; - private List<Token> _result; - private StringBuilder _currentToken; - - public char[] FormulaChars - { - get { return _chars; } - } - - public IList<Token> Result - { - get { return _result; } - } - - public bool IsInString - { - get; - private set; - } - - public void ToggleIsInString() - { - IsInString = !IsInString; - } - - internal int BracketCount - { - get; - set; - } - - public string CurrentToken - { - get { return _currentToken.ToString(); } - } - - public bool CurrentTokenHasValue - { - get { return !string.IsNullOrEmpty(this.IsInString ? CurrentToken : CurrentToken.Trim()); } - } - - public void NewToken() - { - _currentToken = new StringBuilder(); - } - - public void AddToken(Token token) - { - _result.Add(token); - } - - public void AppendToCurrentToken(char c) - { - _currentToken.Append(c.ToString()); - } - - public void AppendToLastToken(string stringToAppend) - { - _result.Last().Append(stringToAppend); - } - - public void SetLastTokenType(TokenType type) - { - _result.Last().TokenType = type; - } - - public void ReplaceLastToken(Token newToken) - { - var count = _result.Count; - if (count > 0) - { - _result.RemoveAt(count - 1); - } - _result.Add(newToken); - } - - public Token LastToken - { - get { return _result.Count > 0 ? _result.Last() : null; } - } - +public class TokenizerContext { + public TokenizerContext(string formula) { + if (!string.IsNullOrEmpty(formula)) { + _chars = formula.ToArray(); } + _result = new(); + _currentToken = new(); + } + + private char[] _chars; + private List<Token> _result; + private StringBuilder _currentToken; + + public char[] FormulaChars => _chars; + + public IList<Token> Result { + get { return _result; } + } + + public bool IsInString { get; private set; } + + public void ToggleIsInString() { + IsInString = !IsInString; + } + + internal int BracketCount { get; set; } + + public string CurrentToken { + get { return _currentToken.ToString(); } + } + + public bool CurrentTokenHasValue { + get { return !string.IsNullOrEmpty(IsInString ? CurrentToken : CurrentToken.Trim()); } + } + + public void NewToken() { + _currentToken = new(); + } + + public void AddToken(Token token) { + _result.Add(token); + } + + public void AppendToCurrentToken(char c) { + _currentToken.Append(c.ToString()); + } + + public void AppendToLastToken(string stringToAppend) { + _result.Last().Append(stringToAppend); + } + + public void SetLastTokenType(TokenType type) { + _result.Last().TokenType = type; + } + + public void ReplaceLastToken(Token newToken) { + var count = _result.Count; + if (count > 0) { + _result.RemoveAt(count - 1); + } + _result.Add(newToken); + } + + public Token LastToken { + get { return _result.Count > 0 ? _result.Last() : null; } + } }
diff --git a/EPPlus/FormulaParsing/Logging/IFormulaParserLogger.cs b/EPPlus/FormulaParsing/Logging/IFormulaParserLogger.cs index f5a91b8..dc38d9d 100644 --- a/EPPlus/FormulaParsing/Logging/IFormulaParserLogger.cs +++ b/EPPlus/FormulaParsing/Logging/IFormulaParserLogger.cs
@@ -1,44 +1,46 @@ using System; -namespace OfficeOpenXml.FormulaParsing.Logging -{ - /// <summary> - /// Used for logging during FormulaParsing - /// </summary> - public interface IFormulaParserLogger : IDisposable - { - /// <summary> - /// Called each time an exception occurs during formula parsing. - /// </summary> - /// <param name="context"></param> - /// <param name="ex"></param> - void Log(ParsingContext context, Exception ex); - /// <summary> - /// Called each time information should be logged during formula parsing. - /// </summary> - /// <param name="context"></param> - /// <param name="message"></param> - void Log(ParsingContext context, string message); - /// <summary> - /// Called to log a message outside the parsing context. - /// </summary> - /// <param name="message"></param> - void Log(string message); - /// <summary> - /// Called each time a cell within the calc chain is accessed during formula parsing. - /// </summary> - void LogCellCounted(); +namespace OfficeOpenXml.FormulaParsing.Logging; - /// <summary> - /// Called each time a function is called during formula parsing. - /// </summary> - /// <param name="func"></param> - void LogFunction(string func); - /// <summary> - /// Some functions measure performance, if so this function will be called. - /// </summary> - /// <param name="func"></param> - /// <param name="milliseconds"></param> - void LogFunction(string func, long milliseconds); - } +/// <summary> +/// Used for logging during FormulaParsing +/// </summary> +public interface IFormulaParserLogger : IDisposable { + /// <summary> + /// Called each time an exception occurs during formula parsing. + /// </summary> + /// <param name="context"></param> + /// <param name="ex"></param> + void Log(ParsingContext context, Exception ex); + + /// <summary> + /// Called each time information should be logged during formula parsing. + /// </summary> + /// <param name="context"></param> + /// <param name="message"></param> + void Log(ParsingContext context, string message); + + /// <summary> + /// Called to log a message outside the parsing context. + /// </summary> + /// <param name="message"></param> + void Log(string message); + + /// <summary> + /// Called each time a cell within the calc chain is accessed during formula parsing. + /// </summary> + void LogCellCounted(); + + /// <summary> + /// Called each time a function is called during formula parsing. + /// </summary> + /// <param name="func"></param> + void LogFunction(string func); + + /// <summary> + /// Some functions measure performance, if so this function will be called. + /// </summary> + /// <param name="func"></param> + /// <param name="milliseconds"></param> + void LogFunction(string func, long milliseconds); }
diff --git a/EPPlus/FormulaParsing/NameValueProvider.cs b/EPPlus/FormulaParsing/NameValueProvider.cs index 5210a31..f7b0a8d 100644 --- a/EPPlus/FormulaParsing/NameValueProvider.cs +++ b/EPPlus/FormulaParsing/NameValueProvider.cs
@@ -1,35 +1,17 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing -{ - public class NameValueProvider : INameValueProvider - { - private NameValueProvider() - { +public class NameValueProvider : INameValueProvider { + private NameValueProvider() {} - } + public static INameValueProvider Empty => new NameValueProvider(); - public static INameValueProvider Empty - { - get { return new NameValueProvider(); } - } + public bool IsNamedValue(string key, string worksheet) { + return false; + } - public bool IsNamedValue(string key, string worksheet) - { - return false; - } + public object GetNamedValue(string key) { + return null; + } - public object GetNamedValue(string key) - { - return null; - } - - public void Reload() - { - - } - } + public void Reload() {} }
diff --git a/EPPlus/FormulaParsing/ParsedValue.cs b/EPPlus/FormulaParsing/ParsedValue.cs index 51d7d08..43112b7 100644 --- a/EPPlus/FormulaParsing/ParsedValue.cs +++ b/EPPlus/FormulaParsing/ParsedValue.cs
@@ -1,35 +1,15 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing; -namespace OfficeOpenXml.FormulaParsing -{ - public class ParsedValue - { - public ParsedValue(object val, int rowIndex, int colIndex) - { - Value = val; - RowIndex = rowIndex; - ColIndex = colIndex; - } +public class ParsedValue { + public ParsedValue(object val, int rowIndex, int colIndex) { + Value = val; + RowIndex = rowIndex; + ColIndex = colIndex; + } - public object Value - { - get; - private set; - } + public object Value { get; private set; } - public int RowIndex - { - get; - private set; - } + public int RowIndex { get; private set; } - public int ColIndex - { - get; - private set; - } - } + public int ColIndex { get; private set; } }
diff --git a/EPPlus/FormulaParsing/ParsingConfiguration.cs b/EPPlus/FormulaParsing/ParsingConfiguration.cs index dddf0b6..71440b3 100644 --- a/EPPlus/FormulaParsing/ParsingConfiguration.cs +++ b/EPPlus/FormulaParsing/ParsingConfiguration.cs
@@ -1,76 +1,62 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; +using OfficeOpenXml.FormulaParsing.Excel.Functions; using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.Excel.Functions; +using OfficeOpenXml.FormulaParsing.LexicalAnalysis; using OfficeOpenXml.FormulaParsing.Logging; using OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing -{ - public class ParsingConfiguration - { - public virtual ILexer Lexer { get; private set; } +namespace OfficeOpenXml.FormulaParsing; - public IFormulaParserLogger Logger { get; private set; } +public class ParsingConfiguration { + public virtual ILexer Lexer { get; private set; } - public IExpressionGraphBuilder GraphBuilder { get; private set; } + public IFormulaParserLogger Logger { get; private set; } - public IExpressionCompiler ExpressionCompiler{ get; private set; } + public IExpressionGraphBuilder GraphBuilder { get; private set; } - public FunctionRepository FunctionRepository{ get; private set; } + public IExpressionCompiler ExpressionCompiler { get; private set; } - private ParsingConfiguration() - { - FunctionRepository = FunctionRepository.Create(); - } + public FunctionRepository FunctionRepository { get; private set; } - internal static ParsingConfiguration Create() - { - return new ParsingConfiguration(); - } + private ParsingConfiguration() { + FunctionRepository = FunctionRepository.Create(); + } - public ParsingConfiguration SetLexer(ILexer lexer) - { - Lexer = lexer; - return this; - } + internal static ParsingConfiguration Create() { + return new(); + } - public ParsingConfiguration SetGraphBuilder(IExpressionGraphBuilder graphBuilder) - { - GraphBuilder = graphBuilder; - return this; - } + public ParsingConfiguration SetLexer(ILexer lexer) { + Lexer = lexer; + return this; + } - public ParsingConfiguration SetExpresionCompiler(IExpressionCompiler expressionCompiler) - { - ExpressionCompiler = expressionCompiler; - return this; - } + public ParsingConfiguration SetGraphBuilder(IExpressionGraphBuilder graphBuilder) { + GraphBuilder = graphBuilder; + return this; + } - /// <summary> - /// Attaches a logger, errors and log entries will be written to the logger during the parsing process. - /// </summary> - /// <param name="logger"></param> - /// <returns></returns> - public ParsingConfiguration AttachLogger(IFormulaParserLogger logger) - { - Require.That(logger).Named("logger").IsNotNull(); - Logger = logger; - return this; - } + public ParsingConfiguration SetExpresionCompiler(IExpressionCompiler expressionCompiler) { + ExpressionCompiler = expressionCompiler; + return this; + } - /// <summary> - /// if a logger is attached it will be removed. - /// </summary> - /// <returns></returns> - public ParsingConfiguration DetachLogger() - { - Logger = null; - return this; - } - } + /// <summary> + /// Attaches a logger, errors and log entries will be written to the logger during the parsing process. + /// </summary> + /// <param name="logger"></param> + /// <returns></returns> + public ParsingConfiguration AttachLogger(IFormulaParserLogger logger) { + Require.That(logger).Named("logger").IsNotNull(); + Logger = logger; + return this; + } + + /// <summary> + /// if a logger is attached it will be removed. + /// </summary> + /// <returns></returns> + public ParsingConfiguration DetachLogger() { + Logger = null; + return this; + } }
diff --git a/EPPlus/FormulaParsing/ParsingContext.cs b/EPPlus/FormulaParsing/ParsingContext.cs index 641d1d6..8eee889 100644 --- a/EPPlus/FormulaParsing/ParsingContext.cs +++ b/EPPlus/FormulaParsing/ParsingContext.cs
@@ -1,76 +1,60 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using OfficeOpenXml.FormulaParsing.LexicalAnalysis; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using OfficeOpenXml.FormulaParsing.ExcelUtilities; -using OfficeOpenXml.FormulaParsing; +using OfficeOpenXml.FormulaParsing.ExcelUtilities; using OfficeOpenXml.FormulaParsing.Logging; -namespace OfficeOpenXml.FormulaParsing -{ - /// <summary> - /// Parsing context - /// </summary> - public class ParsingContext : IParsingLifetimeEventHandler - { - private ParsingContext() { } +namespace OfficeOpenXml.FormulaParsing; - /// <summary> - /// The <see cref="FormulaParser"/> of the current context. - /// </summary> - public FormulaParser Parser { get; set; } +/// <summary> +/// Parsing context +/// </summary> +public class ParsingContext : IParsingLifetimeEventHandler { + private ParsingContext() {} - /// <summary> - /// The <see cref="ExcelDataProvider"/> is an abstraction on top of - /// Excel, in this case EPPlus. - /// </summary> - public ExcelDataProvider ExcelDataProvider { get; set; } + /// <summary> + /// The <see cref="FormulaParser"/> of the current context. + /// </summary> + public FormulaParser Parser { get; set; } - /// <summary> - /// Utility for handling addresses - /// </summary> - public RangeAddressFactory RangeAddressFactory { get; set; } + /// <summary> + /// The <see cref="ExcelDataProvider"/> is an abstraction on top of + /// Excel, in this case EPPlus. + /// </summary> + public ExcelDataProvider ExcelDataProvider { get; set; } - /// <summary> - /// <see cref="INameValueProvider"/> of the current context - /// </summary> - public INameValueProvider NameValueProvider { get; set; } + /// <summary> + /// Utility for handling addresses + /// </summary> + public RangeAddressFactory RangeAddressFactory { get; set; } - /// <summary> - /// Configuration - /// </summary> - public ParsingConfiguration Configuration { get; set; } + /// <summary> + /// <see cref="INameValueProvider"/> of the current context + /// </summary> + public INameValueProvider NameValueProvider { get; set; } - /// <summary> - /// Scopes, a scope represents the parsing of a cell or a value. - /// </summary> - public ParsingScopes Scopes { get; private set; } + /// <summary> + /// Configuration + /// </summary> + public ParsingConfiguration Configuration { get; set; } - /// <summary> - /// Returns true if a <see cref="IFormulaParserLogger"/> is attached to the parser. - /// </summary> - public bool Debug - { - get { return Configuration.Logger != null; } - } + /// <summary> + /// Scopes, a scope represents the parsing of a cell or a value. + /// </summary> + public ParsingScopes Scopes { get; private set; } - /// <summary> - /// Factory method. - /// </summary> - /// <returns></returns> - public static ParsingContext Create() - { - var context = new ParsingContext(); - context.Configuration = ParsingConfiguration.Create(); - context.Scopes = new ParsingScopes(context); - return context; - } + /// <summary> + /// Returns true if a <see cref="IFormulaParserLogger"/> is attached to the parser. + /// </summary> + public bool Debug => Configuration.Logger != null; - void IParsingLifetimeEventHandler.ParsingCompleted() - { - - } - } + /// <summary> + /// Factory method. + /// </summary> + /// <returns></returns> + public static ParsingContext Create() { + var context = new ParsingContext(); + context.Configuration = ParsingConfiguration.Create(); + context.Scopes = new(context); + return context; + } + + void IParsingLifetimeEventHandler.ParsingCompleted() {} }
diff --git a/EPPlus/FormulaParsing/ParsingScope.cs b/EPPlus/FormulaParsing/ParsingScope.cs index 321e693..1e861c5 100644 --- a/EPPlus/FormulaParsing/ParsingScope.cs +++ b/EPPlus/FormulaParsing/ParsingScope.cs
@@ -1,54 +1,45 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; using OfficeOpenXml.FormulaParsing.ExcelUtilities; -namespace OfficeOpenXml.FormulaParsing -{ - /// <summary> - /// Represents a parsing of a single input or workbook addrses. - /// </summary> - public class ParsingScope : IDisposable - { - private readonly ParsingScopes _parsingScopes; +namespace OfficeOpenXml.FormulaParsing; - public ParsingScope(ParsingScopes parsingScopes, RangeAddress address) - : this(parsingScopes, null, address) - { - } +/// <summary> +/// Represents a parsing of a single input or workbook addrses. +/// </summary> +public class ParsingScope : IDisposable { + private readonly ParsingScopes _parsingScopes; - public ParsingScope(ParsingScopes parsingScopes, ParsingScope parent, RangeAddress address) - { - _parsingScopes = parsingScopes; - Parent = parent; - Address = address; - ScopeId = Guid.NewGuid(); - } + public ParsingScope(ParsingScopes parsingScopes, RangeAddress address) + : this(parsingScopes, null, address) {} - /// <summary> - /// Id of the scope. - /// </summary> - public Guid ScopeId { get; private set; } + public ParsingScope(ParsingScopes parsingScopes, ParsingScope parent, RangeAddress address) { + _parsingScopes = parsingScopes; + Parent = parent; + Address = address; + ScopeId = Guid.NewGuid(); + } - /// <summary> - /// The calling scope. - /// </summary> - public ParsingScope Parent { get; private set; } + /// <summary> + /// Id of the scope. + /// </summary> + public Guid ScopeId { get; private set; } - /// <summary> - /// The address of the cell currently beeing parsed. - /// </summary> - public RangeAddress Address { get; private set; } + /// <summary> + /// The calling scope. + /// </summary> + public ParsingScope Parent { get; private set; } - /// <summary> - /// True if the current scope is a Subtotal function beeing executed. - /// </summary> - public bool IsSubtotal { get; set; } + /// <summary> + /// The address of the cell currently beeing parsed. + /// </summary> + public RangeAddress Address { get; private set; } - public void Dispose() - { - _parsingScopes.KillScope(this); - } - } + /// <summary> + /// True if the current scope is a Subtotal function beeing executed. + /// </summary> + public bool IsSubtotal { get; set; } + + public void Dispose() { + _parsingScopes.KillScope(this); + } }
diff --git a/EPPlus/FormulaParsing/ParsingScopes.cs b/EPPlus/FormulaParsing/ParsingScopes.cs index 978df30..51d7bad 100644 --- a/EPPlus/FormulaParsing/ParsingScopes.cs +++ b/EPPlus/FormulaParsing/ParsingScopes.cs
@@ -1,65 +1,51 @@ -using System; using System.Collections.Generic; using System.Linq; -using System.Text; using OfficeOpenXml.FormulaParsing.ExcelUtilities; -namespace OfficeOpenXml.FormulaParsing -{ - /// <summary> - /// This class implements a stack on which instances of <see cref="ParsingScope"/> - /// are put. Each ParsingScope represents the parsing of an address in the workbook. - /// </summary> - public class ParsingScopes - { - private readonly IParsingLifetimeEventHandler _lifetimeEventHandler; +namespace OfficeOpenXml.FormulaParsing; - public ParsingScopes(IParsingLifetimeEventHandler lifetimeEventHandler) - { - _lifetimeEventHandler = lifetimeEventHandler; - } - private Stack<ParsingScope> _scopes = new Stack<ParsingScope>(); +/// <summary> +/// This class implements a stack on which instances of <see cref="ParsingScope"/> +/// are put. Each ParsingScope represents the parsing of an address in the workbook. +/// </summary> +public class ParsingScopes { + private readonly IParsingLifetimeEventHandler _lifetimeEventHandler; - /// <summary> - /// Creates a new <see cref="ParsingScope"/> and puts it on top of the stack. - /// </summary> - /// <param name="address"></param> - /// <returns></returns> - public virtual ParsingScope NewScope(RangeAddress address) - { - ParsingScope scope; - if (_scopes.Count() > 0) - { - scope = new ParsingScope(this, _scopes.Peek(), address); - } - else - { - scope = new ParsingScope(this, address); - } - _scopes.Push(scope); - return scope; - } + public ParsingScopes(IParsingLifetimeEventHandler lifetimeEventHandler) { + _lifetimeEventHandler = lifetimeEventHandler; + } + private Stack<ParsingScope> _scopes = new(); - /// <summary> - /// The current parsing scope. - /// </summary> - public virtual ParsingScope Current - { - get { return _scopes.Count() > 0 ? _scopes.Peek() : null; } - } - - /// <summary> - /// Removes the current scope, setting the calling scope to current. - /// </summary> - /// <param name="parsingScope"></param> - public virtual void KillScope(ParsingScope parsingScope) - { - _scopes.Pop(); - if (_scopes.Count() == 0) - { - _lifetimeEventHandler.ParsingCompleted(); - } - } + /// <summary> + /// Creates a new <see cref="ParsingScope"/> and puts it on top of the stack. + /// </summary> + /// <param name="address"></param> + /// <returns></returns> + public virtual ParsingScope NewScope(RangeAddress address) { + ParsingScope scope; + if (_scopes.Count() > 0) { + scope = new(this, _scopes.Peek(), address); + } else { + scope = new(this, address); } + _scopes.Push(scope); + return scope; + } + + /// <summary> + /// The current parsing scope. + /// </summary> + public virtual ParsingScope Current => _scopes.Count() > 0 ? _scopes.Peek() : null; + + /// <summary> + /// Removes the current scope, setting the calling scope to current. + /// </summary> + /// <param name="parsingScope"></param> + public virtual void KillScope(ParsingScope parsingScope) { + _scopes.Pop(); + if (_scopes.Count() == 0) { + _lifetimeEventHandler.ParsingCompleted(); + } + } }
diff --git a/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs b/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs index 9cf0893..a0a826f 100644 --- a/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs +++ b/EPPlus/FormulaParsing/Utilities/ArgumentInfo.cs
@@ -1,25 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Utilities -{ - public class ArgumentInfo<T> - { - public ArgumentInfo(T val) - { - Value = val; - } +public class ArgumentInfo<T> { + public ArgumentInfo(T val) { + Value = val; + } - public T Value { get; private set; } + public T Value { get; private set; } - public string Name { get; private set; } + public string Name { get; private set; } - public ArgumentInfo<T> Named(string argName) - { - Name = argName; - return this; - } - } + public ArgumentInfo<T> Named(string argName) { + Name = argName; + return this; + } }
diff --git a/EPPlus/FormulaParsing/Utilities/ExtensionMethods.cs b/EPPlus/FormulaParsing/Utilities/ExtensionMethods.cs index 045f793..786ec4f 100644 --- a/EPPlus/FormulaParsing/Utilities/ExtensionMethods.cs +++ b/EPPlus/FormulaParsing/Utilities/ExtensionMethods.cs
@@ -1,33 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; -namespace OfficeOpenXml.FormulaParsing.Utilities -{ - public static class ExtensionMethods - { - public static void IsNotNullOrEmpty(this ArgumentInfo<string> val) - { - if (string.IsNullOrEmpty(val.Value)) - { - throw new ArgumentException(val.Name + " cannot be null or empty"); - } - } +namespace OfficeOpenXml.FormulaParsing.Utilities; - public static void IsNotNull<T>(this ArgumentInfo<T> val) - where T : class - { - if (val.Value == null) - { - throw new ArgumentNullException(val.Name); - } - } - - public static bool IsNumeric(this object obj) - { - if (obj == null) return false; - return (obj.GetType().IsPrimitive || obj is double || obj is decimal || obj is System.DateTime || obj is TimeSpan); - } +public static class ExtensionMethods { + public static void IsNotNullOrEmpty(this ArgumentInfo<string> val) { + if (string.IsNullOrEmpty(val.Value)) { + throw new ArgumentException(val.Name + " cannot be null or empty"); } + } + + public static void IsNotNull<T>(this ArgumentInfo<T> val) + where T : class { + if (val.Value == null) { + throw new ArgumentNullException(val.Name); + } + } + + public static bool IsNumeric(this object obj) { + if (obj == null) { + return false; + } + return (obj.GetType().IsPrimitive + || obj is double + || obj is decimal + || obj is DateTime + || obj is TimeSpan); + } }
diff --git a/EPPlus/FormulaParsing/Utilities/IdProvider.cs b/EPPlus/FormulaParsing/Utilities/IdProvider.cs index 9dfc6ae..15e02b3 100644 --- a/EPPlus/FormulaParsing/Utilities/IdProvider.cs +++ b/EPPlus/FormulaParsing/Utilities/IdProvider.cs
@@ -1,12 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Utilities -{ - public abstract class IdProvider - { - public abstract object NewId(); - } +public abstract class IdProvider { + public abstract object NewId(); }
diff --git a/EPPlus/FormulaParsing/Utilities/IntegerIdProvider.cs b/EPPlus/FormulaParsing/Utilities/IntegerIdProvider.cs index 5b1b0b1..d1a39f4 100644 --- a/EPPlus/FormulaParsing/Utilities/IntegerIdProvider.cs +++ b/EPPlus/FormulaParsing/Utilities/IntegerIdProvider.cs
@@ -1,21 +1,14 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Utilities -{ - public class IntegerIdProvider : IdProvider - { - private int _lastId = int.MinValue; +namespace OfficeOpenXml.FormulaParsing.Utilities; - public override object NewId() - { - if (_lastId >= int.MaxValue) - { - throw new InvalidOperationException("IdProvider run out of id:s"); - } - return _lastId++; - } +public class IntegerIdProvider : IdProvider { + private int _lastId = int.MinValue; + + public override object NewId() { + if (_lastId >= int.MaxValue) { + throw new InvalidOperationException("IdProvider run out of id:s"); } + return _lastId++; + } }
diff --git a/EPPlus/FormulaParsing/Utilities/RegexConstants.cs b/EPPlus/FormulaParsing/Utilities/RegexConstants.cs index 6e009aa..deba058 100644 --- a/EPPlus/FormulaParsing/Utilities/RegexConstants.cs +++ b/EPPlus/FormulaParsing/Utilities/RegexConstants.cs
@@ -13,36 +13,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2013-03-01 (Prior file history on https://github.com/swmal/ExcelFormulaParser) *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.FormulaParsing.Utilities -{ - public static class RegexConstants - { - public const string SingleCellAddress = @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[A-Z]{1,3}[1-9]{1}[0-9]{0,7}$"; - //Changed JK 26/2-2013 - public const string ExcelAddress = @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[\$]{0,1}([A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})(\:({0,1}[A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})){0,1}$"; - //public const string ExcelAddress = @"^([\$]{0,1}([A-Z]{1,3}[\$]{0,1}[0-9]{1,7})(\:([\$]{0,1}[A-Z]{1,3}[\$]{0,1}[0-9]{1,7}){0,1})|([\$]{0,1}[A-Z]{1,3}\:[\$]{0,1}[A-Z]{1,3})|([\$]{0,1}[0-9]{1,7}\:[\$]{0,1}[0-9]{1,7}))$"; - public const string Boolean = @"^(true|false)$"; - public const string Decimal = @"^[0-9]+\.[0-9]+$"; - public const string Integer = @"^[0-9]+$"; - } +namespace OfficeOpenXml.FormulaParsing.Utilities; + +public static class RegexConstants { + public const string SingleCellAddress = + @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[A-Z]{1,3}[1-9]{1}[0-9]{0,7}$"; + + //Changed JK 26/2-2013 + public const string ExcelAddress = + @"^(('[^/\\?*\[\]]{1,31}'|[A-Za-z_]{1,31})!)?[\$]{0,1}([A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})(\:({0,1}[A-Z]|[A-Z]{1,3}[\$]{0,1}[1-9]{1}[0-9]{0,7})){0,1}$"; + + //public const string ExcelAddress = @"^([\$]{0,1}([A-Z]{1,3}[\$]{0,1}[0-9]{1,7})(\:([\$]{0,1}[A-Z]{1,3}[\$]{0,1}[0-9]{1,7}){0,1})|([\$]{0,1}[A-Z]{1,3}\:[\$]{0,1}[A-Z]{1,3})|([\$]{0,1}[0-9]{1,7}\:[\$]{0,1}[0-9]{1,7}))$"; + public const string Boolean = "^(true|false)$"; + public const string Decimal = @"^[0-9]+\.[0-9]+$"; + public const string Integer = "^[0-9]+$"; }
diff --git a/EPPlus/FormulaParsing/Utilities/Require.cs b/EPPlus/FormulaParsing/Utilities/Require.cs index 443ee50..35d53cd 100644 --- a/EPPlus/FormulaParsing/Utilities/Require.cs +++ b/EPPlus/FormulaParsing/Utilities/Require.cs
@@ -1,15 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.FormulaParsing.Utilities; -namespace OfficeOpenXml.FormulaParsing.Utilities -{ - public static class Require - { - public static ArgumentInfo<T> That<T>(T arg) - { - return new ArgumentInfo<T>(arg); - } - } +public static class Require { + public static ArgumentInfo<T> That<T>(T arg) { + return new(arg); + } }
diff --git a/EPPlus/IRangeID.cs b/EPPlus/IRangeID.cs index 6c96524..8ead21d 100644 --- a/EPPlus/IRangeID.cs +++ b/EPPlus/IRangeID.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,42 +13,33 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 2010-02-04 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -namespace OfficeOpenXml -{ - /// <summary> - /// Id from a cell, column or row. - /// </summary> - interface IRangeID - { - /// <summary> - /// This is the id for a cell, row or column. - /// The id is a composit of the SheetID, the row number and the column number. - /// Bit 1-14 SheetID, Bit 15-28 Column number (0 if entire column), Bit 29- Row number (0 if entire row). - /// </summary> - ulong RangeID - { - get; - set; - } - } +namespace OfficeOpenXml; + +/// <summary> +/// Id from a cell, column or row. +/// </summary> +internal interface IRangeId { + /// <summary> + /// This is the id for a cell, row or column. + /// The id is a composit of the SheetID, the row number and the column number. + /// Bit 1-14 SheetID, Bit 15-28 Column number (0 if entire column), Bit 29- Row number (0 if entire row). + /// </summary> + ulong RangeID { get; set; } }
diff --git a/EPPlus/OfficeProperties.cs b/EPPlus/OfficeProperties.cs index d9e83ba..62df7e5 100644 --- a/EPPlus/OfficeProperties.cs +++ b/EPPlus/OfficeProperties.cs
@@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan K�llman Initial Release 2009-10-01 @@ -31,518 +31,448 @@ * Jan K�llman License changed GPL-->LGPL 2011-12-27 * Raziq York Added Created & Modified 2014-08-20 *******************************************************************************/ + using System; -using System.Xml; -using System.IO; using System.Globalization; +using System.IO; +using System.Xml; +using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils; -namespace OfficeOpenXml -{ - /// <summary> - /// Provides access to the properties bag of the package - /// </summary> - public sealed class OfficeProperties : XmlHelper - { - #region Private Properties - private XmlDocument _xmlPropertiesCore; - private XmlDocument _xmlPropertiesExtended; - private XmlDocument _xmlPropertiesCustom; +namespace OfficeOpenXml; - private Uri _uriPropertiesCore = new Uri("/docProps/core.xml", UriKind.Relative); - private Uri _uriPropertiesExtended = new Uri("/docProps/app.xml", UriKind.Relative); - private Uri _uriPropertiesCustom = new Uri("/docProps/custom.xml", UriKind.Relative); +/// <summary> +/// Provides access to the properties bag of the package +/// </summary> +public sealed class OfficeProperties : XmlHelper { + private XmlDocument _xmlPropertiesCore; + private XmlDocument _xmlPropertiesExtended; + private XmlDocument _xmlPropertiesCustom; - XmlHelper _coreHelper; - XmlHelper _extendedHelper; - XmlHelper _customHelper; - private ExcelPackage _package; - #endregion + private Uri _uriPropertiesCore = new("/docProps/core.xml", UriKind.Relative); + private Uri _uriPropertiesExtended = new("/docProps/app.xml", UriKind.Relative); + private Uri _uriPropertiesCustom = new("/docProps/custom.xml", UriKind.Relative); - #region ExcelProperties Constructor - /// <summary> - /// Provides access to all the office document properties. - /// </summary> - /// <param name="package"></param> - /// <param name="ns"></param> - internal OfficeProperties(ExcelPackage package, XmlNamespaceManager ns) : - base(ns) - { - _package = package; + private XmlHelper _coreHelper; + private XmlHelper _extendedHelper; + private XmlHelper _customHelper; + private ExcelPackage _package; - _coreHelper = XmlHelperFactory.Create(ns, CorePropertiesXml.SelectSingleNode("cp:coreProperties", NameSpaceManager)); - _extendedHelper = XmlHelperFactory.Create(ns, ExtendedPropertiesXml); - _customHelper = XmlHelperFactory.Create(ns, CustomPropertiesXml); + /// <summary> + /// Provides access to all the office document properties. + /// </summary> + /// <param name="package"></param> + /// <param name="ns"></param> + internal OfficeProperties(ExcelPackage package, XmlNamespaceManager ns) + : base(ns) { + _package = package; - } - #endregion - #region CorePropertiesXml - /// <summary> - /// Provides access to the XML document that holds all the code - /// document properties. - /// </summary> - public XmlDocument CorePropertiesXml - { - get - { - if (_xmlPropertiesCore == null) - { - string xml = string.Format("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><cp:coreProperties xmlns:cp=\"{0}\" xmlns:dc=\"{1}\" xmlns:dcterms=\"{2}\" xmlns:dcmitype=\"{3}\" xmlns:xsi=\"{4}\"></cp:coreProperties>", - ExcelPackage.schemaCore, - ExcelPackage.schemaDc, - ExcelPackage.schemaDcTerms, - ExcelPackage.schemaDcmiType, - ExcelPackage.schemaXsi); + _coreHelper = XmlHelperFactory.Create( + ns, + CorePropertiesXml.SelectSingleNode("cp:coreProperties", NameSpaceManager)); + _extendedHelper = XmlHelperFactory.Create(ns, ExtendedPropertiesXml); + _customHelper = XmlHelperFactory.Create(ns, CustomPropertiesXml); + } - _xmlPropertiesCore = GetXmlDocument(xml, _uriPropertiesCore, @"application/vnd.openxmlformats-package.core-properties+xml", @"http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"); - } - return (_xmlPropertiesCore); - } - } + /// <summary> + /// Provides access to the XML document that holds all the code + /// document properties. + /// </summary> + public XmlDocument CorePropertiesXml { + get { + if (_xmlPropertiesCore == null) { + string xml = string.Format( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><cp:coreProperties xmlns:cp=\"{0}\" xmlns:dc=\"{1}\" xmlns:dcterms=\"{2}\" xmlns:dcmitype=\"{3}\" xmlns:xsi=\"{4}\"></cp:coreProperties>", + ExcelPackage._schemaCore, + ExcelPackage._schemaDc, + ExcelPackage._schemaDcTerms, + ExcelPackage._schemaDcmiType, + ExcelPackage._schemaXsi); - private XmlDocument GetXmlDocument(string startXml, Uri uri, string contentType, string relationship) - { - XmlDocument xmlDoc; - if (_package.Package.PartExists(uri)) - xmlDoc = _package.GetXmlFromUri(uri); - else - { - xmlDoc = new XmlDocument(); - xmlDoc.LoadXml(startXml); - - // Create a the part and add to the package - Packaging.ZipPackagePart part = _package.Package.CreatePart(uri, contentType); - - // Save it to the package - StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write)); - xmlDoc.Save(stream); - //stream.Close(); - - // create the relationship between the workbook and the new shared strings part - _package.Package.CreateRelationship(UriHelper.GetRelativeUri(new Uri("/xl", UriKind.Relative), uri), Packaging.TargetMode.Internal, relationship); - } - return xmlDoc; - } - #endregion - #region Core Properties - const string TitlePath = "dc:title"; - /// <summary> - /// Gets/sets the title property of the document (core property) - /// </summary> - public string Title - { - get { return _coreHelper.GetXmlNodeString(TitlePath); } - set { _coreHelper.SetXmlNodeString(TitlePath, value); } - } - - const string SubjectPath = "dc:subject"; - /// <summary> - /// Gets/sets the subject property of the document (core property) - /// </summary> - public string Subject - { - get { return _coreHelper.GetXmlNodeString(SubjectPath); } - set { _coreHelper.SetXmlNodeString(SubjectPath, value); } - } - - const string AuthorPath = "dc:creator"; - /// <summary> - /// Gets/sets the author property of the document (core property) - /// </summary> - public string Author - { - get { return _coreHelper.GetXmlNodeString(AuthorPath); } - set { _coreHelper.SetXmlNodeString(AuthorPath, value); } - } - - const string CommentsPath = "dc:description"; - /// <summary> - /// Gets/sets the comments property of the document (core property) - /// </summary> - public string Comments - { - get { return _coreHelper.GetXmlNodeString(CommentsPath); } - set { _coreHelper.SetXmlNodeString(CommentsPath, value); } - } - - const string KeywordsPath = "cp:keywords"; - /// <summary> - /// Gets/sets the keywords property of the document (core property) - /// </summary> - public string Keywords - { - get { return _coreHelper.GetXmlNodeString(KeywordsPath); } - set { _coreHelper.SetXmlNodeString(KeywordsPath, value); } - } - - const string LastModifiedByPath = "cp:lastModifiedBy"; - /// <summary> - /// Gets/sets the lastModifiedBy property of the document (core property) - /// </summary> - public string LastModifiedBy - { - get { return _coreHelper.GetXmlNodeString(LastModifiedByPath); } - set - { - _coreHelper.SetXmlNodeString(LastModifiedByPath, value); - } - } - - const string LastPrintedPath = "cp:lastPrinted"; - /// <summary> - /// Gets/sets the lastPrinted property of the document (core property) - /// </summary> - public string LastPrinted - { - get { return _coreHelper.GetXmlNodeString(LastPrintedPath); } - set { _coreHelper.SetXmlNodeString(LastPrintedPath, value); } - } - - const string CreatedPath = "dcterms:created"; - - /// <summary> - /// Gets/sets the created property of the document (core property) - /// </summary> - public DateTime Created - { - get - { - DateTime date; - return DateTime.TryParse(_coreHelper.GetXmlNodeString(CreatedPath), out date) ? date : DateTime.MinValue; - } - set - { - var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z"; - _coreHelper.SetXmlNodeString(CreatedPath, dateString); - _coreHelper.SetXmlNodeString(CreatedPath + "/@xsi:type", "dcterms:W3CDTF"); - } - } - - const string CategoryPath = "cp:category"; - /// <summary> - /// Gets/sets the category property of the document (core property) - /// </summary> - public string Category - { - get { return _coreHelper.GetXmlNodeString(CategoryPath); } - set { _coreHelper.SetXmlNodeString(CategoryPath, value); } - } - - const string ContentStatusPath = "cp:contentStatus"; - /// <summary> - /// Gets/sets the status property of the document (core property) - /// </summary> - public string Status - { - get { return _coreHelper.GetXmlNodeString(ContentStatusPath); } - set { _coreHelper.SetXmlNodeString(ContentStatusPath, value); } - } - #endregion - - #region Extended Properties - #region ExtendedPropertiesXml - /// <summary> - /// Provides access to the XML document that holds the extended properties of the document (app.xml) - /// </summary> - public XmlDocument ExtendedPropertiesXml - { - get - { - if (_xmlPropertiesExtended == null) - { - _xmlPropertiesExtended = GetXmlDocument(string.Format("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><Properties xmlns:vt=\"{0}\" xmlns=\"{1}\"></Properties>", - ExcelPackage.schemaVt, - ExcelPackage.schemaExtended), - _uriPropertiesExtended, - @"application/vnd.openxmlformats-officedocument.extended-properties+xml", - @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"); - } - return (_xmlPropertiesExtended); - } - } - #endregion - - const string ApplicationPath = "xp:Properties/xp:Application"; - /// <summary> - /// Gets/Set the Application property of the document (extended property) - /// </summary> - public string Application - { - get { return _extendedHelper.GetXmlNodeString(ApplicationPath); } - set { _extendedHelper.SetXmlNodeString(ApplicationPath, value); } - } - - const string HyperlinkBasePath = "xp:Properties/xp:HyperlinkBase"; - /// <summary> - /// Gets/sets the HyperlinkBase property of the document (extended property) - /// </summary> - public Uri HyperlinkBase - { - get { return new Uri(_extendedHelper.GetXmlNodeString(HyperlinkBasePath), UriKind.Absolute); } - set { _extendedHelper.SetXmlNodeString(HyperlinkBasePath, value.AbsoluteUri); } - } - - const string AppVersionPath = "xp:Properties/xp:AppVersion"; - /// <summary> - /// Gets/Set the AppVersion property of the document (extended property) - /// </summary> - public string AppVersion - { - get { return _extendedHelper.GetXmlNodeString(AppVersionPath); } - set { _extendedHelper.SetXmlNodeString(AppVersionPath, value); } - } - const string CompanyPath = "xp:Properties/xp:Company"; - - /// <summary> - /// Gets/sets the Company property of the document (extended property) - /// </summary> - public string Company - { - get { return _extendedHelper.GetXmlNodeString(CompanyPath); } - set { _extendedHelper.SetXmlNodeString(CompanyPath, value); } - } - - const string ManagerPath = "xp:Properties/xp:Manager"; - /// <summary> - /// Gets/sets the Manager property of the document (extended property) - /// </summary> - public string Manager - { - get { return _extendedHelper.GetXmlNodeString(ManagerPath); } - set { _extendedHelper.SetXmlNodeString(ManagerPath, value); } - } - - const string ModifiedPath = "dcterms:modified"; - /// <summary> - /// Gets/sets the modified property of the document (core property) - /// </summary> - public DateTime Modified - { - get - { - DateTime date; - return DateTime.TryParse(_coreHelper.GetXmlNodeString(ModifiedPath), out date) ? date : DateTime.MinValue; - } - set - { - var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z"; - _coreHelper.SetXmlNodeString(ModifiedPath, dateString); - _coreHelper.SetXmlNodeString(ModifiedPath + "/@xsi:type", "dcterms:W3CDTF"); - } - } - - #region Get and Set Extended Properties - private string GetExtendedPropertyValue(string propertyName) - { - string retValue = null; - string searchString = string.Format("xp:Properties/xp:{0}", propertyName); - XmlNode node = ExtendedPropertiesXml.SelectSingleNode(searchString, NameSpaceManager); - if (node != null) - { - retValue = node.InnerText; - } - return retValue; - } - #endregion - #endregion - - #region Custom Properties - - #region CustomPropertiesXml - /// <summary> - /// Provides access to the XML document which holds the document's custom properties - /// </summary> - public XmlDocument CustomPropertiesXml - { - get - { - if (_xmlPropertiesCustom == null) - { - _xmlPropertiesCustom = GetXmlDocument(string.Format("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><Properties xmlns:vt=\"{0}\" xmlns=\"{1}\"></Properties>", - ExcelPackage.schemaVt, - ExcelPackage.schemaCustom), - _uriPropertiesCustom, - @"application/vnd.openxmlformats-officedocument.custom-properties+xml", - @"http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties"); - } - return (_xmlPropertiesCustom); - } - } - #endregion - - #region Get and Set Custom Properties - /// <summary> - /// Gets the value of a custom property - /// </summary> - /// <param name="propertyName">The name of the property</param> - /// <returns>The current value of the property</returns> - public object GetCustomPropertyValue(string propertyName) - { - string searchString = string.Format("ctp:Properties/ctp:property[@name='{0}']", propertyName); - XmlElement node = CustomPropertiesXml.SelectSingleNode(searchString, NameSpaceManager) as XmlElement; - if (node != null) - { - string value = node.LastChild.InnerText; - switch (node.LastChild.LocalName) - { - case "filetime": - DateTime dt; - if (DateTime.TryParse(value, out dt)) - { - return dt; - } - else - { - return null; - } - case "i4": - int i; - if (int.TryParse(value, out i)) - { - return i; - } - else - { - return null; - } - case "r8": - double d; - if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) - { - return d; - } - else - { - return null; - } - case "bool": - if (value == "true") - { - return true; - } - else if (value == "false") - { - return false; - } - else - { - return null; - } - default: - return value; - } - } - else - { - return null; - } - } - - /// <summary> - /// Allows you to set the value of a current custom property or create your own custom property. - /// </summary> - /// <param name="propertyName">The name of the property</param> - /// <param name="value">The value of the property</param> - public void SetCustomPropertyValue(string propertyName, object value) - { - XmlNode allProps = CustomPropertiesXml.SelectSingleNode(@"ctp:Properties", NameSpaceManager); - - var prop = string.Format("ctp:Properties/ctp:property[@name='{0}']", propertyName); - XmlElement node = CustomPropertiesXml.SelectSingleNode(prop, NameSpaceManager) as XmlElement; - if (node == null) - { - int pid; - var MaxNode = CustomPropertiesXml.SelectSingleNode("ctp:Properties/ctp:property[not(@pid <= preceding-sibling::ctp:property/@pid) and not(@pid <= following-sibling::ctp:property/@pid)]", NameSpaceManager); - if (MaxNode == null) - { - pid = 2; - } - else - { - if (!int.TryParse(MaxNode.Attributes["pid"].Value, out pid)) - { - pid = 2; - } - pid++; - } - node = CustomPropertiesXml.CreateElement("property", ExcelPackage.schemaCustom); - node.SetAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"); - node.SetAttribute("pid", pid.ToString()); // custom property pid - node.SetAttribute("name", propertyName); - - allProps.AppendChild(node); - } - else - { - while (node.ChildNodes.Count > 0) node.RemoveChild(node.ChildNodes[0]); - } - XmlElement valueElem; - if (value is bool) - { - valueElem = CustomPropertiesXml.CreateElement("vt", "bool", ExcelPackage.schemaVt); - valueElem.InnerText = value.ToString().ToLower(CultureInfo.InvariantCulture); - } - else if (value is DateTime) - { - valueElem = CustomPropertiesXml.CreateElement("vt", "filetime", ExcelPackage.schemaVt); - valueElem.InnerText = ((DateTime)value).AddHours(-1).ToString("yyyy-MM-ddTHH:mm:ssZ"); - } - else if (value is short || value is int) - { - valueElem = CustomPropertiesXml.CreateElement("vt", "i4", ExcelPackage.schemaVt); - valueElem.InnerText = value.ToString(); - } - else if (value is double || value is decimal || value is float || value is long) - { - valueElem = CustomPropertiesXml.CreateElement("vt", "r8", ExcelPackage.schemaVt); - if (value is double) - { - valueElem.InnerText = ((double)value).ToString(CultureInfo.InvariantCulture); - } - else if (value is float) - { - valueElem.InnerText = ((float)value).ToString(CultureInfo.InvariantCulture); - } - else if (value is decimal) - { - valueElem.InnerText = ((decimal)value).ToString(CultureInfo.InvariantCulture); - } - else - { - valueElem.InnerText = value.ToString(); - } - } - else - { - valueElem = CustomPropertiesXml.CreateElement("vt", "lpwstr", ExcelPackage.schemaVt); - valueElem.InnerText = value.ToString(); - } - node.AppendChild(valueElem); - } - #endregion - #endregion - - #region Save - /// <summary> - /// Saves the document properties back to the package. - /// </summary> - internal void Save() - { - if (_xmlPropertiesCore != null) - { - _package.SavePart(_uriPropertiesCore, _xmlPropertiesCore); - } - if (_xmlPropertiesExtended != null) - { - _package.SavePart(_uriPropertiesExtended, _xmlPropertiesExtended); - } - if (_xmlPropertiesCustom != null) - { - _package.SavePart(_uriPropertiesCustom, _xmlPropertiesCustom); - } - - } - #endregion - + _xmlPropertiesCore = GetXmlDocument( + xml, + _uriPropertiesCore, + "application/vnd.openxmlformats-package.core-properties+xml", + "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties"); + } + return (_xmlPropertiesCore); } + } + + private XmlDocument GetXmlDocument( + string startXml, + Uri uri, + string contentType, + string relationship) { + XmlDocument xmlDoc; + if (_package.Package.PartExists(uri)) { + xmlDoc = _package.GetXmlFromUri(uri); + } else { + xmlDoc = new(); + xmlDoc.LoadXml(startXml); + + // Create a the part and add to the package + ZipPackagePart part = _package.Package.CreatePart(uri, contentType); + + // Save it to the package + StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write)); + xmlDoc.Save(stream); + //stream.Close(); + + // create the relationship between the workbook and the new shared strings part + _package.Package.CreateRelationship( + UriHelper.GetRelativeUri(new("/xl", UriKind.Relative), uri), + TargetMode.Internal, + relationship); + } + return xmlDoc; + } + + private const string _titlePath = "dc:title"; + + /// <summary> + /// Gets/sets the title property of the document (core property) + /// </summary> + public string Title { + get => _coreHelper.GetXmlNodeString(_titlePath); + set => _coreHelper.SetXmlNodeString(_titlePath, value); + } + + private const string _subjectPath = "dc:subject"; + + /// <summary> + /// Gets/sets the subject property of the document (core property) + /// </summary> + public string Subject { + get => _coreHelper.GetXmlNodeString(_subjectPath); + set => _coreHelper.SetXmlNodeString(_subjectPath, value); + } + + private const string _authorPath = "dc:creator"; + + /// <summary> + /// Gets/sets the author property of the document (core property) + /// </summary> + public string Author { + get => _coreHelper.GetXmlNodeString(_authorPath); + set => _coreHelper.SetXmlNodeString(_authorPath, value); + } + + private const string _commentsPath = "dc:description"; + + /// <summary> + /// Gets/sets the comments property of the document (core property) + /// </summary> + public string Comments { + get => _coreHelper.GetXmlNodeString(_commentsPath); + set => _coreHelper.SetXmlNodeString(_commentsPath, value); + } + + private const string _keywordsPath = "cp:keywords"; + + /// <summary> + /// Gets/sets the keywords property of the document (core property) + /// </summary> + public string Keywords { + get => _coreHelper.GetXmlNodeString(_keywordsPath); + set => _coreHelper.SetXmlNodeString(_keywordsPath, value); + } + + private const string _lastModifiedByPath = "cp:lastModifiedBy"; + + /// <summary> + /// Gets/sets the lastModifiedBy property of the document (core property) + /// </summary> + public string LastModifiedBy { + get => _coreHelper.GetXmlNodeString(_lastModifiedByPath); + set => _coreHelper.SetXmlNodeString(_lastModifiedByPath, value); + } + + private const string _lastPrintedPath = "cp:lastPrinted"; + + /// <summary> + /// Gets/sets the lastPrinted property of the document (core property) + /// </summary> + public string LastPrinted { + get => _coreHelper.GetXmlNodeString(_lastPrintedPath); + set => _coreHelper.SetXmlNodeString(_lastPrintedPath, value); + } + + private const string _createdPath = "dcterms:created"; + + /// <summary> + /// Gets/sets the created property of the document (core property) + /// </summary> + public DateTime Created { + get { + DateTime date; + return DateTime.TryParse(_coreHelper.GetXmlNodeString(_createdPath), out date) + ? date + : DateTime.MinValue; + } + set { + var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z"; + _coreHelper.SetXmlNodeString(_createdPath, dateString); + _coreHelper.SetXmlNodeString(_createdPath + "/@xsi:type", "dcterms:W3CDTF"); + } + } + + private const string _categoryPath = "cp:category"; + + /// <summary> + /// Gets/sets the category property of the document (core property) + /// </summary> + public string Category { + get => _coreHelper.GetXmlNodeString(_categoryPath); + set => _coreHelper.SetXmlNodeString(_categoryPath, value); + } + + private const string _contentStatusPath = "cp:contentStatus"; + + /// <summary> + /// Gets/sets the status property of the document (core property) + /// </summary> + public string Status { + get => _coreHelper.GetXmlNodeString(_contentStatusPath); + set => _coreHelper.SetXmlNodeString(_contentStatusPath, value); + } + + /// <summary> + /// Provides access to the XML document that holds the extended properties of the document (app.xml) + /// </summary> + public XmlDocument ExtendedPropertiesXml { + get { + if (_xmlPropertiesExtended == null) { + _xmlPropertiesExtended = GetXmlDocument( + string.Format( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><Properties xmlns:vt=\"{0}\" xmlns=\"{1}\"></Properties>", + ExcelPackage._schemaVt, + ExcelPackage._schemaExtended), + _uriPropertiesExtended, + "application/vnd.openxmlformats-officedocument.extended-properties+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties"); + } + return (_xmlPropertiesExtended); + } + } + + private const string _applicationPath = "xp:Properties/xp:Application"; + + /// <summary> + /// Gets/Set the Application property of the document (extended property) + /// </summary> + public string Application { + get => _extendedHelper.GetXmlNodeString(_applicationPath); + set => _extendedHelper.SetXmlNodeString(_applicationPath, value); + } + + private const string _hyperlinkBasePath = "xp:Properties/xp:HyperlinkBase"; + + /// <summary> + /// Gets/sets the HyperlinkBase property of the document (extended property) + /// </summary> + public Uri HyperlinkBase { + get => new(_extendedHelper.GetXmlNodeString(_hyperlinkBasePath), UriKind.Absolute); + set => _extendedHelper.SetXmlNodeString(_hyperlinkBasePath, value.AbsoluteUri); + } + + private const string _appVersionPath = "xp:Properties/xp:AppVersion"; + + /// <summary> + /// Gets/Set the AppVersion property of the document (extended property) + /// </summary> + public string AppVersion { + get => _extendedHelper.GetXmlNodeString(_appVersionPath); + set => _extendedHelper.SetXmlNodeString(_appVersionPath, value); + } + + private const string _companyPath = "xp:Properties/xp:Company"; + + /// <summary> + /// Gets/sets the Company property of the document (extended property) + /// </summary> + public string Company { + get => _extendedHelper.GetXmlNodeString(_companyPath); + set => _extendedHelper.SetXmlNodeString(_companyPath, value); + } + + private const string _managerPath = "xp:Properties/xp:Manager"; + + /// <summary> + /// Gets/sets the Manager property of the document (extended property) + /// </summary> + public string Manager { + get => _extendedHelper.GetXmlNodeString(_managerPath); + set => _extendedHelper.SetXmlNodeString(_managerPath, value); + } + + private const string _modifiedPath = "dcterms:modified"; + + /// <summary> + /// Gets/sets the modified property of the document (core property) + /// </summary> + public DateTime Modified { + get { + DateTime date; + return DateTime.TryParse(_coreHelper.GetXmlNodeString(_modifiedPath), out date) + ? date + : DateTime.MinValue; + } + set { + var dateString = value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture) + "Z"; + _coreHelper.SetXmlNodeString(_modifiedPath, dateString); + _coreHelper.SetXmlNodeString(_modifiedPath + "/@xsi:type", "dcterms:W3CDTF"); + } + } + + private string GetExtendedPropertyValue(string propertyName) { + string retValue = null; + string searchString = string.Format("xp:Properties/xp:{0}", propertyName); + XmlNode node = ExtendedPropertiesXml.SelectSingleNode(searchString, NameSpaceManager); + if (node != null) { + retValue = node.InnerText; + } + return retValue; + } + + /// <summary> + /// Provides access to the XML document which holds the document's custom properties + /// </summary> + public XmlDocument CustomPropertiesXml { + get { + if (_xmlPropertiesCustom == null) { + _xmlPropertiesCustom = GetXmlDocument( + string.Format( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><Properties xmlns:vt=\"{0}\" xmlns=\"{1}\"></Properties>", + ExcelPackage._schemaVt, + ExcelPackage._schemaCustom), + _uriPropertiesCustom, + "application/vnd.openxmlformats-officedocument.custom-properties+xml", + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties"); + } + return (_xmlPropertiesCustom); + } + } + + /// <summary> + /// Gets the value of a custom property + /// </summary> + /// <param name="propertyName">The name of the property</param> + /// <returns>The current value of the property</returns> + public object GetCustomPropertyValue(string propertyName) { + string searchString = string.Format("ctp:Properties/ctp:property[@name='{0}']", propertyName); + XmlElement node = + CustomPropertiesXml.SelectSingleNode(searchString, NameSpaceManager) as XmlElement; + if (node != null) { + string value = node.LastChild.InnerText; + switch (node.LastChild.LocalName) { + case "filetime": + DateTime dt; + if (DateTime.TryParse(value, out dt)) { + return dt; + } + return null; + case "i4": + int i; + if (int.TryParse(value, out i)) { + return i; + } + return null; + case "r8": + double d; + if (double.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, out d)) { + return d; + } + return null; + case "bool": + if (value == "true") { + return true; + } + if (value == "false") { + return false; + } + return null; + default: + return value; + } + } + return null; + } + + /// <summary> + /// Allows you to set the value of a current custom property or create your own custom property. + /// </summary> + /// <param name="propertyName">The name of the property</param> + /// <param name="value">The value of the property</param> + public void SetCustomPropertyValue(string propertyName, object value) { + XmlNode allProps = CustomPropertiesXml.SelectSingleNode("ctp:Properties", NameSpaceManager); + + var prop = string.Format("ctp:Properties/ctp:property[@name='{0}']", propertyName); + XmlElement node = CustomPropertiesXml.SelectSingleNode(prop, NameSpaceManager) as XmlElement; + if (node == null) { + int pid; + var maxNode = CustomPropertiesXml.SelectSingleNode( + "ctp:Properties/ctp:property[not(@pid <= preceding-sibling::ctp:property/@pid) and not(@pid <= following-sibling::ctp:property/@pid)]", + NameSpaceManager); + if (maxNode == null) { + pid = 2; + } else { + if (!int.TryParse(maxNode.Attributes["pid"].Value, out pid)) { + pid = 2; + } + pid++; + } + node = CustomPropertiesXml.CreateElement("property", ExcelPackage._schemaCustom); + node.SetAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"); + node.SetAttribute("pid", pid.ToString()); // custom property pid + node.SetAttribute("name", propertyName); + + allProps.AppendChild(node); + } else { + while (node.ChildNodes.Count > 0) { + node.RemoveChild(node.ChildNodes[0]); + } + } + XmlElement valueElem; + if (value is bool) { + valueElem = CustomPropertiesXml.CreateElement("vt", "bool", ExcelPackage._schemaVt); + valueElem.InnerText = value.ToString().ToLower(CultureInfo.InvariantCulture); + } else if (value is DateTime) { + valueElem = CustomPropertiesXml.CreateElement("vt", "filetime", ExcelPackage._schemaVt); + valueElem.InnerText = ((DateTime)value).AddHours(-1).ToString("yyyy-MM-ddTHH:mm:ssZ"); + } else if (value is short || value is int) { + valueElem = CustomPropertiesXml.CreateElement("vt", "i4", ExcelPackage._schemaVt); + valueElem.InnerText = value.ToString(); + } else if (value is double || value is decimal || value is float || value is long) { + valueElem = CustomPropertiesXml.CreateElement("vt", "r8", ExcelPackage._schemaVt); + if (value is double) { + valueElem.InnerText = ((double)value).ToString(CultureInfo.InvariantCulture); + } else if (value is float) { + valueElem.InnerText = ((float)value).ToString(CultureInfo.InvariantCulture); + } else if (value is decimal) { + valueElem.InnerText = ((decimal)value).ToString(CultureInfo.InvariantCulture); + } else { + valueElem.InnerText = value.ToString(); + } + } else { + valueElem = CustomPropertiesXml.CreateElement("vt", "lpwstr", ExcelPackage._schemaVt); + valueElem.InnerText = value.ToString(); + } + node.AppendChild(valueElem); + } + + /// <summary> + /// Saves the document properties back to the package. + /// </summary> + internal void Save() { + if (_xmlPropertiesCore != null) { + _package.SavePart(_uriPropertiesCore, _xmlPropertiesCore); + } + if (_xmlPropertiesExtended != null) { + _package.SavePart(_uriPropertiesExtended, _xmlPropertiesExtended); + } + if (_xmlPropertiesCustom != null) { + _package.SavePart(_uriPropertiesCustom, _xmlPropertiesCustom); + } + } }
diff --git a/EPPlus/Packaging/ZipPackage.cs b/EPPlus/Packaging/ZipPackage.cs index 12e3431..4dbed56 100644 --- a/EPPlus/Packaging/ZipPackage.cs +++ b/EPPlus/Packaging/ZipPackage.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,305 +13,273 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 25-Oct-2012 *******************************************************************************/ + using System; using System.Collections.Generic; using System.Globalization; -using System.Linq; -using System.Text; using System.IO; using System.IO.Compression; +using System.Linq; +using System.Text; using System.Xml; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.Packaging -{ - /// <summary> - /// Specifies whether the target is inside or outside the System.IO.Packaging.Package. - /// </summary> - public enum TargetMode - { - /// <summary> - /// The relationship references a part that is inside the package. - /// </summary> - Internal = 0, - /// <summary> - /// The relationship references a resource that is external to the package. - /// </summary> - External = 1, + +namespace OfficeOpenXml.Packaging; + +/// <summary> +/// Specifies whether the target is inside or outside the System.IO.Packaging.Package. +/// </summary> +public enum TargetMode { + /// <summary> + /// The relationship references a part that is inside the package. + /// </summary> + Internal = 0, + + /// <summary> + /// The relationship references a resource that is external to the package. + /// </summary> + External = 1, +} + +/// <summary> +/// Represent an OOXML Zip package. +/// </summary> +public class ZipPackage : ZipPackageRelationshipBase { + internal class ContentType { + internal string Name; + internal bool IsExtension; + internal string Match; + + public ContentType(string name, bool isExtension, string match) { + Name = name; + IsExtension = isExtension; + Match = match; } - /// <summary> - /// Represent an OOXML Zip package. - /// </summary> - public class ZipPackage : ZipPackageRelationshipBase - { - internal class ContentType - { - internal string Name; - internal bool IsExtension; - internal string Match; - public ContentType(string name, bool isExtension, string match) - { - Name = name; - IsExtension = isExtension; - Match = match; - } - } - Dictionary<string, ZipPackagePart> Parts = new Dictionary<string, ZipPackagePart>(StringComparer.InvariantCultureIgnoreCase); - internal Dictionary<string, ContentType> _contentTypes = new Dictionary<string, ContentType>(StringComparer.InvariantCultureIgnoreCase); - internal ZipPackage() - { - AddNew(); - } + } - private void AddNew() - { - _contentTypes.Add("xml", new ContentType(ExcelPackage.schemaXmlExtension, true, "xml")); - _contentTypes.Add("rels", new ContentType(ExcelPackage.schemaRelsExtension, true, "rels")); - } + private Dictionary<string, ZipPackagePart> Parts = new(StringComparer.InvariantCultureIgnoreCase); + internal Dictionary<string, ContentType> _contentTypes = new( + StringComparer.InvariantCultureIgnoreCase); - internal ZipPackage(Stream stream) - { - bool hasContentTypeXml = false; - if (stream == null || stream.Length == 0) - { - AddNew(); - } - else - { - var rels = new Dictionary<string, ZipArchiveEntry>(); - stream.Seek(0, SeekOrigin.Begin); - using var zip = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true); - foreach (var e in zip.Entries) - { - if (e.Length > 0) - { - if (e.FullName .Equals("[content_types].xml", StringComparison.InvariantCultureIgnoreCase)) - { - using var inputStream = e.Open(); - AddContentTypes(inputStream); - hasContentTypeXml = true; - } - else if (e.FullName .Equals("_rels/.rels", StringComparison.InvariantCultureIgnoreCase)) - { - using var inputStream = e.Open(); - ReadRelation(inputStream, ""); - } - else - { - if (e.FullName.EndsWith(".rels", StringComparison.InvariantCultureIgnoreCase)) - { - rels.Add(GetUriKey(e.FullName), e); - } - else - { - using var inputStream = e.Open(); - var part = new ZipPackagePart(this, e); - part.Stream = new MemoryStream(); - inputStream.CopyTo(part.Stream); - Parts.Add(GetUriKey(e.FullName), part); - } - } - } - } - foreach (var p in Parts) - { - string name = Path.GetFileName(p.Key); - string extension = Path.GetExtension(p.Key); - string relFile = string.Format("{0}_rels/{1}.rels", p.Key.Substring(0, p.Key.Length - name.Length), name); - if (rels.TryGetValue(relFile, out var zipArchiveEntry)) - { - using var inputStream = zipArchiveEntry.Open(); - p.Value.ReadRelation(inputStream, p.Value.Uri.OriginalString); - } - if (_contentTypes.TryGetValue(p.Key, out var type)) - { - p.Value.ContentType = type.Name; - } - else if (extension.Length > 1 && _contentTypes.ContainsKey(extension.Substring(1))) - { - p.Value.ContentType = _contentTypes[extension.Substring(1)].Name; - } - } - if (!hasContentTypeXml) - { - throw new InvalidDataException("The file is not an valid Package file."); - } - } - } + internal ZipPackage() { + AddNew(); + } - private void AddContentTypes(Stream inputStream) - { - var doc = new XmlDocument(); - XmlHelper.LoadXmlSafe(doc, inputStream); + private void AddNew() { + _contentTypes.Add("xml", new(ExcelPackage._schemaXmlExtension, true, "xml")); + _contentTypes.Add("rels", new(ExcelPackage._schemaRelsExtension, true, "rels")); + } - foreach (XmlElement c in doc.DocumentElement.ChildNodes) - { - ContentType ct; - if (string.IsNullOrEmpty(c.GetAttribute("Extension"))) - { - ct = new ContentType(c.GetAttribute("ContentType"), false, c.GetAttribute("PartName")); - } - else - { - ct = new ContentType(c.GetAttribute("ContentType"), true, c.GetAttribute("Extension")); - } - _contentTypes.Add(GetUriKey(ct.Match), ct); + internal ZipPackage(Stream stream) { + bool hasContentTypeXml = false; + if (stream == null || stream.Length == 0) { + AddNew(); + } else { + var rels = new Dictionary<string, ZipArchiveEntry>(); + stream.Seek(0, SeekOrigin.Begin); + using var zip = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen: true); + foreach (var e in zip.Entries) { + if (e.Length > 0) { + if (e.FullName.Equals( + "[content_types].xml", + StringComparison.InvariantCultureIgnoreCase)) { + using var inputStream = e.Open(); + AddContentTypes(inputStream); + hasContentTypeXml = true; + } else if (e.FullName.Equals( + "_rels/.rels", + StringComparison.InvariantCultureIgnoreCase)) { + using var inputStream = e.Open(); + ReadRelation(inputStream, ""); + } else { + if (e.FullName.EndsWith(".rels", StringComparison.InvariantCultureIgnoreCase)) { + rels.Add(GetUriKey(e.FullName), e); + } else { + using var inputStream = e.Open(); + var part = new ZipPackagePart(this, e); + part.Stream = new(); + inputStream.CopyTo(part.Stream); + Parts.Add(GetUriKey(e.FullName), part); } + } } - - #region Methods - internal ZipPackagePart CreatePart(Uri partUri, string contentType) - { - return CreatePart(partUri, contentType, CompressionLevel.Default); + } + foreach (var p in Parts) { + string name = Path.GetFileName(p.Key); + string extension = Path.GetExtension(p.Key); + string relFile = string.Format( + "{0}_rels/{1}.rels", + p.Key.Substring(0, p.Key.Length - name.Length), + name); + if (rels.TryGetValue(relFile, out var zipArchiveEntry)) { + using var inputStream = zipArchiveEntry.Open(); + p.Value.ReadRelation(inputStream, p.Value.Uri.OriginalString); } - internal ZipPackagePart CreatePart(Uri partUri, string contentType, CompressionLevel compressionLevel) - { - if (PartExists(partUri)) - { - throw (new InvalidOperationException("Part already exist")); - } - - var part = new ZipPackagePart(this, partUri, contentType, compressionLevel); - _contentTypes.Add(GetUriKey(part.Uri.OriginalString), new ContentType(contentType, false, part.Uri.OriginalString)); - Parts.Add(GetUriKey(part.Uri.OriginalString), part); - return part; + if (_contentTypes.TryGetValue(p.Key, out var type)) { + p.Value.ContentType = type.Name; + } else if (extension.Length > 1 && _contentTypes.ContainsKey(extension.Substring(1))) { + p.Value.ContentType = _contentTypes[extension.Substring(1)].Name; } - internal ZipPackagePart GetPart(Uri partUri) - { - if (PartExists(partUri)) - { - return Parts.Single(x => x.Key.Equals(GetUriKey(partUri.OriginalString),StringComparison.InvariantCultureIgnoreCase)).Value; - } - else - { - throw (new InvalidOperationException("Part does not exist.")); - } - } - - internal string GetUriKey(string uri) - { - string ret = uri; - if (ret[0] != '/') - { - ret = "/" + ret; - } - return ret; - } - internal bool PartExists(Uri partUri) - { - var uriKey = GetUriKey(partUri.OriginalString.ToLower(CultureInfo.InvariantCulture)); - return Parts.Keys.Any(x => x.Equals(uriKey, StringComparison.InvariantCultureIgnoreCase)); - } - #endregion - - internal void DeletePart(Uri Uri) - { - var delList=new List<object[]>(); - foreach (var p in Parts.Values) - { - foreach (var r in p.GetRelationships()) - { - if (UriHelper.ResolvePartUri(p.Uri, r.TargetUri).OriginalString.Equals(Uri.OriginalString, StringComparison.InvariantCultureIgnoreCase)) - { - delList.Add(new object[]{r.Id, p}); - } - } - } - foreach (var o in delList) - { - ((ZipPackagePart)o[1]).DeleteRelationship(o[0].ToString()); - } - var rels = GetPart(Uri).GetRelationships(); - while (rels.Count > 0) - { - rels.Remove(rels.First().Id); - } - rels=null; - _contentTypes.Remove(GetUriKey(Uri.OriginalString)); - //remove all relations - Parts.Remove(GetUriKey(Uri.OriginalString)); - - } - internal void Save(Stream stream) - { - using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true); - /**** ContentType****/ - var contentTypesEntry = zipArchive.CreateEntry("[Content_Types].xml"); - using (var contentTypesWriter = new StreamWriter(contentTypesEntry.Open())) - { - contentTypesWriter.Write(GetContentTypeXml()); - } - /**** Top Rels ****/ - _rels.WriteZip(zipArchive, "_rels\\.rels"); - ZipPackagePart ssPart=null; - foreach(var part in Parts.Values) - { - if (part.ContentType != ExcelPackage.contentTypeSharedString) - { - part.WriteZip(zipArchive); - } - else - { - ssPart = part; - } - } - //Shared strings must be saved after all worksheets. The ss dictionary is populated when that workheets are saved (to get the best performance). - if (ssPart != null) - { - ssPart.WriteZip(zipArchive); - } - //return ms; - } - - private string GetContentTypeXml() - { - StringBuilder xml = new StringBuilder("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">"); - foreach (ContentType ct in _contentTypes.Values) - { - if (ct.IsExtension) - { - xml.AppendFormat("<Default ContentType=\"{0}\" Extension=\"{1}\"/>", ct.Name, ct.Match); - } - else - { - xml.AppendFormat("<Override ContentType=\"{0}\" PartName=\"{1}\" />", ct.Name, GetUriKey(ct.Match)); - } - } - xml.Append("</Types>"); - return xml.ToString(); - } - CompressionLevel _compression = CompressionLevel.Default; - public CompressionLevel Compression - { - get - { - return _compression; - } - set - { - foreach (var part in Parts.Values) - { - if (part.CompressionLevel == _compression) - { - part.CompressionLevel = value; - } - } - _compression = value; - } - } + } + if (!hasContentTypeXml) { + throw new InvalidDataException("The file is not an valid Package file."); + } } + } + + private void AddContentTypes(Stream inputStream) { + var doc = new XmlDocument(); + XmlHelper.LoadXmlSafe(doc, inputStream); + + foreach (XmlElement c in doc.DocumentElement.ChildNodes) { + ContentType ct; + if (string.IsNullOrEmpty(c.GetAttribute("Extension"))) { + ct = new(c.GetAttribute("ContentType"), false, c.GetAttribute("PartName")); + } else { + ct = new(c.GetAttribute("ContentType"), true, c.GetAttribute("Extension")); + } + _contentTypes.Add(GetUriKey(ct.Match), ct); + } + } + + internal ZipPackagePart CreatePart(Uri partUri, string contentType) { + return CreatePart(partUri, contentType, CompressionLevel.Default); + } + + internal ZipPackagePart CreatePart( + Uri partUri, + string contentType, + CompressionLevel compressionLevel) { + if (PartExists(partUri)) { + throw (new InvalidOperationException("Part already exist")); + } + + var part = new ZipPackagePart(this, partUri, contentType, compressionLevel); + _contentTypes.Add( + GetUriKey(part.Uri.OriginalString), + new(contentType, false, part.Uri.OriginalString)); + Parts.Add(GetUriKey(part.Uri.OriginalString), part); + return part; + } + + internal ZipPackagePart GetPart(Uri partUri) { + if (PartExists(partUri)) { + return Parts + .Single(x => + x.Key.Equals( + GetUriKey(partUri.OriginalString), + StringComparison.InvariantCultureIgnoreCase)) + .Value; + } + throw (new InvalidOperationException("Part does not exist.")); + } + + internal string GetUriKey(string uri) { + string ret = uri; + if (ret[0] != '/') { + ret = "/" + ret; + } + return ret; + } + + internal bool PartExists(Uri partUri) { + var uriKey = GetUriKey(partUri.OriginalString.ToLower(CultureInfo.InvariantCulture)); + return Parts.Keys.Any(x => x.Equals(uriKey, StringComparison.InvariantCultureIgnoreCase)); + } + + internal void DeletePart(Uri uri) { + var delList = new List<object[]>(); + foreach (var p in Parts.Values) { + foreach (var r in p.GetRelationships()) { + if (UriHelper + .ResolvePartUri(p.Uri, r.TargetUri) + .OriginalString.Equals( + uri.OriginalString, + StringComparison.InvariantCultureIgnoreCase)) { + delList.Add(new object[] { r.Id, p }); + } + } + } + foreach (var o in delList) { + ((ZipPackagePart)o[1]).DeleteRelationship(o[0].ToString()); + } + var rels = GetPart(uri).GetRelationships(); + while (rels.Count > 0) { + rels.Remove(rels.First().Id); + } + rels = null; + _contentTypes.Remove(GetUriKey(uri.OriginalString)); + //remove all relations + Parts.Remove(GetUriKey(uri.OriginalString)); + } + + internal void Save(Stream stream) { + using var zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen: true); + /**** ContentType****/ + var contentTypesEntry = zipArchive.CreateEntry("[Content_Types].xml"); + using (var contentTypesWriter = new StreamWriter(contentTypesEntry.Open())) { + contentTypesWriter.Write(GetContentTypeXml()); + } + /**** Top Rels ****/ + _rels.WriteZip(zipArchive, "_rels\\.rels"); + ZipPackagePart ssPart = null; + foreach (var part in Parts.Values) { + if (part.ContentType != ExcelPackage._contentTypeSharedString) { + part.WriteZip(zipArchive); + } else { + ssPart = part; + } + } + //Shared strings must be saved after all worksheets. The ss dictionary is populated when that workheets are saved (to get the best performance). + if (ssPart != null) { + ssPart.WriteZip(zipArchive); + } + //return ms; + } + + private string GetContentTypeXml() { + StringBuilder xml = new StringBuilder( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">"); + foreach (ContentType ct in _contentTypes.Values) { + if (ct.IsExtension) { + xml.AppendFormat("<Default ContentType=\"{0}\" Extension=\"{1}\"/>", ct.Name, ct.Match); + } else { + xml.AppendFormat( + "<Override ContentType=\"{0}\" PartName=\"{1}\" />", + ct.Name, + GetUriKey(ct.Match)); + } + } + xml.Append("</Types>"); + return xml.ToString(); + } + + private CompressionLevel _compression = CompressionLevel.Default; + + public CompressionLevel Compression { + get => _compression; + set { + foreach (var part in Parts.Values) { + if (part.CompressionLevel == _compression) { + part.CompressionLevel = value; + } + } + _compression = value; + } + } }
diff --git a/EPPlus/Packaging/ZipPackagePart.cs b/EPPlus/Packaging/ZipPackagePart.cs index 06ca810..407428d 100644 --- a/EPPlus/Packaging/ZipPackagePart.cs +++ b/EPPlus/Packaging/ZipPackagePart.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,149 +13,135 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 25-Oct-2012 *******************************************************************************/ + using System; using System.IO; using System.IO.Compression; -namespace OfficeOpenXml.Packaging -{ - internal class ZipPackagePart : ZipPackageRelationshipBase, IDisposable - { - internal delegate void SaveHandlerDelegate(StreamWriter streamWriter); +namespace OfficeOpenXml.Packaging; - internal ZipPackagePart(ZipPackage package, ZipArchiveEntry entry) - { - Package = package; - SaveHandler = null; - Uri = new Uri(package.GetUriKey(entry.FullName), UriKind.Relative); - } - internal ZipPackagePart(ZipPackage package, Uri partUri, string contentType, CompressionLevel compressionLevel) - { - Package = package; - //Entry = new ZipEntry(); - //Entry.FileName = partUri.OriginalString.Replace('/','\\'); - Uri = partUri; - ContentType = contentType; - CompressionLevel = compressionLevel; - } - internal ZipPackage Package { get; set; } - internal CompressionLevel CompressionLevel; - MemoryStream _stream = null; - internal MemoryStream Stream - { - get - { - return _stream; - } - set - { - _stream = value; - } - } - internal override ZipPackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType) - { +internal class ZipPackagePart : ZipPackageRelationshipBase, IDisposable { + internal delegate void SaveHandlerDelegate(StreamWriter streamWriter); - var rel = base.CreateRelationship(targetUri, targetMode, relationshipType); - rel.SourceUri = Uri; - return rel; - } - internal MemoryStream GetStream() - { - return GetStream(FileMode.OpenOrCreate, FileAccess.ReadWrite); - } - internal MemoryStream GetStream(FileMode fileMode) - { - return GetStream(FileMode.Create, FileAccess.ReadWrite); - } - internal MemoryStream GetStream(FileMode fileMode, FileAccess fileAccess) - { - if (_stream == null || fileMode == FileMode.CreateNew || fileMode == FileMode.Create) - { - _stream = new MemoryStream(); - } - else - { - _stream.Seek(0, SeekOrigin.Begin); - } - return _stream; - } + internal ZipPackagePart(ZipPackage package, ZipArchiveEntry entry) { + Package = package; + SaveHandler = null; + Uri = new(package.GetUriKey(entry.FullName), UriKind.Relative); + } - string _contentType = ""; - public string ContentType - { - get - { - return _contentType; - } - internal set - { - if (!string.IsNullOrEmpty(_contentType)) - { - if (Package._contentTypes.ContainsKey(Package.GetUriKey(Uri.OriginalString))) - { - Package._contentTypes.Remove(Package.GetUriKey(Uri.OriginalString)); - Package._contentTypes.Add(Package.GetUriKey(Uri.OriginalString), new ZipPackage.ContentType(value, false, Uri.OriginalString)); - } - } - _contentType = value; - } - } - public Uri Uri { get; private set; } - internal SaveHandlerDelegate SaveHandler - { - get; - set; - } - internal void WriteZip(ZipArchive zipArchive) - { - byte[] b; - if (SaveHandler == null) - { - b = GetStream().ToArray(); - if (b.Length == 0) //Make sure the file isn't empty. DotNetZip streams does not seems to handle zero sized files. - { - return; - } - var zipEntry = zipArchive.CreateEntry(Uri.OriginalString); - using var os = zipEntry.Open(); - os.Write(b); - } - else - { - var zipEntry = zipArchive.CreateEntry(Uri.OriginalString); - using var streamWriter = new StreamWriter(zipEntry.Open()); - SaveHandler(streamWriter); - } + internal ZipPackagePart( + ZipPackage package, + Uri partUri, + string contentType, + CompressionLevel compressionLevel) { + Package = package; + //Entry = new ZipEntry(); + //Entry.FileName = partUri.OriginalString.Replace('/','\\'); + Uri = partUri; + ContentType = contentType; + CompressionLevel = compressionLevel; + } - if (_rels.Count > 0) - { - string f = Uri.OriginalString; - var name = Path.GetFileName(f); - _rels.WriteZip(zipArchive, $"{f.Substring(0, f.Length - name.Length)}_rels/{name}.rels"); - } - b = null; - } + internal ZipPackage Package { get; set; } + internal CompressionLevel CompressionLevel; + private MemoryStream _stream; - public void Dispose() - { - _stream.Close(); - _stream.Dispose(); - } + internal MemoryStream Stream { + get => _stream; + set => _stream = value; + } + + internal override ZipPackageRelationship CreateRelationship( + Uri targetUri, + TargetMode targetMode, + string relationshipType) { + var rel = base.CreateRelationship(targetUri, targetMode, relationshipType); + rel.SourceUri = Uri; + return rel; + } + + internal MemoryStream GetStream() { + return GetStream(FileMode.OpenOrCreate, FileAccess.ReadWrite); + } + + internal MemoryStream GetStream(FileMode fileMode) { + return GetStream(FileMode.Create, FileAccess.ReadWrite); + } + + internal MemoryStream GetStream(FileMode fileMode, FileAccess fileAccess) { + if (_stream == null || fileMode == FileMode.CreateNew || fileMode == FileMode.Create) { + _stream = new(); + } else { + _stream.Seek(0, SeekOrigin.Begin); } + return _stream; + } + + private string _contentType = ""; + + public string ContentType { + get => _contentType; + internal set { + if (!string.IsNullOrEmpty(_contentType)) { + if (Package._contentTypes.ContainsKey(Package.GetUriKey(Uri.OriginalString))) { + Package._contentTypes.Remove(Package.GetUriKey(Uri.OriginalString)); + Package._contentTypes.Add( + Package.GetUriKey(Uri.OriginalString), + new(value, false, Uri.OriginalString)); + } + } + _contentType = value; + } + } + + public Uri Uri { get; private set; } + + internal SaveHandlerDelegate SaveHandler { get; set; } + + internal void WriteZip(ZipArchive zipArchive) { + byte[] b; + if (SaveHandler == null) { + b = GetStream().ToArray(); + if (b.Length + == 0) //Make sure the file isn't empty. DotNetZip streams does not seems to handle zero sized files. + { + return; + } + var zipEntry = zipArchive.CreateEntry(Uri.OriginalString); + using var os = zipEntry.Open(); + os.Write(b); + } else { + var zipEntry = zipArchive.CreateEntry(Uri.OriginalString); + using var streamWriter = new StreamWriter(zipEntry.Open()); + SaveHandler(streamWriter); + } + + if (_rels.Count > 0) { + string f = Uri.OriginalString; + var name = Path.GetFileName(f); + _rels.WriteZip(zipArchive, $"{f.Substring(0, f.Length - name.Length)}_rels/{name}.rels"); + } + b = null; + } + + public void Dispose() { + _stream.Close(); + _stream.Dispose(); + } }
diff --git a/EPPlus/Packaging/ZipPackageRelationship.cs b/EPPlus/Packaging/ZipPackageRelationship.cs index 7bb7a50..15c4539 100644 --- a/EPPlus/Packaging/ZipPackageRelationship.cs +++ b/EPPlus/Packaging/ZipPackageRelationship.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,35 +13,34 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 25-Oct-2012 *******************************************************************************/ + using System; -namespace OfficeOpenXml.Packaging -{ - public class ZipPackageRelationship - { - public Uri TargetUri { get; internal set; } +namespace OfficeOpenXml.Packaging; - public Uri SourceUri { get; internal set; } +public class ZipPackageRelationship { + public Uri TargetUri { get; internal set; } - public string RelationshipType { get; internal set; } + public Uri SourceUri { get; internal set; } - public TargetMode TargetMode { get; internal set; } + public string RelationshipType { get; internal set; } - public string Id { get; internal set; } - } + public TargetMode TargetMode { get; internal set; } + + public string Id { get; internal set; } }
diff --git a/EPPlus/Packaging/ZipPackageRelationshipBase.cs b/EPPlus/Packaging/ZipPackageRelationshipBase.cs index b0bd124..6c0411f 100644 --- a/EPPlus/Packaging/ZipPackageRelationshipBase.cs +++ b/EPPlus/Packaging/ZipPackageRelationshipBase.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,113 +13,113 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 25-Oct-2012 *******************************************************************************/ + using System; using System.IO; using System.Xml; -namespace OfficeOpenXml.Packaging -{ - public abstract class ZipPackageRelationshipBase - { - protected ZipPackageRelationshipCollection _rels = new ZipPackageRelationshipCollection(); - protected internal int maxRId = 1; - internal void DeleteRelationship(string id) - { - _rels.Remove(id); - UpdateMaxRId(id, ref maxRId); - } - protected void UpdateMaxRId(string id, ref int maxRId) - { - if (id.StartsWith("rId")) - { - int num; - if (int.TryParse(id.Substring(3), out num)) - { - if (num == maxRId - 1) - { - maxRId--; - } - } - } - } - internal virtual ZipPackageRelationship CreateRelationship(Uri targetUri, TargetMode targetMode, string relationshipType) - { - var rel = new ZipPackageRelationship(); - rel.TargetUri = targetUri; - rel.TargetMode = targetMode; - rel.RelationshipType = relationshipType; - rel.Id = "rId" + (maxRId++).ToString(); - _rels.Add(rel); - return rel; - } - internal bool RelationshipExists(string id) - { - return _rels.ContainsKey(id); - } - internal ZipPackageRelationshipCollection GetRelationshipsByType(string schema) - { - return _rels.GetRelationshipsByType(schema); - } - internal ZipPackageRelationshipCollection GetRelationships() - { - return _rels; - } - internal ZipPackageRelationship GetRelationship(string id) - { - return _rels[id]; - } - internal void ReadRelation(Stream inputStream, string source) - { - var doc = new XmlDocument(); - XmlHelper.LoadXmlSafe(doc, inputStream); +namespace OfficeOpenXml.Packaging; - foreach (XmlElement c in doc.DocumentElement.ChildNodes) - { - var rel = new ZipPackageRelationship(); - rel.Id = c.GetAttribute("Id"); - rel.RelationshipType = c.GetAttribute("Type"); - rel.TargetMode = c.GetAttribute("TargetMode").Equals("external",StringComparison.InvariantCultureIgnoreCase) ? TargetMode.External : TargetMode.Internal; - try - { - rel.TargetUri = new Uri(c.GetAttribute("Target"), UriKind.RelativeOrAbsolute); - } - catch - { - //The URI is not a valid URI. Encode it to make i valid. - rel.TargetUri = new Uri(Uri.EscapeUriString("Invalid:URI "+c.GetAttribute("Target")), UriKind.RelativeOrAbsolute); - } - if (!string.IsNullOrEmpty(source)) - { - rel.SourceUri = new Uri(source, UriKind.Relative); - } - if (rel.Id.StartsWith("rid", StringComparison.InvariantCultureIgnoreCase)) - { - int id; - if (int.TryParse(rel.Id.Substring(3), out id)) - { - if (id >= maxRId && id < int.MaxValue - 10000) //Not likly to have this high id's but make sure we have space to avoid overflow. - { - maxRId = id + 1; - } - } - } - _rels.Add(rel); - } +public abstract class ZipPackageRelationshipBase { + protected ZipPackageRelationshipCollection _rels = new(); + protected internal int maxRId = 1; + + internal void DeleteRelationship(string id) { + _rels.Remove(id); + UpdateMaxRId(id, ref maxRId); + } + + protected void UpdateMaxRId(string id, ref int maxRId) { + if (id.StartsWith("rId")) { + int num; + if (int.TryParse(id.Substring(3), out num)) { + if (num == maxRId - 1) { + maxRId--; } + } } -} \ No newline at end of file + } + + internal virtual ZipPackageRelationship CreateRelationship( + Uri targetUri, + TargetMode targetMode, + string relationshipType) { + var rel = new ZipPackageRelationship(); + rel.TargetUri = targetUri; + rel.TargetMode = targetMode; + rel.RelationshipType = relationshipType; + rel.Id = "rId" + (maxRId++); + _rels.Add(rel); + return rel; + } + + internal bool RelationshipExists(string id) { + return _rels.ContainsKey(id); + } + + internal ZipPackageRelationshipCollection GetRelationshipsByType(string schema) { + return _rels.GetRelationshipsByType(schema); + } + + internal ZipPackageRelationshipCollection GetRelationships() { + return _rels; + } + + internal ZipPackageRelationship GetRelationship(string id) { + return _rels[id]; + } + + internal void ReadRelation(Stream inputStream, string source) { + var doc = new XmlDocument(); + XmlHelper.LoadXmlSafe(doc, inputStream); + + foreach (XmlElement c in doc.DocumentElement.ChildNodes) { + var rel = new ZipPackageRelationship(); + rel.Id = c.GetAttribute("Id"); + rel.RelationshipType = c.GetAttribute("Type"); + rel.TargetMode = c.GetAttribute("TargetMode") + .Equals("external", StringComparison.InvariantCultureIgnoreCase) + ? TargetMode.External + : TargetMode.Internal; + try { + rel.TargetUri = new(c.GetAttribute("Target"), UriKind.RelativeOrAbsolute); + } catch { + //The URI is not a valid URI. Encode it to make i valid. + rel.TargetUri = new( + Uri.EscapeUriString("Invalid:URI " + c.GetAttribute("Target")), + UriKind.RelativeOrAbsolute); + } + if (!string.IsNullOrEmpty(source)) { + rel.SourceUri = new(source, UriKind.Relative); + } + if (rel.Id.StartsWith("rid", StringComparison.InvariantCultureIgnoreCase)) { + int id; + if (int.TryParse(rel.Id.Substring(3), out id)) { + if (id >= maxRId + && id + < int.MaxValue + - 10000) //Not likly to have this high id's but make sure we have space to avoid overflow. + { + maxRId = id + 1; + } + } + } + _rels.Add(rel); + } + } +}
diff --git a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs b/EPPlus/Packaging/ZipPackageRelationshipCollection.cs index 0820322..dab1030 100644 --- a/EPPlus/Packaging/ZipPackageRelationshipCollection.cs +++ b/EPPlus/Packaging/ZipPackageRelationshipCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,93 +13,85 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 25-Oct-2012 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; using System.IO; using System.IO.Compression; using System.Security; -namespace OfficeOpenXml.Packaging -{ - public class ZipPackageRelationshipCollection : IEnumerable<ZipPackageRelationship> - { - internal protected Dictionary<string, ZipPackageRelationship> _rels = new Dictionary<string, ZipPackageRelationship>(StringComparer.InvariantCultureIgnoreCase); - internal void Add(ZipPackageRelationship item) - { - _rels.Add(item.Id, item); - } - public IEnumerator<ZipPackageRelationship> GetEnumerator() - { - return _rels.Values.GetEnumerator(); - } +namespace OfficeOpenXml.Packaging; - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _rels.Values.GetEnumerator(); - } +public class ZipPackageRelationshipCollection : IEnumerable<ZipPackageRelationship> { + protected internal Dictionary<string, ZipPackageRelationship> _rels = new( + StringComparer.InvariantCultureIgnoreCase); - internal void Remove(string id) - { - _rels.Remove(id); - } - internal bool ContainsKey(string id) - { - return _rels.ContainsKey(id); - } - internal ZipPackageRelationship this[string id] - { - get - { - return _rels[id]; - } - } - internal ZipPackageRelationshipCollection GetRelationshipsByType(string relationshipType) - { - var ret = new ZipPackageRelationshipCollection(); - foreach (var rel in _rels.Values) - { - if (rel.RelationshipType == relationshipType) - { - ret.Add(rel); - } - } - return ret; - } + internal void Add(ZipPackageRelationship item) { + _rels.Add(item.Id, item); + } - internal void WriteZip(ZipArchive zipArchive, string filename) - { - var entry = zipArchive.CreateEntry(filename); - using var writer = new StreamWriter(entry.Open()); - - writer.Write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"); - foreach (var rel in _rels.Values) - { - writer.Write("<Relationship Id=\"{0}\" Type=\"{1}\" Target=\"{2}\"{3}/>", SecurityElement.Escape(rel.Id), rel.RelationshipType, SecurityElement.Escape(rel.TargetUri.OriginalString), rel.TargetMode == TargetMode.External ? " TargetMode=\"External\"" : ""); - } - writer.Write("</Relationships>"); - } + public IEnumerator<ZipPackageRelationship> GetEnumerator() { + return _rels.Values.GetEnumerator(); + } - public int Count - { - get - { - return _rels.Count; - } - } + IEnumerator IEnumerable.GetEnumerator() { + return _rels.Values.GetEnumerator(); + } + + internal void Remove(string id) { + _rels.Remove(id); + } + + internal bool ContainsKey(string id) { + return _rels.ContainsKey(id); + } + + internal ZipPackageRelationship this[string id] => _rels[id]; + + internal ZipPackageRelationshipCollection GetRelationshipsByType(string relationshipType) { + var ret = new ZipPackageRelationshipCollection(); + foreach (var rel in _rels.Values) { + if (rel.RelationshipType == relationshipType) { + ret.Add(rel); + } } + return ret; + } + + internal void WriteZip(ZipArchive zipArchive, string filename) { + var entry = zipArchive.CreateEntry(filename); + using var writer = new StreamWriter(entry.Open()); + + writer.Write( + "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><Relationships xmlns=\"http://schemas.openxmlformats.org/package/2006/relationships\">"); + foreach (var rel in _rels.Values) { + writer.Write( + "<Relationship Id=\"{0}\" Type=\"{1}\" Target=\"{2}\"{3}/>", + SecurityElement.Escape(rel.Id), + rel.RelationshipType, + SecurityElement.Escape(rel.TargetUri.OriginalString), + rel.TargetMode == TargetMode.External ? " TargetMode=\"External\"" : ""); + } + writer.Write("</Relationships>"); + } + + public int Count { + get { return _rels.Count; } + } }
diff --git a/EPPlus/Properties/AssemblyInfo.cs b/EPPlus/Properties/AssemblyInfo.cs index b4b32ad..2fc9137 100644 --- a/EPPlus/Properties/AssemblyInfo.cs +++ b/EPPlus/Properties/AssemblyInfo.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date ******************************************************************************* * Jan Källman Added 10-SEP-2009 @@ -34,19 +34,22 @@ using System.Runtime.InteropServices; using System.Security; -// General Information about an assembly is controlled through the following +// General Information about an assembly is controlled through the following // set of attributes. Change these attribute values to modify the information // associated with an assembly. [assembly: AssemblyTitle("EPPlus 4.0.4")] -[assembly: AssemblyDescription("Allows Excel files(xlsx;xlsm) to be created on the server. See epplus.codeplex.com")] +[assembly: AssemblyDescription( + "Allows Excel files(xlsx;xlsm) to be created on the server. See epplus.codeplex.com")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("EPPlus")] [assembly: AssemblyProduct("EPPlus 4.0.4")] -[assembly: AssemblyCopyright("Copyright 2009- ©Jan Källman. Parts of the Interface comes from ExcelPackage-project")] +[assembly: AssemblyCopyright( + "Copyright 2009- ©Jan Källman. Parts of the Interface comes from ExcelPackage-project")] [assembly: AssemblyTrademark("The GNU Lesser General Public License (LGPL)")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: InternalsVisibleTo("EPPlusTest, PublicKey=00240000048000009400000006020000002400005253413100040000010001001dd11308ec93a6ebcec727e183a8972dc6f95c23ecc34aa04f40cbfc9c17b08b4a0ea5c00dcd203bace44d15a30ce8796e38176ae88e960ceff9cc439ab938738ba0e603e3d155fc298799b391c004fc0eb4393dd254ce25db341eb43303e4c488c9500e126f1288594f0710ec7d642e9c72e76dd860649f1c48249c00e31fba")] +[assembly: InternalsVisibleTo( + "EPPlusTest, PublicKey=00240000048000009400000006020000002400005253413100040000010001001dd11308ec93a6ebcec727e183a8972dc6f95c23ecc34aa04f40cbfc9c17b08b4a0ea5c00dcd203bace44d15a30ce8796e38176ae88e960ceff9cc439ab938738ba0e603e3d155fc298799b391c004fc0eb4393dd254ce25db341eb43303e4c488c9500e126f1288594f0710ec7d642e9c72e76dd860649f1c48249c00e31fba")] // The following GUID is for the ID of the typelib if this project is exposed to COM [assembly: Guid("9dd43b8d-c4fe-4a8b-ad6e-47ef83bbbb01")] @@ -54,12 +57,12 @@ // Version information for an assembly consists of the following four values: // // Major Version -// Minor Version +// Minor Version // Build Number // Revision // -// You can specify all the values or you can default the Revision and Build Numbers +// You can specify all the values or you can default the Revision and Build Numbers // by using the '*' as shown below: [assembly: AssemblyVersion("4.0.4.0")] [assembly: AssemblyFileVersion("4.0.4.0")] -[assembly: AllowPartiallyTrustedCallers] \ No newline at end of file +[assembly: AllowPartiallyTrustedCallers]
diff --git a/EPPlus/RangeCollection.cs b/EPPlus/RangeCollection.cs index 2e3443e..90fbfb9 100644 --- a/EPPlus/RangeCollection.cs +++ b/EPPlus/RangeCollection.cs
@@ -1,24 +1,3 @@ - - - - - - - - - - - - - - - - - - - - - /******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * @@ -34,304 +13,269 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 2010-02-04 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; using System.Collections; -using OfficeOpenXml.Drawing.Vml;namespace OfficeOpenXml -{ - /// <summary> - /// This is the store for all Rows, Columns and Cells. - /// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID ) - /// </summary> - internal class RangeCollection : IEnumerator<IRangeID>, IEnumerable, IDisposable - { - private class IndexItem - { - internal IndexItem(ulong cellId) - { - RangeID = cellId; - } - internal IndexItem(ulong cellId, int listPointer) - { - RangeID = cellId; - ListPointer=listPointer; - } - internal ulong RangeID; - internal int ListPointer; - } - /// <summary> - /// Compares an IndexItem - /// </summary> - internal class Compare : IComparer<IndexItem> - { - #region IComparer<IndexItem> Members - int IComparer<IndexItem>.Compare(IndexItem x, IndexItem y) - { - return x.RangeID < y.RangeID ? -1 : x.RangeID > y.RangeID ? 1 : 0; - } +using System.Collections.Generic; - #endregion - } - IndexItem[] _cellIndex; - List<IRangeID> _cells; - static readonly Compare _comparer=new Compare(); - /// <summary> - /// Creates a new collection - /// </summary> - /// <param name="cells">The Cells. This list must be sorted</param> - internal RangeCollection(List<IRangeID> cells) - { - _cells = cells; - InitSize(_cells); - for (int i = 0; i < _cells.Count; i++) - { - _cellIndex[i] = new IndexItem(cells[i].RangeID, i); - } - } - ~RangeCollection() - { - _cells = null; - _cellIndex = null; - } - /// <summary> - /// Return the item with the RangeID - /// </summary> - /// <param name="RangeID"></param> - /// <returns></returns> - internal IRangeID this[ulong RangeID] - { - get - { - return _cells[_cellIndex[IndexOf(RangeID)].ListPointer]; - } - } - /// <summary> - /// Return specified index from the sorted list - /// </summary> - /// <param name="Index"></param> - /// <returns></returns> - internal IRangeID this[int Index] - { - get - { - return _cells[_cellIndex[Index].ListPointer]; - } - } - internal int Count - { - get - { - return _cells.Count; - } - } - internal void Add(IRangeID cell) - { - var ix = IndexOf(cell.RangeID); - if (ix >= 0) - { - throw (new Exception("Item already exists")); - } - Insert(~ix, cell); - } - internal void Delete(ulong key) - { - var ix = IndexOf(key); - if (ix < 0) - { - throw (new Exception("Key does not exists")); - } - int listPointer = _cellIndex[ix].ListPointer; - Array.Copy(_cellIndex, ix + 1, _cellIndex, ix, _cells.Count - ix - 1); - _cells.RemoveAt(listPointer); +namespace OfficeOpenXml; - //Item is removed subtract one from all items with greater ListPointer - for (int i = 0; i < _cells.Count; i++) - { - if (_cellIndex[i].ListPointer >= listPointer) - { - _cellIndex[i].ListPointer--; - } - - } - } - internal int IndexOf(ulong key) - { - return Array.BinarySearch<IndexItem>(_cellIndex, 0, _cells.Count, new IndexItem(key), _comparer); - } - internal bool ContainsKey(ulong key) - { - return IndexOf(key) < 0 ? false : true; - } - int _size { get; set; } - #region "RangeID manipulation methods" - /// <summary> - /// Insert a number of rows in the collecion but dont update the cell only the index - /// </summary> - /// <param name="rowID"></param> - /// <param name="rows"></param> - /// <returns>Index of first rangeItem</returns> - internal int InsertRowsUpdateIndex(ulong rowID, int rows) - { - int index = IndexOf(rowID); - if (index < 0) index = ~index; //No match found invert to get start cell - ulong rowAdd = (((ulong)rows) << 29); - for (int i = index; i < _cells.Count; i++) - { - _cellIndex[i].RangeID += rowAdd; - } - return index; - } - /// <summary> - /// Insert a number of rows in the collecion - /// </summary> - /// <param name="rowID"></param> - /// <param name="rows"></param> - /// <returns>Index of first rangeItem</returns> - internal int InsertRows(ulong rowID, int rows) - { - int index = IndexOf(rowID); - if (index < 0) index = ~index; //No match found invert to get start cell - ulong rowAdd=(((ulong)rows) << 29); - for (int i = index; i < _cells.Count; i++) - { - _cellIndex[i].RangeID += rowAdd; - _cells[_cellIndex[i].ListPointer].RangeID += rowAdd; - } - return index; - } - /// <summary> - /// Delete rows from the collecion - /// </summary> - /// <param name="rowID"></param> - /// <param name="rows"></param> - /// <param name="updateCells">Update range id's on cells</param> - internal int DeleteRows(ulong rowID, int rows, bool updateCells) - { - ulong rowAdd = (((ulong)rows) << 29); - var index = IndexOf(rowID); - if (index < 0) index = ~index; //No match found invert to get start cell - - if (index >= _cells.Count || _cellIndex[index] == null) return -1; //No row above this row - while (index < _cells.Count && _cellIndex[index].RangeID < rowID + rowAdd) - { - Delete(_cellIndex[index].RangeID); - } - - int updIndex = IndexOf(rowID + rowAdd); - if (updIndex < 0) updIndex = ~updIndex; //No match found invert to get start cell - - for (int i = updIndex; i < _cells.Count; i++) - { - _cellIndex[i].RangeID -= rowAdd; //Change the index - if (updateCells) _cells[_cellIndex[i].ListPointer].RangeID -= rowAdd; //Change the cell/row or column object - } - return index; - } - internal void InsertColumn(ulong ColumnID, int columns) - { - throw (new Exception("Working on it...")); - } - internal void DeleteColumn(ulong ColumnID,int columns) - { - throw (new Exception("Working on it...")); - } - #endregion - #region "Private Methods" - /// <summary> - /// Init the size starting from 128 items. Double the size until the list fits. - /// </summary> - /// <param name="_cells"></param> - private void InitSize(List<IRangeID> _cells) - { - _size = 128; - while (_cells.Count > _size) _size <<= 1; - _cellIndex = new IndexItem[_size]; - } - /// <summary> - /// Check the size and double the size if out of bound - /// </summary> - private void CheckSize() - { - if (_cells.Count >= _size) - { - _size <<= 1; - Array.Resize(ref _cellIndex, _size); - } - } - private void Insert(int ix, IRangeID cell) - { - CheckSize(); - Array.Copy(_cellIndex, ix, _cellIndex, ix + 1, _cells.Count - ix); - _cellIndex[ix] = new IndexItem(cell.RangeID, _cells.Count); - _cells.Add(cell); - } - #endregion - - #region IEnumerator<IRangeID> Members - - IRangeID IEnumerator<IRangeID>.Current - { - get { throw new NotImplementedException(); } - } - - #endregion - - #region IDisposable for the enumerator Members - - void IDisposable.Dispose() - { - _ix = -1; - } - - #endregion - - #region IEnumerator Members - int _ix = -1; - object IEnumerator.Current - { - get - { - return _cells[_cellIndex[_ix].ListPointer]; - } - } - - bool IEnumerator.MoveNext() - { - _ix++; - return _ix < _cells.Count; - } - - void IEnumerator.Reset() - { - _ix = -1; - } - - #endregion - - #region IEnumerable Members - - IEnumerator IEnumerable.GetEnumerator() - { - return this.MemberwiseClone() as IEnumerator; - } - - #endregion +/// <summary> +/// This is the store for all Rows, Columns and Cells. +/// It is a Dictionary implementation that allows you to change the Key (the RowID, ColumnID or CellID ) +/// </summary> +internal class RangeCollection : IEnumerator<IRangeId>, IEnumerable, IDisposable { + private class IndexItem { + internal IndexItem(ulong cellId) { + RangeID = cellId; } + + internal IndexItem(ulong cellId, int listPointer) { + RangeID = cellId; + ListPointer = listPointer; + } + + internal ulong RangeID; + internal int ListPointer; + } + + /// <summary> + /// Compares an IndexItem + /// </summary> + internal class Compare : IComparer<IndexItem> { + int IComparer<IndexItem>.Compare(IndexItem x, IndexItem y) { + return x.RangeID < y.RangeID + ? -1 + : x.RangeID > y.RangeID + ? 1 + : 0; + } + } + + private IndexItem[] _cellIndex; + private List<IRangeId> _cells; + private static readonly Compare _comparer = new(); + + /// <summary> + /// Creates a new collection + /// </summary> + /// <param name="cells">The Cells. This list must be sorted</param> + internal RangeCollection(List<IRangeId> cells) { + _cells = cells; + InitSize(_cells); + for (int i = 0; i < _cells.Count; i++) { + _cellIndex[i] = new(cells[i].RangeID, i); + } + } + + ~RangeCollection() { + _cells = null; + _cellIndex = null; + } + + /// <summary> + /// Return the item with the RangeID + /// </summary> + /// <param name="rangeId"></param> + /// <returns></returns> + internal IRangeId this[ulong rangeId] => _cells[_cellIndex[IndexOf(rangeId)].ListPointer]; + + /// <summary> + /// Return specified index from the sorted list + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + internal IRangeId this[int index] { + get { return _cells[_cellIndex[index].ListPointer]; } + } + + internal int Count { + get { return _cells.Count; } + } + + internal void Add(IRangeId cell) { + var ix = IndexOf(cell.RangeID); + if (ix >= 0) { + throw (new("Item already exists")); + } + Insert(~ix, cell); + } + + internal void Delete(ulong key) { + var ix = IndexOf(key); + if (ix < 0) { + throw (new("Key does not exists")); + } + int listPointer = _cellIndex[ix].ListPointer; + Array.Copy(_cellIndex, ix + 1, _cellIndex, ix, _cells.Count - ix - 1); + _cells.RemoveAt(listPointer); + + //Item is removed subtract one from all items with greater ListPointer + for (int i = 0; i < _cells.Count; i++) { + if (_cellIndex[i].ListPointer >= listPointer) { + _cellIndex[i].ListPointer--; + } + } + } + + internal int IndexOf(ulong key) { + return Array.BinarySearch(_cellIndex, 0, _cells.Count, new(key), _comparer); + } + + internal bool ContainsKey(ulong key) { + return IndexOf(key) < 0 ? false : true; + } + + private int _size { get; set; } + + /// <summary> + /// Insert a number of rows in the collecion but dont update the cell only the index + /// </summary> + /// <param name="rowId"></param> + /// <param name="rows"></param> + /// <returns>Index of first rangeItem</returns> + internal int InsertRowsUpdateIndex(ulong rowId, int rows) { + int index = IndexOf(rowId); + if (index < 0) { + index = ~index; //No match found invert to get start cell + } + ulong rowAdd = (((ulong)rows) << 29); + for (int i = index; i < _cells.Count; i++) { + _cellIndex[i].RangeID += rowAdd; + } + return index; + } + + /// <summary> + /// Insert a number of rows in the collecion + /// </summary> + /// <param name="rowId"></param> + /// <param name="rows"></param> + /// <returns>Index of first rangeItem</returns> + internal int InsertRows(ulong rowId, int rows) { + int index = IndexOf(rowId); + if (index < 0) { + index = ~index; //No match found invert to get start cell + } + ulong rowAdd = (((ulong)rows) << 29); + for (int i = index; i < _cells.Count; i++) { + _cellIndex[i].RangeID += rowAdd; + _cells[_cellIndex[i].ListPointer].RangeID += rowAdd; + } + return index; + } + + /// <summary> + /// Delete rows from the collecion + /// </summary> + /// <param name="rowId"></param> + /// <param name="rows"></param> + /// <param name="updateCells">Update range id's on cells</param> + internal int DeleteRows(ulong rowId, int rows, bool updateCells) { + ulong rowAdd = (((ulong)rows) << 29); + var index = IndexOf(rowId); + if (index < 0) { + index = ~index; //No match found invert to get start cell + } + + if (index >= _cells.Count || _cellIndex[index] == null) { + return -1; //No row above this row + } + while (index < _cells.Count && _cellIndex[index].RangeID < rowId + rowAdd) { + Delete(_cellIndex[index].RangeID); + } + + int updIndex = IndexOf(rowId + rowAdd); + if (updIndex < 0) { + updIndex = ~updIndex; //No match found invert to get start cell + } + + for (int i = updIndex; i < _cells.Count; i++) { + _cellIndex[i].RangeID -= rowAdd; //Change the index + if (updateCells) { + _cells[_cellIndex[i].ListPointer].RangeID -= rowAdd; //Change the cell/row or column object + } + } + return index; + } + + internal void InsertColumn(ulong columnId, int columns) { + throw (new("Working on it...")); + } + + internal void DeleteColumn(ulong columnId, int columns) { + throw (new("Working on it...")); + } + + /// <summary> + /// Init the size starting from 128 items. Double the size until the list fits. + /// </summary> + /// <param name="_cells"></param> + private void InitSize(List<IRangeId> cells) { + _size = 128; + while (cells.Count > _size) { + _size <<= 1; + } + _cellIndex = new IndexItem[_size]; + } + + /// <summary> + /// Check the size and double the size if out of bound + /// </summary> + private void CheckSize() { + if (_cells.Count >= _size) { + _size <<= 1; + Array.Resize(ref _cellIndex, _size); + } + } + + private void Insert(int ix, IRangeId cell) { + CheckSize(); + Array.Copy(_cellIndex, ix, _cellIndex, ix + 1, _cells.Count - ix); + _cellIndex[ix] = new(cell.RangeID, _cells.Count); + _cells.Add(cell); + } + + IRangeId IEnumerator<IRangeId>.Current { + get { throw new NotImplementedException(); } + } + + void IDisposable.Dispose() { + _ix = -1; + } + + private int _ix = -1; + + object IEnumerator.Current { + get { return _cells[_cellIndex[_ix].ListPointer]; } + } + + bool IEnumerator.MoveNext() { + _ix++; + return _ix < _cells.Count; + } + + void IEnumerator.Reset() { + _ix = -1; + } + + IEnumerator IEnumerable.GetEnumerator() { + return MemberwiseClone() as IEnumerator; + } }
diff --git a/EPPlus/Style/Dxf/DxfStyleBase.cs b/EPPlus/Style/Dxf/DxfStyleBase.cs index bbaa6bd..7bbbcd0 100644 --- a/EPPlus/Style/Dxf/DxfStyleBase.cs +++ b/EPPlus/Style/Dxf/DxfStyleBase.cs
@@ -1,98 +1,79 @@ -using System; -using System.Collections.Generic; +using System; using System.Globalization; -using System.Linq; -using System.Text; -using System.Xml; -namespace OfficeOpenXml.Style.Dxf -{ - public abstract class DxfStyleBase<T> - { - protected ExcelStyles _styles; - internal DxfStyleBase(ExcelStyles styles) - { - _styles = styles; - AllowChange = false; //Don't touch this value in the styles.xml (by default). When Dxfs is fully implemented this can be removed. - } - protected internal abstract string Id { get; } - protected internal abstract bool HasValue{get;} - protected internal abstract void CreateNodes(XmlHelper helper, string path); - protected internal abstract T Clone(); - protected void SetValueColor(XmlHelper helper,string path, ExcelDxfColor color) - { - if (color != null && color.HasValue) - { - if (color.Color != null) - { - SetValue(helper, path + "/@rgb", color.Color.Value.ToArgb().ToString("x")); - } - else if (color.Auto != null) - { - SetValueBool(helper, path + "/@auto", color.Auto); - } - else if (color.Theme != null) - { - SetValue(helper, path + "/@theme", color.Theme); - } - else if (color.Index != null) - { - SetValue(helper, path + "/@indexed", color.Index); - } - if (color.Tint != null) - { - SetValue(helper, path + "/@tint", color.Tint); - } - } - } - /// <summary> - /// Same as SetValue but will set first char to lower case. - /// </summary> - /// <param name="helper"></param> - /// <param name="path"></param> - /// <param name="v"></param> - protected void SetValueEnum(XmlHelper helper, string path, Enum v) - { - if (v == null) - { - helper.DeleteNode(path); - } - else - { - var s = v.ToString(); - s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1); - helper.SetXmlNodeString(path, s); - } - } - protected void SetValue(XmlHelper helper, string path, object v) - { - if (v == null) - { - helper.DeleteNode(path); - } - else - { - helper.SetXmlNodeString(path, v.ToString()); - } - } - protected void SetValueBool(XmlHelper helper, string path, bool? v) - { - if (v == null) - { - helper.DeleteNode(path); - } - else - { - helper.SetXmlNodeBool(path, (bool)v); - } - } - protected internal string GetAsString(object v) - { - return (v ?? "").ToString(); - } - /// <summary> - /// Is this value allowed to be changed? - /// </summary> - protected internal bool AllowChange { get; set; } +namespace OfficeOpenXml.Style.Dxf; + +public abstract class DxfStyleBase<T> { + protected ExcelStyles _styles; + + internal DxfStyleBase(ExcelStyles styles) { + _styles = styles; + AllowChange = false; //Don't touch this value in the styles.xml (by default). When Dxfs is fully implemented this can be removed. + } + + protected internal abstract string Id { get; } + + protected internal abstract bool HasValue { get; } + + protected internal abstract void CreateNodes(XmlHelper helper, string path); + + protected internal abstract T Clone(); + + protected void SetValueColor(XmlHelper helper, string path, ExcelDxfColor color) { + if (color != null && color.HasValue) { + if (color.Color != null) { + SetValue(helper, path + "/@rgb", color.Color.Value.ToArgb().ToString("x")); + } else if (color.Auto != null) { + SetValueBool(helper, path + "/@auto", color.Auto); + } else if (color.Theme != null) { + SetValue(helper, path + "/@theme", color.Theme); + } else if (color.Index != null) { + SetValue(helper, path + "/@indexed", color.Index); + } + if (color.Tint != null) { + SetValue(helper, path + "/@tint", color.Tint); + } } + } + + /// <summary> + /// Same as SetValue but will set first char to lower case. + /// </summary> + /// <param name="helper"></param> + /// <param name="path"></param> + /// <param name="v"></param> + protected void SetValueEnum(XmlHelper helper, string path, Enum v) { + if (v == null) { + helper.DeleteNode(path); + } else { + var s = v.ToString(); + s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1); + helper.SetXmlNodeString(path, s); + } + } + + protected void SetValue(XmlHelper helper, string path, object v) { + if (v == null) { + helper.DeleteNode(path); + } else { + helper.SetXmlNodeString(path, v.ToString()); + } + } + + protected void SetValueBool(XmlHelper helper, string path, bool? v) { + if (v == null) { + helper.DeleteNode(path); + } else { + helper.SetXmlNodeBool(path, (bool)v); + } + } + + protected internal string GetAsString(object v) { + return (v ?? "").ToString(); + } + + /// <summary> + /// Is this value allowed to be changed? + /// </summary> + protected internal bool AllowChange { get; set; } }
diff --git a/EPPlus/Style/Dxf/ExcelDxfBorder.cs b/EPPlus/Style/Dxf/ExcelDxfBorder.cs index b3fd096..12bcc84 100644 --- a/EPPlus/Style/Dxf/ExcelDxfBorder.cs +++ b/EPPlus/Style/Dxf/ExcelDxfBorder.cs
@@ -1,106 +1,81 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; +namespace OfficeOpenXml.Style.Dxf; -namespace OfficeOpenXml.Style.Dxf -{ - public class ExcelDxfBorderBase : DxfStyleBase<ExcelDxfBorderBase> - { - internal ExcelDxfBorderBase(ExcelStyles styles) - : base(styles) - { - Left=new ExcelDxfBorderItem(_styles); - Right = new ExcelDxfBorderItem(_styles); - Top = new ExcelDxfBorderItem(_styles); - Bottom = new ExcelDxfBorderItem(_styles); - } - /// <summary> - /// Left border style - /// </summary> - public ExcelDxfBorderItem Left - { - get; - internal set; - } - /// <summary> - /// Right border style - /// </summary> - public ExcelDxfBorderItem Right - { - get; - internal set; - } - /// <summary> - /// Top border style - /// </summary> - public ExcelDxfBorderItem Top - { - get; - internal set; - } - /// <summary> - /// Bottom border style - /// </summary> - public ExcelDxfBorderItem Bottom - { - get; - internal set; - } - ///// <summary> - ///// Diagonal border style - ///// </summary> - //public ExcelDxfBorderItem Diagonal - //{ - // get; - // private set; - //} - ///// <summary> - ///// A diagonal from the bottom left to top right of the cell - ///// </summary> - //public bool DiagonalUp - //{ - // get; - // set; - //} - ///// <summary> - ///// A diagonal from the top left to bottom right of the cell - ///// </summary> - //public bool DiagonalDown - //{ - // get; - // set; - //} +public class ExcelDxfBorderBase : DxfStyleBase<ExcelDxfBorderBase> { + internal ExcelDxfBorderBase(ExcelStyles styles) + : base(styles) { + Left = new(_styles); + Right = new(_styles); + Top = new(_styles); + Bottom = new(_styles); + } - protected internal override string Id - { - get - { - return Top.Id + Bottom.Id + Left.Id + Right.Id/* + Diagonal.Id + GetAsString(DiagonalUp) + GetAsString(DiagonalDown)*/; - } - } + /// <summary> + /// Left border style + /// </summary> + public ExcelDxfBorderItem Left { get; internal set; } - protected internal override void CreateNodes(XmlHelper helper, string path) - { - Left.CreateNodes(helper, path + "/d:left"); - Right.CreateNodes(helper, path + "/d:right"); - Top.CreateNodes(helper, path + "/d:top"); - Bottom.CreateNodes(helper, path + "/d:bottom"); - } - protected internal override bool HasValue - { - get - { - return Left.HasValue || - Right.HasValue || - Top.HasValue || - Bottom.HasValue; - } - } - protected internal override ExcelDxfBorderBase Clone() - { - return new ExcelDxfBorderBase(_styles) { Bottom = Bottom.Clone(), Top=Top.Clone(), Left=Left.Clone(), Right=Right.Clone() }; - } - } + /// <summary> + /// Right border style + /// </summary> + public ExcelDxfBorderItem Right { get; internal set; } + + /// <summary> + /// Top border style + /// </summary> + public ExcelDxfBorderItem Top { get; internal set; } + + /// <summary> + /// Bottom border style + /// </summary> + public ExcelDxfBorderItem Bottom { get; internal set; } + + ///// <summary> + ///// Diagonal border style + ///// </summary> + //public ExcelDxfBorderItem Diagonal + //{ + // get; + // private set; + //} + ///// <summary> + ///// A diagonal from the bottom left to top right of the cell + ///// </summary> + //public bool DiagonalUp + //{ + // get; + // set; + //} + ///// <summary> + ///// A diagonal from the top left to bottom right of the cell + ///// </summary> + //public bool DiagonalDown + //{ + // get; + // set; + //} + + protected internal override string Id => + Top.Id + + Bottom.Id + + Left.Id + + Right.Id /* + Diagonal.Id + GetAsString(DiagonalUp) + GetAsString(DiagonalDown)*/; + + protected internal override void CreateNodes(XmlHelper helper, string path) { + Left.CreateNodes(helper, path + "/d:left"); + Right.CreateNodes(helper, path + "/d:right"); + Top.CreateNodes(helper, path + "/d:top"); + Bottom.CreateNodes(helper, path + "/d:bottom"); + } + + protected internal override bool HasValue => + Left.HasValue || Right.HasValue || Top.HasValue || Bottom.HasValue; + + protected internal override ExcelDxfBorderBase Clone() { + return new(_styles) { + Bottom = Bottom.Clone(), + Top = Top.Clone(), + Left = Left.Clone(), + Right = Right.Clone(), + }; + } }
diff --git a/EPPlus/Style/Dxf/ExcelDxfBorderItem.cs b/EPPlus/Style/Dxf/ExcelDxfBorderItem.cs index 9223bea..f068605 100644 --- a/EPPlus/Style/Dxf/ExcelDxfBorderItem.cs +++ b/EPPlus/Style/Dxf/ExcelDxfBorderItem.cs
@@ -1,44 +1,29 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; +namespace OfficeOpenXml.Style.Dxf; -namespace OfficeOpenXml.Style.Dxf -{ - public class ExcelDxfBorderItem : DxfStyleBase<ExcelDxfBorderItem> - { - internal ExcelDxfBorderItem(ExcelStyles styles) : - base(styles) - { - Color=new ExcelDxfColor(styles); - } - public ExcelBorderStyle? Style { get; set;} - public ExcelDxfColor Color { get; internal set; } +public class ExcelDxfBorderItem : DxfStyleBase<ExcelDxfBorderItem> { + internal ExcelDxfBorderItem(ExcelStyles styles) + : base(styles) { + Color = new(styles); + } - protected internal override string Id - { - get - { - return GetAsString(Style) + "|" + (Color == null ? "" : Color.Id); - } - } + public ExcelBorderStyle? Style { get; set; } - protected internal override void CreateNodes(XmlHelper helper, string path) - { - SetValueEnum(helper, path + "/@style", Style); - SetValueColor(helper, path + "/d:color", Color); - } - protected internal override bool HasValue - { - get - { - return Style != null || Color.HasValue; - } - } - protected internal override ExcelDxfBorderItem Clone() - { - return new ExcelDxfBorderItem(_styles) { Style = Style, Color = Color }; - } - } + public ExcelDxfColor Color { get; internal set; } + + protected internal override string Id => + GetAsString(Style) + "|" + (Color == null ? "" : Color.Id); + + protected internal override void CreateNodes(XmlHelper helper, string path) { + SetValueEnum(helper, path + "/@style", Style); + SetValueColor(helper, path + "/d:color", Color); + } + + protected internal override bool HasValue => Style != null || Color.HasValue; + + protected internal override ExcelDxfBorderItem Clone() { + return new(_styles) { + Style = Style, + Color = Color, + }; + } }
diff --git a/EPPlus/Style/Dxf/ExcelDxfColor.cs b/EPPlus/Style/Dxf/ExcelDxfColor.cs index 0ad7ee8..4e6c4f9 100644 --- a/EPPlus/Style/Dxf/ExcelDxfColor.cs +++ b/EPPlus/Style/Dxf/ExcelDxfColor.cs
@@ -1,46 +1,47 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; using System.Drawing; -using System.Xml; -namespace OfficeOpenXml.Style.Dxf -{ - public class ExcelDxfColor : DxfStyleBase<ExcelDxfColor> +namespace OfficeOpenXml.Style.Dxf; - { - public ExcelDxfColor(ExcelStyles styles) : base(styles) - { +public class ExcelDxfColor : DxfStyleBase<ExcelDxfColor> { + public ExcelDxfColor(ExcelStyles styles) + : base(styles) {} - } - public int? Theme { get; set; } - public int? Index { get; set; } - public bool? Auto { get; set; } - public double? Tint { get; set; } - public Color? Color { get; set; } - protected internal override string Id - { - get { return GetAsString(Theme) + "|" + GetAsString(Index) + "|" + GetAsString(Auto) + "|" + GetAsString(Tint) + "|" + GetAsString(Color==null ? "" : ((Color)Color.Value).ToArgb().ToString("x")); } - } - protected internal override ExcelDxfColor Clone() - { - return new ExcelDxfColor(_styles) { Theme = Theme, Index = Index, Color = Color, Auto = Auto, Tint = Tint }; - } - protected internal override bool HasValue - { - get - { - return Theme != null || - Index != null || - Auto != null || - Tint != null || - Color != null; - } - } - protected internal override void CreateNodes(XmlHelper helper, string path) - { - throw new NotImplementedException(); - } - } + public int? Theme { get; set; } + + public int? Index { get; set; } + + public bool? Auto { get; set; } + + public double? Tint { get; set; } + + public Color? Color { get; set; } + + protected internal override string Id => + GetAsString(Theme) + + "|" + + GetAsString(Index) + + "|" + + GetAsString(Auto) + + "|" + + GetAsString(Tint) + + "|" + + GetAsString(Color == null ? "" : Color.Value.ToArgb().ToString("x")); + + protected internal override ExcelDxfColor Clone() { + return new(_styles) { + Theme = Theme, + Index = Index, + Color = Color, + Auto = Auto, + Tint = Tint, + }; + } + + protected internal override bool HasValue => + Theme != null || Index != null || Auto != null || Tint != null || Color != null; + + protected internal override void CreateNodes(XmlHelper helper, string path) { + throw new NotImplementedException(); + } }
diff --git a/EPPlus/Style/Dxf/ExcelDxfFill.cs b/EPPlus/Style/Dxf/ExcelDxfFill.cs index 26a8c10..f4bf1d3 100644 --- a/EPPlus/Style/Dxf/ExcelDxfFill.cs +++ b/EPPlus/Style/Dxf/ExcelDxfFill.cs
@@ -1,57 +1,46 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; -using System.Xml; +namespace OfficeOpenXml.Style.Dxf; -namespace OfficeOpenXml.Style.Dxf -{ - public class ExcelDxfFill : DxfStyleBase<ExcelDxfFill> - { - public ExcelDxfFill(ExcelStyles styles) - : base(styles) - { - PatternColor = new ExcelDxfColor(styles); - BackgroundColor = new ExcelDxfColor(styles); - } - public ExcelFillStyle? PatternType { get; set; } - /// <summary> - /// The color of the pattern - /// </summary> - public ExcelDxfColor PatternColor { get; internal set; } - /// <summary> - /// The background color - /// </summary> - public ExcelDxfColor BackgroundColor { get; internal set; } +public class ExcelDxfFill : DxfStyleBase<ExcelDxfFill> { + public ExcelDxfFill(ExcelStyles styles) + : base(styles) { + PatternColor = new(styles); + BackgroundColor = new(styles); + } - protected internal override string Id - { - get - { - return GetAsString(PatternType) + "|" + (PatternColor == null ? "" : PatternColor.Id) + "|" + (BackgroundColor == null ? "" : BackgroundColor.Id); - } - } - protected internal override void CreateNodes(XmlHelper helper, string path) - { - helper.CreateNode(path); - SetValueEnum(helper, path + "/d:patternFill/@patternType", PatternType); - SetValueColor(helper, path + "/d:patternFill/d:fgColor", PatternColor); - SetValueColor(helper, path + "/d:patternFill/d:bgColor", BackgroundColor); - } + public ExcelFillStyle? PatternType { get; set; } - protected internal override bool HasValue - { - get - { - return PatternType != null || - PatternColor.HasValue || - BackgroundColor.HasValue; - } - } - protected internal override ExcelDxfFill Clone() - { - return new ExcelDxfFill(_styles) {PatternType=PatternType, PatternColor=PatternColor.Clone(), BackgroundColor=BackgroundColor.Clone()}; - } - } + /// <summary> + /// The color of the pattern + /// </summary> + public ExcelDxfColor PatternColor { get; internal set; } + + /// <summary> + /// The background color + /// </summary> + public ExcelDxfColor BackgroundColor { get; internal set; } + + protected internal override string Id => + GetAsString(PatternType) + + "|" + + (PatternColor == null ? "" : PatternColor.Id) + + "|" + + (BackgroundColor == null ? "" : BackgroundColor.Id); + + protected internal override void CreateNodes(XmlHelper helper, string path) { + helper.CreateNode(path); + SetValueEnum(helper, path + "/d:patternFill/@patternType", PatternType); + SetValueColor(helper, path + "/d:patternFill/d:fgColor", PatternColor); + SetValueColor(helper, path + "/d:patternFill/d:bgColor", BackgroundColor); + } + + protected internal override bool HasValue => + PatternType != null || PatternColor.HasValue || BackgroundColor.HasValue; + + protected internal override ExcelDxfFill Clone() { + return new(_styles) { + PatternType = PatternType, + PatternColor = PatternColor.Clone(), + BackgroundColor = BackgroundColor.Clone(), + }; + } }
diff --git a/EPPlus/Style/Dxf/ExcelDxfFontBase.cs b/EPPlus/Style/Dxf/ExcelDxfFontBase.cs index c326f98..aae7d61 100644 --- a/EPPlus/Style/Dxf/ExcelDxfFontBase.cs +++ b/EPPlus/Style/Dxf/ExcelDxfFontBase.cs
@@ -1,85 +1,72 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Drawing; -using System.Xml; +namespace OfficeOpenXml.Style.Dxf; -namespace OfficeOpenXml.Style.Dxf -{ - public class ExcelDxfFontBase : DxfStyleBase<ExcelDxfFontBase> - { - public ExcelDxfFontBase(ExcelStyles styles) - : base(styles) - { - Color = new ExcelDxfColor(styles); - } - /// <summary> - /// Font bold - /// </summary> - public bool? Bold - { - get; - set; - } - /// <summary> - /// Font Italic - /// </summary> - public bool? Italic - { - get; - set; - } - /// <summary> - /// Font-Strikeout - /// </summary> - public bool? Strike { get; set; } - //public float? Size { get; set; } - public ExcelDxfColor Color { get; set; } - //public string Name { get; set; } - //public int? Family { get; set; } - ///// <summary> - ///// Font-Vertical Align - ///// </summary> - //public ExcelVerticalAlignmentFont? VerticalAlign - //{ - // get; - // set; - //} +public class ExcelDxfFontBase : DxfStyleBase<ExcelDxfFontBase> { + public ExcelDxfFontBase(ExcelStyles styles) + : base(styles) { + Color = new(styles); + } - public ExcelUnderLineType? Underline { get; set; } + /// <summary> + /// Font bold + /// </summary> + public bool? Bold { get; set; } - protected internal override string Id - { - get - { - return GetAsString(Bold) + "|" + GetAsString(Italic) + "|" + GetAsString(Strike) + "|" + (Color ==null ? "" : Color.Id) + "|" /*+ GetAsString(VerticalAlign) + "|"*/ + GetAsString(Underline); - } - } + /// <summary> + /// Font Italic + /// </summary> + public bool? Italic { get; set; } - protected internal override void CreateNodes(XmlHelper helper, string path) - { - helper.CreateNode(path); - SetValueBool(helper, path + "/d:b/@val", Bold); - SetValueBool(helper, path + "/d:i/@val", Italic); - SetValueBool(helper, path + "/d:strike", Strike); - SetValue(helper, path + "/d:u/@val", Underline); - SetValueColor(helper, path + "/d:color", Color); - } - protected internal override bool HasValue - { - get - { - return Bold != null || - Italic != null || - Strike != null || - Underline != null || - Color.HasValue; - } - } - protected internal override ExcelDxfFontBase Clone() - { - return new ExcelDxfFontBase(_styles) { Bold = Bold, Color = Color.Clone(), Italic = Italic, Strike = Strike, Underline = Underline }; - } - } + /// <summary> + /// Font-Strikeout + /// </summary> + public bool? Strike { get; set; } + + //public float? Size { get; set; } + public ExcelDxfColor Color { get; set; } + + //public string Name { get; set; } + //public int? Family { get; set; } + ///// <summary> + ///// Font-Vertical Align + ///// </summary> + //public ExcelVerticalAlignmentFont? VerticalAlign + //{ + // get; + // set; + //} + + public ExcelUnderLineType? Underline { get; set; } + + protected internal override string Id => + GetAsString(Bold) + + "|" + + GetAsString(Italic) + + "|" + + GetAsString(Strike) + + "|" + + (Color == null ? "" : Color.Id) + + "|" /*+ GetAsString(VerticalAlign) + "|"*/ + + GetAsString(Underline); + + protected internal override void CreateNodes(XmlHelper helper, string path) { + helper.CreateNode(path); + SetValueBool(helper, path + "/d:b/@val", Bold); + SetValueBool(helper, path + "/d:i/@val", Italic); + SetValueBool(helper, path + "/d:strike", Strike); + SetValue(helper, path + "/d:u/@val", Underline); + SetValueColor(helper, path + "/d:color", Color); + } + + protected internal override bool HasValue => + Bold != null || Italic != null || Strike != null || Underline != null || Color.HasValue; + + protected internal override ExcelDxfFontBase Clone() { + return new(_styles) { + Bold = Bold, + Color = Color.Clone(), + Italic = Italic, + Strike = Strike, + Underline = Underline, + }; + } }
diff --git a/EPPlus/Style/Dxf/ExcelDxfNumberFormat.cs b/EPPlus/Style/Dxf/ExcelDxfNumberFormat.cs index 1d6ffd0..e00114c 100644 --- a/EPPlus/Style/Dxf/ExcelDxfNumberFormat.cs +++ b/EPPlus/Style/Dxf/ExcelDxfNumberFormat.cs
@@ -1,105 +1,77 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; +namespace OfficeOpenXml.Style.Dxf; -namespace OfficeOpenXml.Style.Dxf -{ - public class ExcelDxfNumberFormat : DxfStyleBase<ExcelDxfNumberFormat> - { - public ExcelDxfNumberFormat(ExcelStyles styles) : base(styles) - { +public class ExcelDxfNumberFormat : DxfStyleBase<ExcelDxfNumberFormat> { + public ExcelDxfNumberFormat(ExcelStyles styles) + : base(styles) {} - } - int _numFmtID=int.MinValue; - /// <summary> - /// Id for number format - /// - /// Build in ID's - /// - /// 0 General - /// 1 0 - /// 2 0.00 - /// 3 #,##0 - /// 4 #,##0.00 - /// 9 0% - /// 10 0.00% - /// 11 0.00E+00 - /// 12 # ?/? - /// 13 # ??/?? - /// 14 mm-dd-yy - /// 15 d-mmm-yy - /// 16 d-mmm - /// 17 mmm-yy - /// 18 h:mm AM/PM - /// 19 h:mm:ss AM/PM - /// 20 h:mm - /// 21 h:mm:ss - /// 22 m/d/yy h:mm - /// 37 #,##0 ;(#,##0) - /// 38 #,##0 ;[Red](#,##0) - /// 39 #,##0.00;(#,##0.00) - /// 40 #,##0.00;[Red](#,##0.00) - /// 45 mm:ss - /// 46 [h]:mm:ss - /// 47 mmss.0 - /// 48 ##0.0E+0 - /// 49 @ - /// </summary> - public int NumFmtID - { - get - { - return _numFmtID; - } - internal set - { - _numFmtID = value; - } - } - string _format=""; - public string Format - { - get - { - return _format; - } - set - { - _format = value; - NumFmtID = ExcelNumberFormat.GetFromBuildIdFromFormat(value); - } - } + private int _numFmtID = int.MinValue; - protected internal override string Id - { - get - { - return Format; - } - } + /// <summary> + /// Id for number format + /// + /// Build in ID's + /// + /// 0 General + /// 1 0 + /// 2 0.00 + /// 3 #,##0 + /// 4 #,##0.00 + /// 9 0% + /// 10 0.00% + /// 11 0.00E+00 + /// 12 # ?/? + /// 13 # ??/?? + /// 14 mm-dd-yy + /// 15 d-mmm-yy + /// 16 d-mmm + /// 17 mmm-yy + /// 18 h:mm AM/PM + /// 19 h:mm:ss AM/PM + /// 20 h:mm + /// 21 h:mm:ss + /// 22 m/d/yy h:mm + /// 37 #,##0 ;(#,##0) + /// 38 #,##0 ;[Red](#,##0) + /// 39 #,##0.00;(#,##0.00) + /// 40 #,##0.00;[Red](#,##0.00) + /// 45 mm:ss + /// 46 [h]:mm:ss + /// 47 mmss.0 + /// 48 ##0.0E+0 + /// 49 @ + /// </summary> + public int NumFmtID { + get => _numFmtID; + internal set => _numFmtID = value; + } - protected internal override void CreateNodes(XmlHelper helper, string path) - { - if (NumFmtID < 0 && !string.IsNullOrEmpty(Format)) - { - NumFmtID = _styles._nextDfxNumFmtID++; - } - helper.CreateNode(path); - SetValue(helper, path + "/@numFmtId", NumFmtID); - SetValue(helper, path + "/@formatCode", Format); - } - protected internal override bool HasValue - { - get - { - return !string.IsNullOrEmpty(Format); - } - } - protected internal override ExcelDxfNumberFormat Clone() - { - return new ExcelDxfNumberFormat(_styles) { NumFmtID = NumFmtID, Format = Format }; - } + private string _format = ""; + + public string Format { + get => _format; + set { + _format = value; + NumFmtID = ExcelNumberFormat.GetFromBuildIdFromFormat(value); } + } + + protected internal override string Id => Format; + + protected internal override void CreateNodes(XmlHelper helper, string path) { + if (NumFmtID < 0 && !string.IsNullOrEmpty(Format)) { + NumFmtID = _styles._nextDfxNumFmtID++; + } + helper.CreateNode(path); + SetValue(helper, path + "/@numFmtId", NumFmtID); + SetValue(helper, path + "/@formatCode", Format); + } + + protected internal override bool HasValue => !string.IsNullOrEmpty(Format); + + protected internal override ExcelDxfNumberFormat Clone() { + return new(_styles) { + NumFmtID = NumFmtID, + Format = Format, + }; + } }
diff --git a/EPPlus/Style/Dxf/ExcelDxfStyle.cs b/EPPlus/Style/Dxf/ExcelDxfStyle.cs index c2143e8..4cb8bba 100644 --- a/EPPlus/Style/Dxf/ExcelDxfStyle.cs +++ b/EPPlus/Style/Dxf/ExcelDxfStyle.cs
@@ -1,153 +1,155 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using System.Xml; +using System; using System.Drawing; +using System.Globalization; +using System.Xml; -namespace OfficeOpenXml.Style.Dxf -{ - public class ExcelDxfStyleConditionalFormatting : DxfStyleBase<ExcelDxfStyleConditionalFormatting> - { - XmlHelperInstance _helper; - internal ExcelDxfStyleConditionalFormatting(XmlNamespaceManager nameSpaceManager, XmlNode topNode, ExcelStyles styles) : base(styles) - { - NumberFormat = new ExcelDxfNumberFormat(_styles); - Font = new ExcelDxfFontBase(_styles); - Border = new ExcelDxfBorderBase(_styles); - Fill = new ExcelDxfFill(_styles); - if (topNode != null) - { - _helper = new XmlHelperInstance(nameSpaceManager, topNode); - NumberFormat.NumFmtID = _helper.GetXmlNodeInt("d:numFmt/@numFmtId"); - NumberFormat.Format = _helper.GetXmlNodeString("d:numFmt/@formatCode"); - if (NumberFormat.NumFmtID < 164 && string.IsNullOrEmpty(NumberFormat.Format)) - { - NumberFormat.Format = ExcelNumberFormat.GetFromBuildInFromID(NumberFormat.NumFmtID); - } +namespace OfficeOpenXml.Style.Dxf; - Font.Bold = _helper.GetXmlNodeBoolNullable("d:font/d:b/@val"); - Font.Italic = _helper.GetXmlNodeBoolNullable("d:font/d:i/@val"); - Font.Strike = _helper.GetXmlNodeBoolNullable("d:font/d:strike"); - Font.Underline = GetUnderLineEnum(_helper.GetXmlNodeString("d:font/d:u/@val")); - Font.Color = GetColor(_helper, "d:font/d:color"); +public class ExcelDxfStyleConditionalFormatting : DxfStyleBase<ExcelDxfStyleConditionalFormatting> { + private XmlHelperInstance _helper; - Border.Left = GetBorderItem(_helper, "d:border/d:left"); - Border.Right = GetBorderItem(_helper, "d:border/d:right"); - Border.Bottom = GetBorderItem(_helper, "d:border/d:bottom"); - Border.Top = GetBorderItem(_helper, "d:border/d:top"); + internal ExcelDxfStyleConditionalFormatting( + XmlNamespaceManager nameSpaceManager, + XmlNode topNode, + ExcelStyles styles) + : base(styles) { + NumberFormat = new(_styles); + Font = new(_styles); + Border = new(_styles); + Fill = new(_styles); + if (topNode != null) { + _helper = new(nameSpaceManager, topNode); + NumberFormat.NumFmtID = _helper.GetXmlNodeInt("d:numFmt/@numFmtId"); + NumberFormat.Format = _helper.GetXmlNodeString("d:numFmt/@formatCode"); + if (NumberFormat.NumFmtID < 164 && string.IsNullOrEmpty(NumberFormat.Format)) { + NumberFormat.Format = ExcelNumberFormat.GetFromBuildInFromId(NumberFormat.NumFmtID); + } - Fill.PatternType = GetPatternTypeEnum(_helper.GetXmlNodeString("d:fill/d:patternFill/@patternType")); - Fill.BackgroundColor = GetColor(_helper, "d:fill/d:patternFill/d:bgColor/"); - Fill.PatternColor = GetColor(_helper, "d:fill/d:patternFill/d:fgColor/"); - } - else - { - _helper = new XmlHelperInstance(nameSpaceManager); - } - _helper.SchemaNodeOrder = new string[] { "font", "numFmt", "fill", "border" }; - } - private ExcelDxfBorderItem GetBorderItem(XmlHelperInstance helper, string path) - { - ExcelDxfBorderItem bi = new ExcelDxfBorderItem(_styles); - bi.Style = GetBorderStyleEnum(helper.GetXmlNodeString(path+"/@style")); - bi.Color = GetColor(helper, path+"/d:color"); - return bi; - } - private ExcelBorderStyle GetBorderStyleEnum(string style) - { - if (style == "") return ExcelBorderStyle.None; - string sInStyle = style.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + style.Substring(1, style.Length - 1); - try - { - return (ExcelBorderStyle)Enum.Parse(typeof(ExcelBorderStyle), sInStyle); - } - catch - { - return ExcelBorderStyle.None; - } + Font.Bold = _helper.GetXmlNodeBoolNullable("d:font/d:b/@val"); + Font.Italic = _helper.GetXmlNodeBoolNullable("d:font/d:i/@val"); + Font.Strike = _helper.GetXmlNodeBoolNullable("d:font/d:strike"); + Font.Underline = GetUnderLineEnum(_helper.GetXmlNodeString("d:font/d:u/@val")); + Font.Color = GetColor(_helper, "d:font/d:color"); - } - private ExcelFillStyle GetPatternTypeEnum(string patternType) - { - if (patternType == "") return ExcelFillStyle.None; - patternType = patternType.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + patternType.Substring(1, patternType.Length - 1); - try - { - return (ExcelFillStyle)Enum.Parse(typeof(ExcelFillStyle), patternType); - } - catch - { - return ExcelFillStyle.None; - } - } - private ExcelDxfColor GetColor(XmlHelperInstance helper, string path) - { - ExcelDxfColor ret = new ExcelDxfColor(_styles); - ret.Theme = helper.GetXmlNodeIntNull(path + "/@theme"); - ret.Index = helper.GetXmlNodeIntNull(path + "/@indexed"); - string rgb=helper.GetXmlNodeString(path + "/@rgb"); - if(rgb!="") - { - ret.Color = Color.FromArgb( int.Parse(rgb.Substring(0, 2), System.Globalization.NumberStyles.AllowHexSpecifier), - int.Parse(rgb.Substring(2, 2), System.Globalization.NumberStyles.AllowHexSpecifier), - int.Parse(rgb.Substring(4, 2), System.Globalization.NumberStyles.AllowHexSpecifier), - int.Parse(rgb.Substring(6, 2), System.Globalization.NumberStyles.AllowHexSpecifier)); - } - ret.Auto = helper.GetXmlNodeBoolNullable(path + "/@auto"); - ret.Tint = helper.GetXmlNodeDoubleNull(path + "/@tint"); - return ret; - } - private ExcelUnderLineType? GetUnderLineEnum(string value) - { - switch(value.ToLower(CultureInfo.InvariantCulture)) - { - case "single": - return ExcelUnderLineType.Single; - case "double": - return ExcelUnderLineType.Double; - case "singleaccounting": - return ExcelUnderLineType.SingleAccounting; - case "doubleaccounting": - return ExcelUnderLineType.DoubleAccounting; - default: - return null; - } - } - internal int DxfId { get; set; } - public ExcelDxfFontBase Font { get; set; } - public ExcelDxfNumberFormat NumberFormat { get; set; } - public ExcelDxfFill Fill { get; set; } - public ExcelDxfBorderBase Border { get; set; } - protected internal override string Id - { - get - { - return NumberFormat.Id + Font.Id + Border.Id + Fill.Id + - (AllowChange ? "" : DxfId.ToString());//If allowchange is false we add the dxfID to ensure it's not used when conditional formatting is updated); - } - } - protected internal override ExcelDxfStyleConditionalFormatting Clone() - { - var s=new ExcelDxfStyleConditionalFormatting(_helper.NameSpaceManager, null, _styles); - s.Font = Font.Clone(); - s.NumberFormat = NumberFormat.Clone(); - s.Fill = Fill.Clone(); - s.Border = Border.Clone(); - return s; - } + Border.Left = GetBorderItem(_helper, "d:border/d:left"); + Border.Right = GetBorderItem(_helper, "d:border/d:right"); + Border.Bottom = GetBorderItem(_helper, "d:border/d:bottom"); + Border.Top = GetBorderItem(_helper, "d:border/d:top"); - protected internal override void CreateNodes(XmlHelper helper, string path) - { - if(Font.HasValue) Font.CreateNodes(helper, "d:font"); - if (NumberFormat.HasValue) NumberFormat.CreateNodes(helper, "d:numFmt"); - if (Fill.HasValue) Fill.CreateNodes(helper, "d:fill"); - if (Border.HasValue) Border.CreateNodes(helper, "d:border"); - } - protected internal override bool HasValue - { - get { return Font.HasValue || NumberFormat.HasValue || Fill.HasValue || Border.HasValue; } - } + Fill.PatternType = GetPatternTypeEnum( + _helper.GetXmlNodeString("d:fill/d:patternFill/@patternType")); + Fill.BackgroundColor = GetColor(_helper, "d:fill/d:patternFill/d:bgColor/"); + Fill.PatternColor = GetColor(_helper, "d:fill/d:patternFill/d:fgColor/"); + } else { + _helper = new(nameSpaceManager); } + _helper.SchemaNodeOrder = new[] { "font", "numFmt", "fill", "border" }; + } + + private ExcelDxfBorderItem GetBorderItem(XmlHelperInstance helper, string path) { + ExcelDxfBorderItem bi = new ExcelDxfBorderItem(_styles); + bi.Style = GetBorderStyleEnum(helper.GetXmlNodeString(path + "/@style")); + bi.Color = GetColor(helper, path + "/d:color"); + return bi; + } + + private ExcelBorderStyle GetBorderStyleEnum(string style) { + if (style == "") { + return ExcelBorderStyle.None; + } + string sInStyle = + style.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + + style.Substring(1, style.Length - 1); + try { + return (ExcelBorderStyle)Enum.Parse(typeof(ExcelBorderStyle), sInStyle); + } catch { + return ExcelBorderStyle.None; + } + } + + private ExcelFillStyle GetPatternTypeEnum(string patternType) { + if (patternType == "") { + return ExcelFillStyle.None; + } + patternType = + patternType.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + + patternType.Substring(1, patternType.Length - 1); + try { + return (ExcelFillStyle)Enum.Parse(typeof(ExcelFillStyle), patternType); + } catch { + return ExcelFillStyle.None; + } + } + + private ExcelDxfColor GetColor(XmlHelperInstance helper, string path) { + ExcelDxfColor ret = new ExcelDxfColor(_styles); + ret.Theme = helper.GetXmlNodeIntNull(path + "/@theme"); + ret.Index = helper.GetXmlNodeIntNull(path + "/@indexed"); + string rgb = helper.GetXmlNodeString(path + "/@rgb"); + if (rgb != "") { + ret.Color = Color.FromArgb( + int.Parse(rgb.Substring(0, 2), NumberStyles.AllowHexSpecifier), + int.Parse(rgb.Substring(2, 2), NumberStyles.AllowHexSpecifier), + int.Parse(rgb.Substring(4, 2), NumberStyles.AllowHexSpecifier), + int.Parse(rgb.Substring(6, 2), NumberStyles.AllowHexSpecifier)); + } + ret.Auto = helper.GetXmlNodeBoolNullable(path + "/@auto"); + ret.Tint = helper.GetXmlNodeDoubleNull(path + "/@tint"); + return ret; + } + + private ExcelUnderLineType? GetUnderLineEnum(string value) { + switch (value.ToLower(CultureInfo.InvariantCulture)) { + case "single": + return ExcelUnderLineType.Single; + case "double": + return ExcelUnderLineType.Double; + case "singleaccounting": + return ExcelUnderLineType.SingleAccounting; + case "doubleaccounting": + return ExcelUnderLineType.DoubleAccounting; + default: + return null; + } + } + + internal int DxfId { get; set; } + + public ExcelDxfFontBase Font { get; set; } + + public ExcelDxfNumberFormat NumberFormat { get; set; } + + public ExcelDxfFill Fill { get; set; } + + public ExcelDxfBorderBase Border { get; set; } + + protected internal override string Id => + NumberFormat.Id + Font.Id + Border.Id + Fill.Id + (AllowChange ? "" : DxfId.ToString()); //If allowchange is false we add the dxfID to ensure it's not used when conditional formatting is updated); + + protected internal override ExcelDxfStyleConditionalFormatting Clone() { + var s = new ExcelDxfStyleConditionalFormatting(_helper.NameSpaceManager, null, _styles); + s.Font = Font.Clone(); + s.NumberFormat = NumberFormat.Clone(); + s.Fill = Fill.Clone(); + s.Border = Border.Clone(); + return s; + } + + protected internal override void CreateNodes(XmlHelper helper, string path) { + if (Font.HasValue) { + Font.CreateNodes(helper, "d:font"); + } + if (NumberFormat.HasValue) { + NumberFormat.CreateNodes(helper, "d:numFmt"); + } + if (Fill.HasValue) { + Fill.CreateNodes(helper, "d:fill"); + } + if (Border.HasValue) { + Border.CreateNodes(helper, "d:border"); + } + } + + protected internal override bool HasValue => + Font.HasValue || NumberFormat.HasValue || Fill.HasValue || Border.HasValue; }
diff --git a/EPPlus/Style/ExcelBorder.cs b/EPPlus/Style/ExcelBorder.cs index d2db7c3..bf07432 100644 --- a/EPPlus/Style/ExcelBorder.cs +++ b/EPPlus/Style/ExcelBorder.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,166 +13,190 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -using OfficeOpenXml.Style.XmlAccess; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Cell Border style - /// </summary> - public sealed class Border : StyleBase - { - internal Border(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int PositionID, string address, int index) : - base(styles, ChangedEvent, PositionID, address) - { - Index = index; - } - /// <summary> - /// Left border style - /// </summary> - public ExcelBorderItem Left - { - get - { - return new ExcelBorderItem(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderLeft, this); - } - } - /// <summary> - /// Right border style - /// </summary> - public ExcelBorderItem Right - { - get - { - return new ExcelBorderItem(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderRight, this); - } - } - /// <summary> - /// Top border style - /// </summary> - public ExcelBorderItem Top - { - get - { - return new ExcelBorderItem(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderTop, this); - } - } - /// <summary> - /// Bottom border style - /// </summary> - public ExcelBorderItem Bottom - { - get - { - return new ExcelBorderItem(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderBottom, this); - } - } - /// <summary> - /// 0Diagonal border style - /// </summary> - public ExcelBorderItem Diagonal - { - get - { - return new ExcelBorderItem(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderDiagonal, this); - } - } - /// <summary> - /// A diagonal from the bottom left to top right of the cell - /// </summary> - public bool DiagonalUp - { - get - { - if (Index >=0) - { - return _styles.Borders[Index].DiagonalUp; - } - else - { - return false; - } - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Border, eStyleProperty.BorderDiagonalUp, value, _positionID, _address)); - } - } - /// <summary> - /// A diagonal from the top left to bottom right of the cell - /// </summary> - public bool DiagonalDown - { - get - { - if (Index >= 0) - { - return _styles.Borders[Index].DiagonalDown; - } - else - { - return false; - } - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Border, eStyleProperty.BorderDiagonalDown, value, _positionID, _address)); - } - } - internal override string Id - { - get { return Top.Id + Bottom.Id +Left.Id + Right.Id + Diagonal.Id + DiagonalUp + DiagonalDown; } - } - /// <summary> - /// Set the border style around the range. - /// </summary> - /// <param name="Style">The border style</param> - public void BorderAround(ExcelBorderStyle Style) - { - var addr = new ExcelAddress(_address); - SetBorderAroundStyle(Style, addr); - } - /// <summary> - /// Set the border style around the range. - /// </summary> - /// <param name="Style">The border style</param> - /// <param name="Color">The color of the border</param> - public void BorderAround(ExcelBorderStyle Style, System.Drawing.Color Color) - { - var addr=new ExcelAddress(_address); - SetBorderAroundStyle(Style, addr); +using System.Drawing; - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderTop, eStyleProperty.Color, Color.ToArgb().ToString("X"), _positionID, new ExcelAddress(addr._fromRow, addr._fromCol, addr._fromRow, addr._toCol).Address)); - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderBottom, eStyleProperty.Color, Color.ToArgb().ToString("X"), _positionID, new ExcelAddress(addr._toRow, addr._fromCol, addr._toRow, addr._toCol).Address)); - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderLeft, eStyleProperty.Color, Color.ToArgb().ToString("X"), _positionID, new ExcelAddress(addr._fromRow, addr._fromCol, addr._toRow, addr._fromCol).Address)); - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderRight, eStyleProperty.Color, Color.ToArgb().ToString("X"), _positionID, new ExcelAddress(addr._fromRow, addr._toCol, addr._toRow, addr._toCol).Address)); - } +namespace OfficeOpenXml.Style; - private void SetBorderAroundStyle(ExcelBorderStyle Style, ExcelAddress addr) - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderTop, eStyleProperty.Style, Style, _positionID, new ExcelAddress(addr._fromRow, addr._fromCol, addr._fromRow, addr._toCol).Address)); - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderBottom, eStyleProperty.Style, Style, _positionID, new ExcelAddress(addr._toRow, addr._fromCol, addr._toRow, addr._toCol).Address)); - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderLeft, eStyleProperty.Style, Style, _positionID, new ExcelAddress(addr._fromRow, addr._fromCol, addr._toRow, addr._fromCol).Address)); - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.BorderRight, eStyleProperty.Style, Style, _positionID, new ExcelAddress(addr._fromRow, addr._toCol, addr._toRow, addr._toCol).Address)); - } +/// <summary> +/// Cell Border style +/// </summary> +public sealed class Border : StyleBase { + internal Border( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int positionId, + string address, + int index) + : base(styles, changedEvent, positionId, address) { + Index = index; + } + + /// <summary> + /// Left border style + /// </summary> + public ExcelBorderItem Left => + new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderLeft, this); + + /// <summary> + /// Right border style + /// </summary> + public ExcelBorderItem Right => + new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderRight, this); + + /// <summary> + /// Top border style + /// </summary> + public ExcelBorderItem Top => + new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderTop, this); + + /// <summary> + /// Bottom border style + /// </summary> + public ExcelBorderItem Bottom => + new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderBottom, this); + + /// <summary> + /// 0Diagonal border style + /// </summary> + public ExcelBorderItem Diagonal => + new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.BorderDiagonal, this); + + /// <summary> + /// A diagonal from the bottom left to top right of the cell + /// </summary> + public bool DiagonalUp { + get { + if (Index >= 0) { + return _styles.Borders[Index].DiagonalUp; + } + return false; } + set => + _ChangedEvent( + this, + new(eStyleClass.Border, eStyleProperty.BorderDiagonalUp, value, _positionID, _address)); + } + + /// <summary> + /// A diagonal from the top left to bottom right of the cell + /// </summary> + public bool DiagonalDown { + get { + if (Index >= 0) { + return _styles.Borders[Index].DiagonalDown; + } + return false; + } + set => + _ChangedEvent( + this, + new(eStyleClass.Border, eStyleProperty.BorderDiagonalDown, value, _positionID, _address)); + } + + internal override string Id => + Top.Id + Bottom.Id + Left.Id + Right.Id + Diagonal.Id + DiagonalUp + DiagonalDown; + + /// <summary> + /// Set the border style around the range. + /// </summary> + /// <param name="style">The border style</param> + public void BorderAround(ExcelBorderStyle style) { + var addr = new ExcelAddress(_address); + SetBorderAroundStyle(style, addr); + } + + /// <summary> + /// Set the border style around the range. + /// </summary> + /// <param name="style">The border style</param> + /// <param name="color">The color of the border</param> + public void BorderAround(ExcelBorderStyle style, Color color) { + var addr = new ExcelAddress(_address); + SetBorderAroundStyle(style, addr); + + _ChangedEvent( + this, + new( + eStyleClass.BorderTop, + eStyleProperty.Color, + color.ToArgb().ToString("X"), + _positionID, + new ExcelAddress(addr._fromRow, addr._fromCol, addr._fromRow, addr._toCol).Address)); + _ChangedEvent( + this, + new( + eStyleClass.BorderBottom, + eStyleProperty.Color, + color.ToArgb().ToString("X"), + _positionID, + new ExcelAddress(addr._toRow, addr._fromCol, addr._toRow, addr._toCol).Address)); + _ChangedEvent( + this, + new( + eStyleClass.BorderLeft, + eStyleProperty.Color, + color.ToArgb().ToString("X"), + _positionID, + new ExcelAddress(addr._fromRow, addr._fromCol, addr._toRow, addr._fromCol).Address)); + _ChangedEvent( + this, + new( + eStyleClass.BorderRight, + eStyleProperty.Color, + color.ToArgb().ToString("X"), + _positionID, + new ExcelAddress(addr._fromRow, addr._toCol, addr._toRow, addr._toCol).Address)); + } + + private void SetBorderAroundStyle(ExcelBorderStyle style, ExcelAddress addr) { + _ChangedEvent( + this, + new( + eStyleClass.BorderTop, + eStyleProperty.Style, + style, + _positionID, + new ExcelAddress(addr._fromRow, addr._fromCol, addr._fromRow, addr._toCol).Address)); + _ChangedEvent( + this, + new( + eStyleClass.BorderBottom, + eStyleProperty.Style, + style, + _positionID, + new ExcelAddress(addr._toRow, addr._fromCol, addr._toRow, addr._toCol).Address)); + _ChangedEvent( + this, + new( + eStyleClass.BorderLeft, + eStyleProperty.Style, + style, + _positionID, + new ExcelAddress(addr._fromRow, addr._fromCol, addr._toRow, addr._fromCol).Address)); + _ChangedEvent( + this, + new( + eStyleClass.BorderRight, + eStyleProperty.Style, + style, + _positionID, + new ExcelAddress(addr._fromRow, addr._toCol, addr._toRow, addr._toCol).Address)); + } }
diff --git a/EPPlus/Style/ExcelBorderItem.cs b/EPPlus/Style/ExcelBorderItem.cs index 7794d9a..f46f55a 100644 --- a/EPPlus/Style/ExcelBorderItem.cs +++ b/EPPlus/Style/ExcelBorderItem.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,100 +13,91 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; using OfficeOpenXml.Style.XmlAccess; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Cell border style - /// </summary> - public sealed class ExcelBorderItem : StyleBase - { - eStyleClass _cls; - StyleBase _parent; - internal ExcelBorderItem (ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int worksheetID, string address, eStyleClass cls, StyleBase parent) : - base(styles, ChangedEvent, worksheetID, address) - { - _cls=cls; - _parent = parent; - } - /// <summary> - /// The line style of the border - /// </summary> - public ExcelBorderStyle Style - { - get - { - return GetSource().Style; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(_cls, eStyleProperty.Style, value, _positionID, _address)); - } - } - ExcelColor _color=null; - /// <summary> - /// The color of the border - /// </summary> - public ExcelColor Color - { - get - { - if (_color == null) - { - _color = new ExcelColor(_styles, _ChangedEvent, _positionID, _address, _cls, _parent); - } - return _color; - } - } +namespace OfficeOpenXml.Style; - internal override string Id - { - get { return Style + Color.Id; } - } - internal override void SetIndex(int index) - { - _parent.Index = index; - } - private ExcelBorderItemXml GetSource() - { - int ix = _parent.Index < 0 ? 0 : _parent.Index; +/// <summary> +/// Cell border style +/// </summary> +public sealed class ExcelBorderItem : StyleBase { + private eStyleClass _cls; + private StyleBase _parent; - switch(_cls) - { - case eStyleClass.BorderTop: - return _styles.Borders[ix].Top; - case eStyleClass.BorderBottom: - return _styles.Borders[ix].Bottom; - case eStyleClass.BorderLeft: - return _styles.Borders[ix].Left; - case eStyleClass.BorderRight: - return _styles.Borders[ix].Right; - case eStyleClass.BorderDiagonal: - return _styles.Borders[ix].Diagonal; - default: - throw new Exception("Invalid class for Borderitem"); - } + internal ExcelBorderItem( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int worksheetId, + string address, + eStyleClass cls, + StyleBase parent) + : base(styles, changedEvent, worksheetId, address) { + _cls = cls; + _parent = parent; + } - } + /// <summary> + /// The line style of the border + /// </summary> + public ExcelBorderStyle Style { + get => GetSource().Style; + set => _ChangedEvent(this, new(_cls, eStyleProperty.Style, value, _positionID, _address)); + } + + private ExcelColor _color; + + /// <summary> + /// The color of the border + /// </summary> + public ExcelColor Color { + get { + if (_color == null) { + _color = new(_styles, _ChangedEvent, _positionID, _address, _cls, _parent); + } + return _color; } + } + + internal override string Id => Style + Color.Id; + + internal override void SetIndex(int index) { + _parent.Index = index; + } + + private ExcelBorderItemXml GetSource() { + int ix = _parent.Index < 0 ? 0 : _parent.Index; + + switch (_cls) { + case eStyleClass.BorderTop: + return _styles.Borders[ix].Top; + case eStyleClass.BorderBottom: + return _styles.Borders[ix].Bottom; + case eStyleClass.BorderLeft: + return _styles.Borders[ix].Left; + case eStyleClass.BorderRight: + return _styles.Borders[ix].Right; + case eStyleClass.BorderDiagonal: + return _styles.Borders[ix].Diagonal; + default: + throw new("Invalid class for Borderitem"); + } + } }
diff --git a/EPPlus/Style/ExcelColor.cs b/EPPlus/Style/ExcelColor.cs index 33d1957..935f78e 100644 --- a/EPPlus/Style/ExcelColor.cs +++ b/EPPlus/Style/ExcelColor.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,245 +13,213 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -using OfficeOpenXml.Style.XmlAccess; using System.Drawing; +using OfficeOpenXml.Style.XmlAccess; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Color for cellstyling - /// </summary> - public sealed class ExcelColor : StyleBase - { - eStyleClass _cls; - StyleBase _parent; - internal ExcelColor(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int worksheetID, string address, eStyleClass cls, StyleBase parent) : - base(styles, ChangedEvent, worksheetID, address) - - { - _parent = parent; - _cls = cls; - } - /// <summary> - /// The theme color - /// </summary> - public string Theme - { - get - { - return GetSource().Theme; - } - } - /// <summary> - /// The tint value - /// </summary> - public decimal Tint - { - get - { - return GetSource().Tint; - } - set - { - if (value > 1 || value < -1) - { - throw (new ArgumentOutOfRangeException("Value must be between -1 and 1")); - } - _ChangedEvent(this, new StyleChangeEventArgs(_cls, eStyleProperty.Tint, value, _positionID, _address)); - } - } - /// <summary> - /// The RGB value - /// </summary> - public string Rgb - { - get - { - return GetSource().Rgb; - } - internal set - { - _ChangedEvent(this, new StyleChangeEventArgs(_cls, eStyleProperty.Color, value, _positionID, _address)); - } - } - /// <summary> - /// The indexed color number. - /// </summary> - public int Indexed - { - get - { - return GetSource().Indexed; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(_cls, eStyleProperty.IndexedColor, value, _positionID, _address)); - } - } - /// <summary> - /// Set the color of the object - /// </summary> - /// <param name="color">The color</param> - public void SetColor(Color color) - { - Rgb = color.ToArgb().ToString("X"); - } +namespace OfficeOpenXml.Style; +/// <summary> +/// Color for cellstyling +/// </summary> +public sealed class ExcelColor : StyleBase { + private eStyleClass _cls; + private StyleBase _parent; - internal override string Id - { - get - { - return Theme + Tint + Rgb + Indexed; - } - } - private ExcelColorXml GetSource() - { - Index = _parent.Index < 0 ? 0 : _parent.Index; - switch(_cls) - { - case eStyleClass.FillBackgroundColor: - return _styles.Fills[Index].BackgroundColor; - case eStyleClass.FillPatternColor: - return _styles.Fills[Index].PatternColor; - case eStyleClass.Font: - return _styles.Fonts[Index].Color; - case eStyleClass.BorderLeft: - return _styles.Borders[Index].Left.Color; - case eStyleClass.BorderTop: - return _styles.Borders[Index].Top.Color; - case eStyleClass.BorderRight: - return _styles.Borders[Index].Right.Color; - case eStyleClass.BorderBottom: - return _styles.Borders[Index].Bottom.Color; - case eStyleClass.BorderDiagonal: - return _styles.Borders[Index].Diagonal.Color; - default: - throw(new Exception("Invalid style-class for Color")); - } - } - internal override void SetIndex(int index) - { - _parent.Index = index; - } - /// <summary> - /// Return the RGB value for the color object that uses the Indexed or Tint property - /// </summary> - /// <param name="theColor">The color object</param> - /// <returns>The RGB color starting with a #</returns> - public string LookupColor(ExcelColor theColor) - { - //Thanks to neaves for contributing this method. - int iTint = 0; - string translatedRGB = ""; + internal ExcelColor( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int worksheetId, + string address, + eStyleClass cls, + StyleBase parent) + : base(styles, changedEvent, worksheetId, address) { + _parent = parent; + _cls = cls; + } - // reference extracted from ECMA-376, Part 4, Section 3.8.26 - string[] rgbLookup = - { - "#FF000000", // 0 - "#FFFFFFFF", - "#FFFF0000", - "#FF00FF00", - "#FF0000FF", - "#FFFFFF00", - "#FFFF00FF", - "#FF00FFFF", - "#FF000000", // 8 - "#FFFFFFFF", - "#FFFF0000", - "#FF00FF00", - "#FF0000FF", - "#FFFFFF00", - "#FFFF00FF", - "#FF00FFFF", - "#FF800000", - "#FF008000", - "#FF000080", - "#FF808000", - "#FF800080", - "#FF008080", - "#FFC0C0C0", - "#FF808080", - "#FF9999FF", - "#FF993366", - "#FFFFFFCC", - "#FFCCFFFF", - "#FF660066", - "#FFFF8080", - "#FF0066CC", - "#FFCCCCFF", - "#FF000080", - "#FFFF00FF", - "#FFFFFF00", - "#FF00FFFF", - "#FF800080", - "#FF800000", - "#FF008080", - "#FF0000FF", - "#FF00CCFF", - "#FFCCFFFF", - "#FFCCFFCC", - "#FFFFFF99", - "#FF99CCFF", - "#FFFF99CC", - "#FFCC99FF", - "#FFFFCC99", - "#FF3366FF", - "#FF33CCCC", - "#FF99CC00", - "#FFFFCC00", - "#FFFF9900", - "#FFFF6600", - "#FF666699", - "#FF969696", - "#FF003366", - "#FF339966", - "#FF003300", - "#FF333300", - "#FF993300", - "#FF993366", - "#FF333399", - "#FF333333", // 63 - }; + /// <summary> + /// The theme color + /// </summary> + public string Theme => GetSource().Theme; - if ((0 <= theColor.Indexed) && (rgbLookup.Length > theColor.Indexed)) - { - // coloring by pre-set color codes - translatedRGB = rgbLookup[theColor.Indexed]; - } - else if (null != theColor.Rgb && 0 < theColor.Rgb.Length) - { - // coloring by RGB value ("FFRRGGBB") - translatedRGB = "#" + theColor.Rgb; - } - else - { - // coloring by shades of grey (-1 -> 0) - iTint = ((int)(theColor.Tint * 160) + 0x80); - translatedRGB = ((int)(decimal.Round(theColor.Tint * -512))).ToString("X"); - translatedRGB = "#FF" + translatedRGB + translatedRGB + translatedRGB; - } - - return translatedRGB; - } + /// <summary> + /// The tint value + /// </summary> + public decimal Tint { + get => GetSource().Tint; + set { + if (value > 1 || value < -1) { + throw (new ArgumentOutOfRangeException("Value must be between -1 and 1")); + } + _ChangedEvent(this, new(_cls, eStyleProperty.Tint, value, _positionID, _address)); } + } + + /// <summary> + /// The RGB value + /// </summary> + public string Rgb { + get => GetSource().Rgb; + internal set => + _ChangedEvent(this, new(_cls, eStyleProperty.Color, value, _positionID, _address)); + } + + /// <summary> + /// The indexed color number. + /// </summary> + public int Indexed { + get => GetSource().Indexed; + set => + _ChangedEvent(this, new(_cls, eStyleProperty.IndexedColor, value, _positionID, _address)); + } + + /// <summary> + /// Set the color of the object + /// </summary> + /// <param name="color">The color</param> + public void SetColor(Color color) { + Rgb = color.ToArgb().ToString("X"); + } + + internal override string Id => Theme + Tint + Rgb + Indexed; + + private ExcelColorXml GetSource() { + Index = _parent.Index < 0 ? 0 : _parent.Index; + switch (_cls) { + case eStyleClass.FillBackgroundColor: + return _styles.Fills[Index].BackgroundColor; + case eStyleClass.FillPatternColor: + return _styles.Fills[Index].PatternColor; + case eStyleClass.Font: + return _styles.Fonts[Index].Color; + case eStyleClass.BorderLeft: + return _styles.Borders[Index].Left.Color; + case eStyleClass.BorderTop: + return _styles.Borders[Index].Top.Color; + case eStyleClass.BorderRight: + return _styles.Borders[Index].Right.Color; + case eStyleClass.BorderBottom: + return _styles.Borders[Index].Bottom.Color; + case eStyleClass.BorderDiagonal: + return _styles.Borders[Index].Diagonal.Color; + default: + throw (new("Invalid style-class for Color")); + } + } + + internal override void SetIndex(int index) { + _parent.Index = index; + } + + /// <summary> + /// Return the RGB value for the color object that uses the Indexed or Tint property + /// </summary> + /// <param name="theColor">The color object</param> + /// <returns>The RGB color starting with a #</returns> + public string LookupColor(ExcelColor theColor) { + //Thanks to neaves for contributing this method. + int iTint = 0; + string translatedRgb = ""; + + // reference extracted from ECMA-376, Part 4, Section 3.8.26 + string[] rgbLookup = { + "#FF000000", // 0 + "#FFFFFFFF", + "#FFFF0000", + "#FF00FF00", + "#FF0000FF", + "#FFFFFF00", + "#FFFF00FF", + "#FF00FFFF", + "#FF000000", // 8 + "#FFFFFFFF", + "#FFFF0000", + "#FF00FF00", + "#FF0000FF", + "#FFFFFF00", + "#FFFF00FF", + "#FF00FFFF", + "#FF800000", + "#FF008000", + "#FF000080", + "#FF808000", + "#FF800080", + "#FF008080", + "#FFC0C0C0", + "#FF808080", + "#FF9999FF", + "#FF993366", + "#FFFFFFCC", + "#FFCCFFFF", + "#FF660066", + "#FFFF8080", + "#FF0066CC", + "#FFCCCCFF", + "#FF000080", + "#FFFF00FF", + "#FFFFFF00", + "#FF00FFFF", + "#FF800080", + "#FF800000", + "#FF008080", + "#FF0000FF", + "#FF00CCFF", + "#FFCCFFFF", + "#FFCCFFCC", + "#FFFFFF99", + "#FF99CCFF", + "#FFFF99CC", + "#FFCC99FF", + "#FFFFCC99", + "#FF3366FF", + "#FF33CCCC", + "#FF99CC00", + "#FFFFCC00", + "#FFFF9900", + "#FFFF6600", + "#FF666699", + "#FF969696", + "#FF003366", + "#FF339966", + "#FF003300", + "#FF333300", + "#FF993300", + "#FF993366", + "#FF333399", + "#FF333333", // 63 + }; + + if ((0 <= theColor.Indexed) && (rgbLookup.Length > theColor.Indexed)) { + // coloring by pre-set color codes + translatedRgb = rgbLookup[theColor.Indexed]; + } else if (null != theColor.Rgb && 0 < theColor.Rgb.Length) { + // coloring by RGB value ("FFRRGGBB") + translatedRgb = "#" + theColor.Rgb; + } else { + // coloring by shades of grey (-1 -> 0) + iTint = ((int)(theColor.Tint * 160) + 0x80); + translatedRgb = ((int)(decimal.Round(theColor.Tint * -512))).ToString("X"); + translatedRgb = "#FF" + translatedRgb + translatedRgb + translatedRgb; + } + + return translatedRgb; + } }
diff --git a/EPPlus/Style/ExcelFill.cs b/EPPlus/Style/ExcelFill.cs index f957154..d1a5ea6 100644 --- a/EPPlus/Style/ExcelFill.cs +++ b/EPPlus/Style/ExcelFill.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,126 +13,127 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -using OfficeOpenXml.Style.XmlAccess; -using System.Globalization; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// The background fill of a cell - /// </summary> - public class ExcelFill : StyleBase - { - internal ExcelFill(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int PositionID, string address, int index) : - base(styles, ChangedEvent, PositionID, address) +namespace OfficeOpenXml.Style; - { - Index = index; - } - /// <summary> - /// The pattern for solid fills. - /// </summary> - public ExcelFillStyle PatternType - { - get - { - if (Index == int.MinValue) - { - return ExcelFillStyle.None; - } - else - { - return _styles.Fills[Index].PatternType; - } - } - set - { - if (_gradient != null) _gradient = null; - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Fill, eStyleProperty.PatternType, value, _positionID, _address)); - } - } - ExcelColor _patternColor = null; - /// <summary> - /// The color of the pattern - /// </summary> - public ExcelColor PatternColor - { - get - { - if (_patternColor == null) - { - _patternColor = new ExcelColor(_styles, _ChangedEvent, _positionID, _address, eStyleClass.FillPatternColor, this); - if (_gradient != null) _gradient = null; - } - return _patternColor; - } - } - ExcelColor _backgroundColor = null; - /// <summary> - /// The background color - /// </summary> - public ExcelColor BackgroundColor - { - get - { - if (_backgroundColor == null) - { - _backgroundColor = new ExcelColor(_styles, _ChangedEvent, _positionID, _address, eStyleClass.FillBackgroundColor, this); - if (_gradient != null) _gradient = null; - } - return _backgroundColor; - - } - } - ExcelGradientFill _gradient=null; - /// <summary> - /// Access to properties for gradient fill. - /// </summary> - public ExcelGradientFill Gradient - { - get - { - if (_gradient == null) - { - _gradient = new ExcelGradientFill(_styles, _ChangedEvent, _positionID, _address, Index); - _backgroundColor = null; - _patternColor = null; - } - return _gradient; - } - } - internal override string Id - { - get - { - if (_gradient == null) - { - return PatternType + PatternColor.Id + BackgroundColor.Id; - } - else - { - return _gradient.Id; - } - } - } +/// <summary> +/// The background fill of a cell +/// </summary> +public class ExcelFill : StyleBase { + internal ExcelFill( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int positionId, + string address, + int index) + : base(styles, changedEvent, positionId, address) { + Index = index; + } + + /// <summary> + /// The pattern for solid fills. + /// </summary> + public ExcelFillStyle PatternType { + get { + if (Index == int.MinValue) { + return ExcelFillStyle.None; + } + return _styles.Fills[Index].PatternType; } + set { + if (_gradient != null) { + _gradient = null; + } + _ChangedEvent( + this, + new(eStyleClass.Fill, eStyleProperty.PatternType, value, _positionID, _address)); + } + } + + private ExcelColor _patternColor; + + /// <summary> + /// The color of the pattern + /// </summary> + public ExcelColor PatternColor { + get { + if (_patternColor == null) { + _patternColor = new( + _styles, + _ChangedEvent, + _positionID, + _address, + eStyleClass.FillPatternColor, + this); + if (_gradient != null) { + _gradient = null; + } + } + return _patternColor; + } + } + + private ExcelColor _backgroundColor; + + /// <summary> + /// The background color + /// </summary> + public ExcelColor BackgroundColor { + get { + if (_backgroundColor == null) { + _backgroundColor = new( + _styles, + _ChangedEvent, + _positionID, + _address, + eStyleClass.FillBackgroundColor, + this); + if (_gradient != null) { + _gradient = null; + } + } + return _backgroundColor; + } + } + + private ExcelGradientFill _gradient; + + /// <summary> + /// Access to properties for gradient fill. + /// </summary> + public ExcelGradientFill Gradient { + get { + if (_gradient == null) { + _gradient = new(_styles, _ChangedEvent, _positionID, _address, Index); + _backgroundColor = null; + _patternColor = null; + } + return _gradient; + } + } + + internal override string Id { + get { + if (_gradient == null) { + return PatternType + PatternColor.Id + BackgroundColor.Id; + } + return _gradient.Id; + } + } }
diff --git a/EPPlus/Style/ExcelFont.cs b/EPPlus/Style/ExcelFont.cs index 4702d83..36beb83 100644 --- a/EPPlus/Style/ExcelFont.cs +++ b/EPPlus/Style/ExcelFont.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,223 +13,181 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; using System.Drawing; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Cell style Font - /// </summary> - public sealed class ExcelFont : StyleBase - { - internal ExcelFont(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int PositionID, string address, int index) : - base(styles, ChangedEvent, PositionID, address) +namespace OfficeOpenXml.Style; - { - Index = index; - } - /// <summary> - /// The name of the font - /// </summary> - public string Name - { - get - { - return _styles.Fonts[Index].Name; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.Name, value, _positionID, _address)); - } - } - /// <summary> - /// The Size of the font - /// </summary> - public float Size - { - get - { - return _styles.Fonts[Index].Size; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.Size, value, _positionID, _address)); - } - } - /// <summary> - /// Font family - /// </summary> - public int Family - { - get - { - return _styles.Fonts[Index].Family; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.Family, value, _positionID, _address)); - } - } - /// <summary> - /// Cell color - /// </summary> - public ExcelColor Color - { - get - { - return new ExcelColor(_styles, _ChangedEvent, _positionID, _address, eStyleClass.Font, this); - } - } - /// <summary> - /// Scheme - /// </summary> - public string Scheme - { - get - { - return _styles.Fonts[Index].Scheme; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.Scheme, value, _positionID, _address)); - } - } - /// <summary> - /// Font-bold - /// </summary> - public bool Bold - { - get - { - return _styles.Fonts[Index].Bold; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.Bold, value, _positionID, _address)); - } - } - /// <summary> - /// Font-italic - /// </summary> - public bool Italic - { - get - { - return _styles.Fonts[Index].Italic; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.Italic, value, _positionID, _address)); - } - } - /// <summary> - /// Font-Strikeout - /// </summary> - public bool Strike - { - get - { - return _styles.Fonts[Index].Strike; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.Strike, value, _positionID, _address)); - } - } - /// <summary> - /// Font-Underline - /// </summary> - public bool UnderLine - { - get - { - return _styles.Fonts[Index].UnderLine; - } - set - { - if (value) - { - UnderLineType = ExcelUnderLineType.Single; - } - else - { - UnderLineType = ExcelUnderLineType.None; - } - //_ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.UnderlineType, value, _positionID, _address)); - } - } - public ExcelUnderLineType UnderLineType - { - get - { - return _styles.Fonts[Index].UnderLineType; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.UnderlineType, value, _positionID, _address)); - } - } - /// <summary> - /// Font-Vertical Align - /// </summary> - public ExcelVerticalAlignmentFont VerticalAlign - { - get - { - if (_styles.Fonts[Index].VerticalAlign == "") - { - return ExcelVerticalAlignmentFont.None; - } - else - { - return (ExcelVerticalAlignmentFont)Enum.Parse(typeof(ExcelVerticalAlignmentFont), _styles.Fonts[Index].VerticalAlign, true); - } - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.VerticalAlign, value, _positionID, _address)); - } - } - /// <summary> - /// Set the font from a Font object - /// </summary> - /// <param name="Font"></param> - public void SetFromFont(Font Font) - { - Name = Font.Name; - //Family=fnt.FontFamily.; - Size = (int)Font.Size; - Strike = Font.Strikeout; - Bold = Font.Bold; - UnderLine = Font.Underline; - Italic = Font.Italic; - } +/// <summary> +/// Cell style Font +/// </summary> +public sealed class ExcelFont : StyleBase { + internal ExcelFont( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int positionId, + string address, + int index) + : base(styles, changedEvent, positionId, address) { + Index = index; + } - internal override string Id - { - get - { - return Name + Size.ToString() + Family.ToString() + Scheme.ToString() + Bold.ToString()[0] + Italic.ToString()[0] + Strike.ToString()[0] + UnderLine.ToString()[0] + VerticalAlign; - } - } + /// <summary> + /// The name of the font + /// </summary> + public string Name { + get => _styles.Fonts[Index].Name; + set => + _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Name, value, _positionID, _address)); + } + + /// <summary> + /// The Size of the font + /// </summary> + public float Size { + get => _styles.Fonts[Index].Size; + set => + _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Size, value, _positionID, _address)); + } + + /// <summary> + /// Font family + /// </summary> + public int Family { + get => _styles.Fonts[Index].Family; + set => + _ChangedEvent( + this, + new(eStyleClass.Font, eStyleProperty.Family, value, _positionID, _address)); + } + + /// <summary> + /// Cell color + /// </summary> + public ExcelColor Color => + new(_styles, _ChangedEvent, _positionID, _address, eStyleClass.Font, this); + + /// <summary> + /// Scheme + /// </summary> + public string Scheme { + get => _styles.Fonts[Index].Scheme; + set => + _ChangedEvent( + this, + new(eStyleClass.Font, eStyleProperty.Scheme, value, _positionID, _address)); + } + + /// <summary> + /// Font-bold + /// </summary> + public bool Bold { + get => _styles.Fonts[Index].Bold; + set => + _ChangedEvent(this, new(eStyleClass.Font, eStyleProperty.Bold, value, _positionID, _address)); + } + + /// <summary> + /// Font-italic + /// </summary> + public bool Italic { + get => _styles.Fonts[Index].Italic; + set => + _ChangedEvent( + this, + new(eStyleClass.Font, eStyleProperty.Italic, value, _positionID, _address)); + } + + /// <summary> + /// Font-Strikeout + /// </summary> + public bool Strike { + get => _styles.Fonts[Index].Strike; + set => + _ChangedEvent( + this, + new(eStyleClass.Font, eStyleProperty.Strike, value, _positionID, _address)); + } + + /// <summary> + /// Font-Underline + /// </summary> + public bool UnderLine { + get => _styles.Fonts[Index].UnderLine; + set { + if (value) { + UnderLineType = ExcelUnderLineType.Single; + } else { + UnderLineType = ExcelUnderLineType.None; + } + //_ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Font, eStyleProperty.UnderlineType, value, _positionID, _address)); } + } + + public ExcelUnderLineType UnderLineType { + get => _styles.Fonts[Index].UnderLineType; + set => + _ChangedEvent( + this, + new(eStyleClass.Font, eStyleProperty.UnderlineType, value, _positionID, _address)); + } + + /// <summary> + /// Font-Vertical Align + /// </summary> + public ExcelVerticalAlignmentFont VerticalAlign { + get { + if (_styles.Fonts[Index].VerticalAlign == "") { + return ExcelVerticalAlignmentFont.None; + } + return (ExcelVerticalAlignmentFont) + Enum.Parse(typeof(ExcelVerticalAlignmentFont), _styles.Fonts[Index].VerticalAlign, true); + } + set => + _ChangedEvent( + this, + new(eStyleClass.Font, eStyleProperty.VerticalAlign, value, _positionID, _address)); + } + + /// <summary> + /// Set the font from a Font object + /// </summary> + /// <param name="font"></param> + public void SetFromFont(Font font) { + Name = font.Name; + //Family=fnt.FontFamily.; + Size = (int)font.Size; + Strike = font.Strikeout; + Bold = font.Bold; + UnderLine = font.Underline; + Italic = font.Italic; + } + + internal override string Id => + Name + + Size + + Family + + Scheme + + Bold.ToString()[0] + + Italic.ToString()[0] + + Strike.ToString()[0] + + UnderLine.ToString()[0] + + VerticalAlign; }
diff --git a/EPPlus/Style/ExcelGradientFill.cs b/EPPlus/Style/ExcelGradientFill.cs index 1606316..16e73c8 100644 --- a/EPPlus/Style/ExcelGradientFill.cs +++ b/EPPlus/Style/ExcelGradientFill.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,176 +13,179 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; using OfficeOpenXml.Style.XmlAccess; -using System.Globalization; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// The background fill of a cell - /// </summary> - public class ExcelGradientFill : StyleBase - { - internal ExcelGradientFill(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int PositionID, string address, int index) : - base(styles, ChangedEvent, PositionID, address) +namespace OfficeOpenXml.Style; - { - Index = index; - } - /// <summary> - /// Angle of the linear gradient - /// </summary> - public double Degree - { - get - { - return ((ExcelGradientFillXml)_styles.Fills[Index]).Degree; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.GradientFill, eStyleProperty.GradientDegree, value, _positionID, _address)); - } - } - /// <summary> - /// Linear or Path gradient - /// </summary> - public ExcelFillGradientType Type - { - get - { - return ((ExcelGradientFillXml)_styles.Fills[Index]).Type; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.GradientFill, eStyleProperty.GradientType, value, _positionID, _address)); - } - } - /// <summary> - /// Specifies in percentage format(from the top to the bottom) the position of the top edge of the inner rectangle (color 1). For top, 0 means the top edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell. (applies to From Corner and From Center gradients). - /// </summary> - public double Top - { - get - { - return ((ExcelGradientFillXml)_styles.Fills[Index]).Top; - } - set - { - if (value < 0 | value > 1) - { - throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); - } - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.GradientFill, eStyleProperty.GradientTop, value, _positionID, _address)); - } - } - /// <summary> - /// Specifies in percentage format (from the top to the bottom) the position of the bottom edge of the inner rectangle (color 1). For bottom, 0 means the bottom edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell. - /// </summary> - public double Bottom - { - get - { - return ((ExcelGradientFillXml)_styles.Fills[Index]).Bottom; - } - set - { - if (value < 0 | value > 1) - { - throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); - } - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.GradientFill, eStyleProperty.GradientBottom, value, _positionID, _address)); - } - } - /// <summary> - /// Specifies in percentage format (from the left to the right) the position of the left edge of the inner rectangle (color 1). For left, 0 means the left edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients). - /// </summary> - public double Left - { - get - { - return ((ExcelGradientFillXml)_styles.Fills[Index]).Left; - } - set - { - if (value < 0 | value > 1) - { - throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); - } - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.GradientFill, eStyleProperty.GradientLeft, value, _positionID, _address)); - } - } - /// <summary> - /// Specifies in percentage format (from the left to the right) the position of the right edge of the inner rectangle (color 1). For right, 0 means the right edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients). - /// </summary> - public double Right - { - get - { - return ((ExcelGradientFillXml)_styles.Fills[Index]).Right; - } - set - { - if (value < 0 | value > 1) - { - throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); - } - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.GradientFill, eStyleProperty.GradientRight, value, _positionID, _address)); - } - } - ExcelColor _gradientColor1 = null; - /// <summary> - /// Gradient Color 1 - /// </summary> - public ExcelColor Color1 - { - get - { - if (_gradientColor1 == null) - { - _gradientColor1 = new ExcelColor(_styles, _ChangedEvent, _positionID, _address, eStyleClass.FillGradientColor1, this); - } - return _gradientColor1; +/// <summary> +/// The background fill of a cell +/// </summary> +public class ExcelGradientFill : StyleBase { + internal ExcelGradientFill( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int positionId, + string address, + int index) + : base(styles, changedEvent, positionId, address) { + Index = index; + } - } - } - ExcelColor _gradientColor2 = null; - /// <summary> - /// Gradient Color 2 - /// </summary> - public ExcelColor Color2 - { - get - { - if (_gradientColor2 == null) - { - _gradientColor2 = new ExcelColor(_styles, _ChangedEvent, _positionID, _address, eStyleClass.FillGradientColor2, this); - } - return _gradientColor2; + /// <summary> + /// Angle of the linear gradient + /// </summary> + public double Degree { + get => ((ExcelGradientFillXml)_styles.Fills[Index]).Degree; + set => + _ChangedEvent( + this, + new( + eStyleClass.GradientFill, + eStyleProperty.GradientDegree, + value, + _positionID, + _address)); + } - } - } - internal override string Id - { - get { return Degree.ToString() + Type + Color1.Id + Color2.Id + Top.ToString() + Bottom.ToString() + Left.ToString() + Right.ToString(); } - } + /// <summary> + /// Linear or Path gradient + /// </summary> + public ExcelFillGradientType Type { + get => ((ExcelGradientFillXml)_styles.Fills[Index]).Type; + set => + _ChangedEvent( + this, + new(eStyleClass.GradientFill, eStyleProperty.GradientType, value, _positionID, _address)); + } + + /// <summary> + /// Specifies in percentage format(from the top to the bottom) the position of the top edge of the inner rectangle (color 1). For top, 0 means the top edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell. (applies to From Corner and From Center gradients). + /// </summary> + public double Top { + get => ((ExcelGradientFillXml)_styles.Fills[Index]).Top; + set { + if (value < 0 | value > 1) { + throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); + } + _ChangedEvent( + this, + new(eStyleClass.GradientFill, eStyleProperty.GradientTop, value, _positionID, _address)); } + } + + /// <summary> + /// Specifies in percentage format (from the top to the bottom) the position of the bottom edge of the inner rectangle (color 1). For bottom, 0 means the bottom edge of the inner rectangle is on the top edge of the cell, and 1 means it is on the bottom edge of the cell. + /// </summary> + public double Bottom { + get => ((ExcelGradientFillXml)_styles.Fills[Index]).Bottom; + set { + if (value < 0 | value > 1) { + throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); + } + _ChangedEvent( + this, + new( + eStyleClass.GradientFill, + eStyleProperty.GradientBottom, + value, + _positionID, + _address)); + } + } + + /// <summary> + /// Specifies in percentage format (from the left to the right) the position of the left edge of the inner rectangle (color 1). For left, 0 means the left edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients). + /// </summary> + public double Left { + get => ((ExcelGradientFillXml)_styles.Fills[Index]).Left; + set { + if (value < 0 | value > 1) { + throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); + } + _ChangedEvent( + this, + new(eStyleClass.GradientFill, eStyleProperty.GradientLeft, value, _positionID, _address)); + } + } + + /// <summary> + /// Specifies in percentage format (from the left to the right) the position of the right edge of the inner rectangle (color 1). For right, 0 means the right edge of the inner rectangle is on the left edge of the cell, and 1 means it is on the right edge of the cell. (applies to From Corner and From Center gradients). + /// </summary> + public double Right { + get => ((ExcelGradientFillXml)_styles.Fills[Index]).Right; + set { + if (value < 0 | value > 1) { + throw (new ArgumentOutOfRangeException("Value must be between 0 and 1")); + } + _ChangedEvent( + this, + new( + eStyleClass.GradientFill, + eStyleProperty.GradientRight, + value, + _positionID, + _address)); + } + } + + private ExcelColor _gradientColor1; + + /// <summary> + /// Gradient Color 1 + /// </summary> + public ExcelColor Color1 { + get { + if (_gradientColor1 == null) { + _gradientColor1 = new( + _styles, + _ChangedEvent, + _positionID, + _address, + eStyleClass.FillGradientColor1, + this); + } + return _gradientColor1; + } + } + + private ExcelColor _gradientColor2; + + /// <summary> + /// Gradient Color 2 + /// </summary> + public ExcelColor Color2 { + get { + if (_gradientColor2 == null) { + _gradientColor2 = new( + _styles, + _ChangedEvent, + _positionID, + _address, + eStyleClass.FillGradientColor2, + this); + } + return _gradientColor2; + } + } + + internal override string Id => + Degree.ToString() + Type + Color1.Id + Color2.Id + Top + Bottom + Left + Right; }
diff --git a/EPPlus/Style/ExcelNumberFormat.cs b/EPPlus/Style/ExcelNumberFormat.cs index cd2fd40..d1841df 100644 --- a/EPPlus/Style/ExcelNumberFormat.cs +++ b/EPPlus/Style/ExcelNumberFormat.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,216 +13,202 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -using System.Text.RegularExpressions; -using System.Globalization; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// The numberformat of the cell - /// </summary> - public sealed class ExcelNumberFormat : StyleBase - { - internal ExcelNumberFormat(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int PositionID, string Address, int index) : - base(styles, ChangedEvent, PositionID, Address) - { - Index = index; - } - /// <summary> - /// The numeric index fror the format - /// </summary> - public int NumFmtID - { - get - { - return Index; - } - //set - //{ - // _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Numberformat, "NumFmtID", value, _workSheetID, _address)); - //} - } - /// <summary> - /// The numberformat - /// </summary> - public string Format - { - get - { - for(int i=0;i<_styles.NumberFormats.Count;i++) - { - if(Index==_styles.NumberFormats[i].NumFmtId) - { - return _styles.NumberFormats[i].Format; - } - } - return "general"; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Numberformat, eStyleProperty.Format, (string.IsNullOrEmpty(value) ? "General" : value), _positionID, _address)); - } - } +namespace OfficeOpenXml.Style; - internal override string Id - { - get - { - return Format; - } - } - /// <summary> - /// If the numeric format is a build-in from. - /// </summary> - public bool BuildIn { get; private set; } +/// <summary> +/// The numberformat of the cell +/// </summary> +public sealed class ExcelNumberFormat : StyleBase { + internal ExcelNumberFormat( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int positionId, + string address, + int index) + : base(styles, changedEvent, positionId, address) { + Index = index; + } - internal static string GetFromBuildInFromID(int _numFmtId) - { - switch (_numFmtId) - { - case 0: - return "General"; - case 1: - return "0"; - case 2: - return "0.00"; - case 3: - return "#,##0"; - case 4: - return "#,##0.00"; - case 9: - return "0%"; - case 10: - return "0.00%"; - case 11: - return "0.00E+00"; - case 12: - return "# ?/?"; - case 13: - return "# ??/??"; - case 14: - return "mm-dd-yy"; - case 15: - return "d-mmm-yy"; - case 16: - return "d-mmm"; - case 17: - return "mmm-yy"; - case 18: - return "h:mm AM/PM"; - case 19: - return "h:mm:ss AM/PM"; - case 20: - return "h:mm"; - case 21: - return "h:mm:ss"; - case 22: - return "m/d/yy h:mm"; - case 37: - return "#,##0 ;(#,##0)"; - case 38: - return "#,##0 ;[Red](#,##0)"; - case 39: - return "#,##0.00;(#,##0.00)"; - case 40: - return "#,##0.00;[Red](#,##0.00)"; - case 45: - return "mm:ss"; - case 46: - return "[h]:mm:ss"; - case 47: - return "mmss.0"; - case 48: - return "##0.0"; - case 49: - return "@"; - default: - return string.Empty; - } + /// <summary> + /// The numeric index fror the format + /// </summary> + public int NumFmtID => Index; + + //set + //{ + // _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Numberformat, "NumFmtID", value, _workSheetID, _address)); + //} + /// <summary> + /// The numberformat + /// </summary> + public string Format { + get { + for (int i = 0; i < _styles.NumberFormats.Count; i++) { + if (Index == _styles.NumberFormats[i].NumFmtId) { + return _styles.NumberFormats[i].Format; } - internal static int GetFromBuildIdFromFormat(string format) - { - switch (format) - { - case "General": - case "": - return 0; - case "0": - return 1; - case "0.00": - return 2; - case "#,##0": - return 3; - case "#,##0.00": - return 4; - case "0%": - return 9; - case "0.00%": - return 10; - case "0.00E+00": - return 11; - case "# ?/?": - return 12; - case "# ??/??": - return 13; - case "mm-dd-yy": - return 14; - case "d-mmm-yy": - return 15; - case "d-mmm": - return 16; - case "mmm-yy": - return 17; - case "h:mm AM/PM": - return 18; - case "h:mm:ss AM/PM": - return 19; - case "h:mm": - return 20; - case "h:mm:ss": - return 21; - case "m/d/yy h:mm": - return 22; - case "#,##0 ;(#,##0)": - return 37; - case "#,##0 ;[Red](#,##0)": - return 38; - case "#,##0.00;(#,##0.00)": - return 39; - case "#,##0.00;[Red](#,##0.00)": - return 40; - case "mm:ss": - return 45; - case "[h]:mm:ss": - return 46; - case "mmss.0": - return 47; - case "##0.0": - return 48; - case "@": - return 49; - default: - return int.MinValue; - } - } + } + return "general"; } + set => + _ChangedEvent( + this, + new( + eStyleClass.Numberformat, + eStyleProperty.Format, + (string.IsNullOrEmpty(value) ? "General" : value), + _positionID, + _address)); + } + + internal override string Id => Format; + + /// <summary> + /// If the numeric format is a build-in from. + /// </summary> + public bool BuildIn { get; private set; } + + internal static string GetFromBuildInFromId(int numFmtId) { + switch (numFmtId) { + case 0: + return "General"; + case 1: + return "0"; + case 2: + return "0.00"; + case 3: + return "#,##0"; + case 4: + return "#,##0.00"; + case 9: + return "0%"; + case 10: + return "0.00%"; + case 11: + return "0.00E+00"; + case 12: + return "# ?/?"; + case 13: + return "# ??/??"; + case 14: + return "mm-dd-yy"; + case 15: + return "d-mmm-yy"; + case 16: + return "d-mmm"; + case 17: + return "mmm-yy"; + case 18: + return "h:mm AM/PM"; + case 19: + return "h:mm:ss AM/PM"; + case 20: + return "h:mm"; + case 21: + return "h:mm:ss"; + case 22: + return "m/d/yy h:mm"; + case 37: + return "#,##0 ;(#,##0)"; + case 38: + return "#,##0 ;[Red](#,##0)"; + case 39: + return "#,##0.00;(#,##0.00)"; + case 40: + return "#,##0.00;[Red](#,##0.00)"; + case 45: + return "mm:ss"; + case 46: + return "[h]:mm:ss"; + case 47: + return "mmss.0"; + case 48: + return "##0.0"; + case 49: + return "@"; + default: + return string.Empty; + } + } + + internal static int GetFromBuildIdFromFormat(string format) { + switch (format) { + case "General": + case "": + return 0; + case "0": + return 1; + case "0.00": + return 2; + case "#,##0": + return 3; + case "#,##0.00": + return 4; + case "0%": + return 9; + case "0.00%": + return 10; + case "0.00E+00": + return 11; + case "# ?/?": + return 12; + case "# ??/??": + return 13; + case "mm-dd-yy": + return 14; + case "d-mmm-yy": + return 15; + case "d-mmm": + return 16; + case "mmm-yy": + return 17; + case "h:mm AM/PM": + return 18; + case "h:mm:ss AM/PM": + return 19; + case "h:mm": + return 20; + case "h:mm:ss": + return 21; + case "m/d/yy h:mm": + return 22; + case "#,##0 ;(#,##0)": + return 37; + case "#,##0 ;[Red](#,##0)": + return 38; + case "#,##0.00;(#,##0.00)": + return 39; + case "#,##0.00;[Red](#,##0.00)": + return 40; + case "mm:ss": + return 45; + case "[h]:mm:ss": + return 46; + case "mmss.0": + return 47; + case "##0.0": + return 48; + case "@": + return 49; + default: + return int.MinValue; + } + } }
diff --git a/EPPlus/Style/ExcelParagraph.cs b/EPPlus/Style/ExcelParagraph.cs index ef745af..a758a83 100644 --- a/EPPlus/Style/ExcelParagraph.cs +++ b/EPPlus/Style/ExcelParagraph.cs
@@ -13,55 +13,48 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; + using System.Xml; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Handels paragraph text - /// </summary> - public sealed class ExcelParagraph : ExcelTextFont - { - public ExcelParagraph(XmlNamespaceManager ns, XmlNode rootNode, string path, string[] schemaNodeOrder) : - base(ns, rootNode, path + "a:rPr", schemaNodeOrder) - { +namespace OfficeOpenXml.Style; - } - const string TextPath = "../a:t"; - /// <summary> - /// Text - /// </summary> - public string Text - { - get - { - return GetXmlNodeString(TextPath); - } - set - { - CreateTopNode(); - SetXmlNodeString(TextPath, value); - } +/// <summary> +/// Handels paragraph text +/// </summary> +public sealed class ExcelParagraph : ExcelTextFont { + public ExcelParagraph( + XmlNamespaceManager ns, + XmlNode rootNode, + string path, + string[] schemaNodeOrder) + : base(ns, rootNode, path + "a:rPr", schemaNodeOrder) {} - } + private const string _textPath = "../a:t"; + + /// <summary> + /// Text + /// </summary> + public string Text { + get => GetXmlNodeString(_textPath); + set { + CreateTopNode(); + SetXmlNodeString(_textPath, value); } + } }
diff --git a/EPPlus/Style/ExcelParagraphCollection.cs b/EPPlus/Style/ExcelParagraphCollection.cs index 7049162..8c96724 100644 --- a/EPPlus/Style/ExcelParagraphCollection.cs +++ b/EPPlus/Style/ExcelParagraphCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,165 +13,133 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; + +using System.Collections; using System.Collections.Generic; using System.Text; using System.Xml; -using OfficeOpenXml.Drawing; -using System.Drawing; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// A collection of Paragraph objects - /// </summary> - public class ExcelParagraphCollection : XmlHelper, IEnumerable<ExcelParagraph> - { - List<ExcelParagraph> _list = new List<ExcelParagraph>(); - string _path; - internal ExcelParagraphCollection(XmlNamespaceManager ns, XmlNode topNode, string path, string[] schemaNodeOrder) : - base(ns, topNode) - { - var nl = topNode.SelectNodes(path + "/a:r", NameSpaceManager); - SchemaNodeOrder = schemaNodeOrder; - if (nl != null) - { - foreach (XmlNode n in nl) - { - _list.Add(new ExcelParagraph(ns, n, "",schemaNodeOrder)); - } - } - _path = path; - } - public ExcelParagraph this[int Index] - { - get - { - return _list[Index]; - } - } - public int Count - { - get - { - return _list.Count; - } - } - /// <summary> - /// Add a rich text string - /// </summary> - /// <param name="Text">The text to add</param> - /// <returns></returns> - public ExcelParagraph Add(string Text) - { - XmlDocument doc; - if (TopNode is XmlDocument) - { - doc = TopNode as XmlDocument; - } - else - { - doc = TopNode.OwnerDocument; - } - XmlNode parentNode=TopNode.SelectSingleNode(_path, NameSpaceManager); - if (parentNode == null) - { - CreateNode(_path); - parentNode = TopNode.SelectSingleNode(_path, NameSpaceManager); - } - - var node = doc.CreateElement("a", "r", ExcelPackage.schemaDrawings); - parentNode.AppendChild(node); - var childNode = doc.CreateElement("a", "rPr", ExcelPackage.schemaDrawings); - node.AppendChild(childNode); - var rt = new ExcelParagraph(NameSpaceManager, node, "", SchemaNodeOrder); - rt.ComplexFont = "Calibri"; - rt.LatinFont = "Calibri"; - rt.Size = 11; +namespace OfficeOpenXml.Style; - rt.Text = Text; - _list.Add(rt); - return rt; - } - public void Clear() - { - _list.Clear(); - TopNode.RemoveAll(); - } - public void RemoveAt(int Index) - { - var node = _list[Index].TopNode; - while (node != null && node.Name != "a:r") - { - node = node.ParentNode; - } - node.ParentNode.RemoveChild(node); - _list.RemoveAt(Index); - } - public void Remove(ExcelRichText Item) - { - TopNode.RemoveChild(Item.TopNode); - } - public string Text - { - get - { - StringBuilder sb = new StringBuilder(); - foreach (var item in _list) - { - sb.Append(item.Text); - } - return sb.ToString(); - } - set - { - if (Count == 0) - { - Add(value); - } - else - { - this[0].Text = value; - int count = Count; - for (int ix = Count-1; ix > 0; ix--) - { - RemoveAt(ix); - } - } - } - } - #region IEnumerable<ExcelRichText> Members +/// <summary> +/// A collection of Paragraph objects +/// </summary> +public class ExcelParagraphCollection : XmlHelper, IEnumerable<ExcelParagraph> { + private List<ExcelParagraph> _list = new(); + private string _path; - IEnumerator<ExcelParagraph> IEnumerable<ExcelParagraph>.GetEnumerator() - { - return _list.GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _list.GetEnumerator(); - } - - #endregion + internal ExcelParagraphCollection( + XmlNamespaceManager ns, + XmlNode topNode, + string path, + string[] schemaNodeOrder) + : base(ns, topNode) { + var nl = topNode.SelectNodes(path + "/a:r", NameSpaceManager); + SchemaNodeOrder = schemaNodeOrder; + if (nl != null) { + foreach (XmlNode n in nl) { + _list.Add(new(ns, n, "", schemaNodeOrder)); + } } + _path = path; + } + + public ExcelParagraph this[int index] => _list[index]; + + public int Count => _list.Count; + + /// <summary> + /// Add a rich text string + /// </summary> + /// <param name="text">The text to add</param> + /// <returns></returns> + public ExcelParagraph Add(string text) { + XmlDocument doc; + if (TopNode is XmlDocument) { + doc = TopNode as XmlDocument; + } else { + doc = TopNode.OwnerDocument; + } + XmlNode parentNode = TopNode.SelectSingleNode(_path, NameSpaceManager); + if (parentNode == null) { + CreateNode(_path); + parentNode = TopNode.SelectSingleNode(_path, NameSpaceManager); + } + + var node = doc.CreateElement("a", "r", ExcelPackage._schemaDrawings); + parentNode.AppendChild(node); + var childNode = doc.CreateElement("a", "rPr", ExcelPackage._schemaDrawings); + node.AppendChild(childNode); + var rt = new ExcelParagraph(NameSpaceManager, node, "", SchemaNodeOrder); + rt.ComplexFont = "Calibri"; + rt.LatinFont = "Calibri"; + rt.Size = 11; + + rt.Text = text; + _list.Add(rt); + return rt; + } + + public void Clear() { + _list.Clear(); + TopNode.RemoveAll(); + } + + public void RemoveAt(int index) { + var node = _list[index].TopNode; + while (node != null && node.Name != "a:r") { + node = node.ParentNode; + } + node.ParentNode.RemoveChild(node); + _list.RemoveAt(index); + } + + public void Remove(ExcelRichText item) { + TopNode.RemoveChild(item.TopNode); + } + + public string Text { + get { + StringBuilder sb = new StringBuilder(); + foreach (var item in _list) { + sb.Append(item.Text); + } + return sb.ToString(); + } + set { + if (Count == 0) { + Add(value); + } else { + this[0].Text = value; + int count = Count; + for (int ix = Count - 1; ix > 0; ix--) { + RemoveAt(ix); + } + } + } + } + + IEnumerator<ExcelParagraph> IEnumerable<ExcelParagraph>.GetEnumerator() { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _list.GetEnumerator(); + } }
diff --git a/EPPlus/Style/ExcelRichText.cs b/EPPlus/Style/ExcelRichText.cs index bc74fa6..2207656 100644 --- a/EPPlus/Style/ExcelRichText.cs +++ b/EPPlus/Style/ExcelRichText.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 @@ -31,291 +31,277 @@ * Richard Tallent Fix inadvertent removal of XML node 2012-10-31 * Richard Tallent Remove VertAlign node if no alignment specified 2012-10-31 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; using System.Drawing; using System.Globalization; +using System.Xml; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// A richtext part - /// </summary> - public class ExcelRichText : XmlHelper - { - internal ExcelRichText(XmlNamespaceManager ns, XmlNode topNode, ExcelRichTextCollection collection) : - base(ns, topNode) - { - SchemaNodeOrder=new string[] {"rPr", "t", "b", "i","strike", "u", "vertAlign" , "sz", "color", "rFont", "family", "scheme", "charset"}; - _collection = collection; - } - internal delegate void CallbackDelegate(); - CallbackDelegate _callback; - internal void SetCallback(CallbackDelegate callback) - { - _callback=callback; - } - const string TEXT_PATH="d:t"; - /// <summary> - /// The text - /// </summary> - public string Text - { +namespace OfficeOpenXml.Style; - get - { - // Bug 15151 - if (TopNode.Name == "t") - return TopNode.InnerText; - else - return GetXmlNodeString(TEXT_PATH); - } - set - { - _collection.ConvertRichtext(); - // Don't remove if blank -- setting a blank rich text value on a node is common, - // for example when applying both bold and italic to text. - SetXmlNodeString(TEXT_PATH, value, false); - if (PreserveSpace) - { - XmlElement elem = TopNode.SelectSingleNode(TEXT_PATH, NameSpaceManager) as XmlElement; - elem.SetAttribute("xml:space", "preserve"); - } - if (_callback != null) _callback(); - } - } - /// <summary> - /// Preserves whitespace. Default true - /// </summary> - public bool PreserveSpace - { - get - { - XmlElement elem = TopNode.SelectSingleNode(TEXT_PATH, NameSpaceManager) as XmlElement; - if (elem != null) - { - return elem.GetAttribute("xml:space")=="preserve"; - } - return false; - } - set - { - _collection.ConvertRichtext(); - XmlElement elem = TopNode.SelectSingleNode(TEXT_PATH, NameSpaceManager) as XmlElement; - if (elem != null) - { - if (value) - { - elem.SetAttribute("xml:space", "preserve"); - } - else - { - elem.RemoveAttribute("xml:space"); - } - } - if (_callback != null) _callback(); - } - } - const string BOLD_PATH = "d:rPr/d:b"; - /// <summary> - /// Bold text - /// </summary> - public bool Bold - { - get - { - return ExistNode(BOLD_PATH); - } - set - { - _collection.ConvertRichtext(); - if (value) - { - CreateNode(BOLD_PATH); - } - else - { - DeleteNode(BOLD_PATH); - } - if(_callback!=null) _callback(); - } - } - const string ITALIC_PATH = "d:rPr/d:i"; - /// <summary> - /// Italic text - /// </summary> - public bool Italic - { - get - { - //return GetXmlNodeBool(ITALIC_PATH, false); - return ExistNode(ITALIC_PATH); - } - set - { - _collection.ConvertRichtext(); - if (value) - { - CreateNode(ITALIC_PATH); - } - else - { - DeleteNode(ITALIC_PATH); - } - if (_callback != null) _callback(); - } - } - const string STRIKE_PATH = "d:rPr/d:strike"; - /// <summary> - /// Strike-out text - /// </summary> - public bool Strike - { - get - { - return ExistNode(STRIKE_PATH); - } - set - { - _collection.ConvertRichtext(); - if (value) - { - CreateNode(STRIKE_PATH); - } - else - { - DeleteNode(STRIKE_PATH); - } - if (_callback != null) _callback(); - } - } - const string UNDERLINE_PATH = "d:rPr/d:u"; - /// <summary> - /// Underlined text - /// </summary> - public bool UnderLine - { - get - { - return ExistNode(UNDERLINE_PATH); - } - set - { - _collection.ConvertRichtext(); - if (value) - { - CreateNode(UNDERLINE_PATH); - } - else - { - DeleteNode(UNDERLINE_PATH); - } - if (_callback != null) _callback(); - } - } +/// <summary> +/// A richtext part +/// </summary> +public class ExcelRichText : XmlHelper { + internal ExcelRichText( + XmlNamespaceManager ns, + XmlNode topNode, + ExcelRichTextCollection collection) + : base(ns, topNode) { + SchemaNodeOrder = new[] { + "rPr", + "t", + "b", + "i", + "strike", + "u", + "vertAlign", + "sz", + "color", + "rFont", + "family", + "scheme", + "charset", + }; + _collection = collection; + } - const string VERT_ALIGN_PATH = "d:rPr/d:vertAlign/@val"; - /// <summary> - /// Vertical Alignment - /// </summary> - public ExcelVerticalAlignmentFont VerticalAlign - { - get - { - string v=GetXmlNodeString(VERT_ALIGN_PATH); - if(v=="") - { - return ExcelVerticalAlignmentFont.None; - } - else - { - try - { - return (ExcelVerticalAlignmentFont)Enum.Parse(typeof(ExcelVerticalAlignmentFont), v, true); - } - catch - { - return ExcelVerticalAlignmentFont.None; - } - } - } - set - { - _collection.ConvertRichtext(); - if (value == ExcelVerticalAlignmentFont.None) - { - // If Excel 2010 encounters a vertical align value of blank, it will not load - // the spreadsheet. So if None is specified, delete the node, it will be - // recreated if a new value is applied later. - DeleteNode(VERT_ALIGN_PATH); - } else { - SetXmlNodeString(VERT_ALIGN_PATH, value.ToString().ToLowerInvariant()); - } - if (_callback != null) _callback(); - } - } - const string SIZE_PATH = "d:rPr/d:sz/@val"; - /// <summary> - /// Font size - /// </summary> - public float Size - { - get - { - return Convert.ToSingle(GetXmlNodeDecimal(SIZE_PATH)); - } - set - { - _collection.ConvertRichtext(); - SetXmlNodeString(SIZE_PATH, value.ToString(CultureInfo.InvariantCulture)); - if (_callback != null) _callback(); - } - } - const string FONT_PATH = "d:rPr/d:rFont/@val"; - /// <summary> - /// Name of the font - /// </summary> - public string FontName - { - get - { - return GetXmlNodeString(FONT_PATH); - } - set - { - _collection.ConvertRichtext(); - SetXmlNodeString(FONT_PATH, value); - if (_callback != null) _callback(); - } - } - const string COLOR_PATH = "d:rPr/d:color/@rgb"; - /// <summary> - /// Text color - /// </summary> - public Color Color - { - get - { - string col = GetXmlNodeString(COLOR_PATH); - if (col == "") - { - return Color.Empty; - } - else - { - return Color.FromArgb(int.Parse(col, System.Globalization.NumberStyles.AllowHexSpecifier)); - } - } - set - { - _collection.ConvertRichtext(); - SetXmlNodeString(COLOR_PATH, value.ToArgb().ToString("X")/*.Substring(2, 6)*/); - if (_callback != null) _callback(); - } - } + internal delegate void CallbackDelegate(); - public ExcelRichTextCollection _collection { get; set; } + private CallbackDelegate _callback; + + internal void SetCallback(CallbackDelegate callback) { + _callback = callback; + } + + private const string _textPath = "d:t"; + + /// <summary> + /// The text + /// </summary> + public string Text { + get { + // Bug 15151 + if (TopNode.Name == "t") { + return TopNode.InnerText; + } + return GetXmlNodeString(_textPath); } + set { + _collection.ConvertRichtext(); + // Don't remove if blank -- setting a blank rich text value on a node is common, + // for example when applying both bold and italic to text. + SetXmlNodeString(_textPath, value, false); + if (PreserveSpace) { + XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement; + elem.SetAttribute("xml:space", "preserve"); + } + if (_callback != null) { + _callback(); + } + } + } + + /// <summary> + /// Preserves whitespace. Default true + /// </summary> + public bool PreserveSpace { + get { + XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement; + if (elem != null) { + return elem.GetAttribute("xml:space") == "preserve"; + } + return false; + } + set { + _collection.ConvertRichtext(); + XmlElement elem = TopNode.SelectSingleNode(_textPath, NameSpaceManager) as XmlElement; + if (elem != null) { + if (value) { + elem.SetAttribute("xml:space", "preserve"); + } else { + elem.RemoveAttribute("xml:space"); + } + } + if (_callback != null) { + _callback(); + } + } + } + + private const string _boldPath = "d:rPr/d:b"; + + /// <summary> + /// Bold text + /// </summary> + public bool Bold { + get => ExistNode(_boldPath); + set { + _collection.ConvertRichtext(); + if (value) { + CreateNode(_boldPath); + } else { + DeleteNode(_boldPath); + } + if (_callback != null) { + _callback(); + } + } + } + + private const string _italicPath = "d:rPr/d:i"; + + /// <summary> + /// Italic text + /// </summary> + public bool Italic { + get => + //return GetXmlNodeBool(ITALIC_PATH, false); + ExistNode(_italicPath); + set { + _collection.ConvertRichtext(); + if (value) { + CreateNode(_italicPath); + } else { + DeleteNode(_italicPath); + } + if (_callback != null) { + _callback(); + } + } + } + + private const string _strikePath = "d:rPr/d:strike"; + + /// <summary> + /// Strike-out text + /// </summary> + public bool Strike { + get => ExistNode(_strikePath); + set { + _collection.ConvertRichtext(); + if (value) { + CreateNode(_strikePath); + } else { + DeleteNode(_strikePath); + } + if (_callback != null) { + _callback(); + } + } + } + + private const string _underlinePath = "d:rPr/d:u"; + + /// <summary> + /// Underlined text + /// </summary> + public bool UnderLine { + get => ExistNode(_underlinePath); + set { + _collection.ConvertRichtext(); + if (value) { + CreateNode(_underlinePath); + } else { + DeleteNode(_underlinePath); + } + if (_callback != null) { + _callback(); + } + } + } + + private const string _vertAlignPath = "d:rPr/d:vertAlign/@val"; + + /// <summary> + /// Vertical Alignment + /// </summary> + public ExcelVerticalAlignmentFont VerticalAlign { + get { + string v = GetXmlNodeString(_vertAlignPath); + if (v == "") { + return ExcelVerticalAlignmentFont.None; + } + try { + return (ExcelVerticalAlignmentFont)Enum.Parse(typeof(ExcelVerticalAlignmentFont), v, true); + } catch { + return ExcelVerticalAlignmentFont.None; + } + } + set { + _collection.ConvertRichtext(); + if (value == ExcelVerticalAlignmentFont.None) { + // If Excel 2010 encounters a vertical align value of blank, it will not load + // the spreadsheet. So if None is specified, delete the node, it will be + // recreated if a new value is applied later. + DeleteNode(_vertAlignPath); + } else { + SetXmlNodeString(_vertAlignPath, value.ToString().ToLowerInvariant()); + } + if (_callback != null) { + _callback(); + } + } + } + + private const string _sizePath = "d:rPr/d:sz/@val"; + + /// <summary> + /// Font size + /// </summary> + public float Size { + get => Convert.ToSingle(GetXmlNodeDecimal(_sizePath)); + set { + _collection.ConvertRichtext(); + SetXmlNodeString(_sizePath, value.ToString(CultureInfo.InvariantCulture)); + if (_callback != null) { + _callback(); + } + } + } + + private const string _fontPath = "d:rPr/d:rFont/@val"; + + /// <summary> + /// Name of the font + /// </summary> + public string FontName { + get => GetXmlNodeString(_fontPath); + set { + _collection.ConvertRichtext(); + SetXmlNodeString(_fontPath, value); + if (_callback != null) { + _callback(); + } + } + } + + private const string _colorPath = "d:rPr/d:color/@rgb"; + + /// <summary> + /// Text color + /// </summary> + public Color Color { + get { + string col = GetXmlNodeString(_colorPath); + if (col == "") { + return Color.Empty; + } + return Color.FromArgb(int.Parse(col, NumberStyles.AllowHexSpecifier)); + } + set { + _collection.ConvertRichtext(); + SetXmlNodeString( + _colorPath, + value + .ToArgb() + .ToString( + "X") /*.Substring(2, 6)*/); + if (_callback != null) { + _callback(); + } + } + } + + public ExcelRichTextCollection _collection { get; set; } }
diff --git a/EPPlus/Style/ExcelRichTextCollection.cs b/EPPlus/Style/ExcelRichTextCollection.cs index c28bf91..496431d 100644 --- a/EPPlus/Style/ExcelRichTextCollection.cs +++ b/EPPlus/Style/ExcelRichTextCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,252 +13,245 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; + +using System.Collections; using System.Collections.Generic; +using System.Drawing; +using System.Globalization; using System.Linq; using System.Text; using System.Xml; -using System.Drawing; -using System.Globalization; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Collection of Richtext objects - /// </summary> - public class ExcelRichTextCollection : XmlHelper, IEnumerable<ExcelRichText> - { - List<ExcelRichText> _list = new List<ExcelRichText>(); - ExcelRangeBase _cells=null; - internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode) : - base(ns, topNode) - { - var nl = topNode.SelectNodes("d:r|d:t", NameSpaceManager); // Bug 15151 - if (nl != null) - { - foreach (XmlNode n in nl) - { - _list.Add(new ExcelRichText(ns, n,this)); - } - } - } - internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode, ExcelRangeBase cells) : - this(ns, topNode) - { - _cells = cells; - } - /// <summary> - /// Collection containing the richtext objects - /// </summary> - /// <param name="Index"></param> - /// <returns></returns> - public ExcelRichText this[int Index] - { - get - { - var item=_list[Index]; - if(_cells!=null) item.SetCallback(UpdateCells); - return item; - } - } - /// <summary> - /// Items in the list - /// </summary> - public int Count - { - get - { - return _list.Count; - } - } - /// <summary> - /// Add a rich text string - /// </summary> - /// <param name="Text">The text to add</param> - /// <returns></returns> - public ExcelRichText Add(string Text) - { - ConvertRichtext(); - XmlDocument doc; - if (TopNode is XmlDocument) - { - doc = TopNode as XmlDocument; - } - else - { - doc = TopNode.OwnerDocument; - } - var node = doc.CreateElement("d", "r", ExcelPackage.schemaMain); - TopNode.AppendChild(node); - var rt = new ExcelRichText(NameSpaceManager, node, this); - if (_list.Count > 0) - { - ExcelRichText prevItem = _list[_list.Count - 1]; - rt.FontName = prevItem.FontName; - rt.Size = prevItem.Size; - if (prevItem.Color.IsEmpty) - { - rt.Color = Color.Black; - } - else - { - rt.Color = prevItem.Color; - } - rt.PreserveSpace = rt.PreserveSpace; - rt.Bold = prevItem.Bold; - rt.Italic = prevItem.Italic; - rt.UnderLine = prevItem.UnderLine; - } - else if (_cells == null) - { - rt.FontName = "Calibri"; - rt.Size = 11; - } - else - { - var style = _cells.Offset(0, 0).Style; - rt.FontName = style.Font.Name; - rt.Size = style.Font.Size; - rt.Bold = style.Font.Bold; - rt.Italic = style.Font.Italic; - _cells.IsRichText = true; - } - rt.Text = Text; - rt.PreserveSpace = true; - if(_cells!=null) - { - rt.SetCallback(UpdateCells); - UpdateCells(); - } - _list.Add(rt); - return rt; - } +namespace OfficeOpenXml.Style; - internal void ConvertRichtext() - { - if (_cells == null) return; - var isRt = _cells.Worksheet._flags.GetFlagValue(_cells._fromRow, _cells._fromCol, CellFlags.RichText); - if (Count == 1 && isRt == false) - { - _cells.Worksheet._flags.SetFlagValue(_cells._fromRow, _cells._fromCol, true, CellFlags.RichText); - var s = _cells.Worksheet._styles.GetValue(_cells._fromRow, _cells._fromCol); - //var fnt = cell.Style.Font; - var fnt = _cells.Worksheet.Workbook.Styles.GetStyleObject(s, _cells.Worksheet.PositionID, ExcelAddressBase.GetAddress(_cells._fromRow, _cells._fromCol)).Font; - this[0].PreserveSpace = true; - this[0].Bold = fnt.Bold; - this[0].FontName = fnt.Name; - this[0].Italic = fnt.Italic; - this[0].Size = fnt.Size; - this[0].UnderLine = fnt.UnderLine; +/// <summary> +/// Collection of Richtext objects +/// </summary> +public class ExcelRichTextCollection : XmlHelper, IEnumerable<ExcelRichText> { + private List<ExcelRichText> _list = new(); + private ExcelRangeBase _cells; - int hex; - if (fnt.Color.Rgb != "" && int.TryParse(fnt.Color.Rgb, NumberStyles.HexNumber, null, out hex)) - { - this[0].Color = Color.FromArgb(hex); - } - } - } - internal void UpdateCells() - { - _cells.SetValueRichText(TopNode.InnerXml); - } - /// <summary> - /// Clear the collection - /// </summary> - public void Clear() - { - _list.Clear(); - TopNode.RemoveAll(); - UpdateCells(); - if (_cells != null) _cells.IsRichText = false; - } - /// <summary> - /// Removes an item at the specific index - /// </summary> - /// <param name="Index"></param> - public void RemoveAt(int Index) - { - TopNode.RemoveChild(_list[Index].TopNode); - _list.RemoveAt(Index); - if (_cells != null && _list.Count==0) _cells.IsRichText = false; - } - /// <summary> - /// Removes an item - /// </summary> - /// <param name="Item"></param> - public void Remove(ExcelRichText Item) - { - TopNode.RemoveChild(Item.TopNode); - _list.Remove(Item); - if (_cells != null && _list.Count == 0) _cells.IsRichText = false; - } - //public void Insert(int index, string Text) - //{ - // _list.Insert(index, item); - //} - - /// <summary> - /// The text - /// </summary> - public string Text - { - get - { - StringBuilder sb=new StringBuilder(); - foreach (var item in _list) - { - sb.Append(item.Text); - } - return sb.ToString(); - } - set - { - if (Count == 0) - { - Add(value); - } - else - { - this[0].Text = value; - for (int ix = 1; ix < Count; ix++) - { - RemoveAt(ix); - } - } - } - } - #region IEnumerable<ExcelRichText> Members - - IEnumerator<ExcelRichText> IEnumerable<ExcelRichText>.GetEnumerator() - { - return _list.Select(x => { x.SetCallback(UpdateCells); return x; }).GetEnumerator(); - } - - #endregion - - #region IEnumerable Members - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _list.Select(x => { x.SetCallback(UpdateCells); return x; }).GetEnumerator(); - } - - #endregion + internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode) + : base(ns, topNode) { + var nl = topNode.SelectNodes("d:r|d:t", NameSpaceManager); // Bug 15151 + if (nl != null) { + foreach (XmlNode n in nl) { + _list.Add(new(ns, n, this)); + } } + } + + internal ExcelRichTextCollection(XmlNamespaceManager ns, XmlNode topNode, ExcelRangeBase cells) + : this(ns, topNode) { + _cells = cells; + } + + /// <summary> + /// Collection containing the richtext objects + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public ExcelRichText this[int index] { + get { + var item = _list[index]; + if (_cells != null) { + item.SetCallback(UpdateCells); + } + return item; + } + } + + /// <summary> + /// Items in the list + /// </summary> + public int Count => _list.Count; + + /// <summary> + /// Add a rich text string + /// </summary> + /// <param name="text">The text to add</param> + /// <returns></returns> + public ExcelRichText Add(string text) { + ConvertRichtext(); + XmlDocument doc; + if (TopNode is XmlDocument) { + doc = TopNode as XmlDocument; + } else { + doc = TopNode.OwnerDocument; + } + var node = doc.CreateElement("d", "r", ExcelPackage._schemaMain); + TopNode.AppendChild(node); + var rt = new ExcelRichText(NameSpaceManager, node, this); + if (_list.Count > 0) { + ExcelRichText prevItem = _list[_list.Count - 1]; + rt.FontName = prevItem.FontName; + rt.Size = prevItem.Size; + if (prevItem.Color.IsEmpty) { + rt.Color = Color.Black; + } else { + rt.Color = prevItem.Color; + } + rt.PreserveSpace = rt.PreserveSpace; + rt.Bold = prevItem.Bold; + rt.Italic = prevItem.Italic; + rt.UnderLine = prevItem.UnderLine; + } else if (_cells == null) { + rt.FontName = "Calibri"; + rt.Size = 11; + } else { + var style = _cells.Offset(0, 0).Style; + rt.FontName = style.Font.Name; + rt.Size = style.Font.Size; + rt.Bold = style.Font.Bold; + rt.Italic = style.Font.Italic; + _cells.IsRichText = true; + } + rt.Text = text; + rt.PreserveSpace = true; + if (_cells != null) { + rt.SetCallback(UpdateCells); + UpdateCells(); + } + _list.Add(rt); + return rt; + } + + internal void ConvertRichtext() { + if (_cells == null) { + return; + } + var isRt = _cells.Worksheet._flags.GetFlagValue( + _cells._fromRow, + _cells._fromCol, + CellFlags.RichText); + if (Count == 1 && isRt == false) { + _cells.Worksheet._flags.SetFlagValue( + _cells._fromRow, + _cells._fromCol, + true, + CellFlags.RichText); + var s = _cells.Worksheet._styles.GetValue(_cells._fromRow, _cells._fromCol); + //var fnt = cell.Style.Font; + var fnt = _cells.Worksheet.Workbook.Styles + .GetStyleObject( + s, + _cells.Worksheet.PositionID, + ExcelCellBase.GetAddress(_cells._fromRow, _cells._fromCol)) + .Font; + this[0].PreserveSpace = true; + this[0].Bold = fnt.Bold; + this[0].FontName = fnt.Name; + this[0].Italic = fnt.Italic; + this[0].Size = fnt.Size; + this[0].UnderLine = fnt.UnderLine; + + int hex; + if (fnt.Color.Rgb != "" + && int.TryParse(fnt.Color.Rgb, NumberStyles.HexNumber, null, out hex)) { + this[0].Color = Color.FromArgb(hex); + } + } + } + + internal void UpdateCells() { + _cells.SetValueRichText(TopNode.InnerXml); + } + + /// <summary> + /// Clear the collection + /// </summary> + public void Clear() { + _list.Clear(); + TopNode.RemoveAll(); + UpdateCells(); + if (_cells != null) { + _cells.IsRichText = false; + } + } + + /// <summary> + /// Removes an item at the specific index + /// </summary> + /// <param name="index"></param> + public void RemoveAt(int index) { + TopNode.RemoveChild(_list[index].TopNode); + _list.RemoveAt(index); + if (_cells != null && _list.Count == 0) { + _cells.IsRichText = false; + } + } + + /// <summary> + /// Removes an item + /// </summary> + /// <param name="item"></param> + public void Remove(ExcelRichText item) { + TopNode.RemoveChild(item.TopNode); + _list.Remove(item); + if (_cells != null && _list.Count == 0) { + _cells.IsRichText = false; + } + } + + //public void Insert(int index, string Text) + //{ + // _list.Insert(index, item); + //} + + /// <summary> + /// The text + /// </summary> + public string Text { + get { + StringBuilder sb = new StringBuilder(); + foreach (var item in _list) { + sb.Append(item.Text); + } + return sb.ToString(); + } + set { + if (Count == 0) { + Add(value); + } else { + this[0].Text = value; + for (int ix = 1; ix < Count; ix++) { + RemoveAt(ix); + } + } + } + } + + IEnumerator<ExcelRichText> IEnumerable<ExcelRichText>.GetEnumerator() { + return _list + .Select(x => { + x.SetCallback(UpdateCells); + return x; + }) + .GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _list + .Select(x => { + x.SetCallback(UpdateCells); + return x; + }) + .GetEnumerator(); + } }
diff --git a/EPPlus/Style/ExcelRichTextHtmlUtility.cs b/EPPlus/Style/ExcelRichTextHtmlUtility.cs index 8274545..83e37c6 100644 --- a/EPPlus/Style/ExcelRichTextHtmlUtility.cs +++ b/EPPlus/Style/ExcelRichTextHtmlUtility.cs
@@ -13,188 +13,175 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Richard Tallent Initial Release 2012-08-13 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; using System.Text.RegularExpressions; +using System.Web; -namespace OfficeOpenXml.Style -{ - public class ExcelRichTextHtmlUtility - { +namespace OfficeOpenXml.Style; - /// <summary> - /// Provides basic HTML support by converting well-behaved HTML into appropriate RichText blocks. - /// HTML support is limited, and does not include font colors, sizes, or typefaces at this time, - /// and also does not support CSS style attributes. It does support line breaks using the BR tag. - /// - /// This routine parses the HTML into RegEx pairings of an HTML tag and the text until the NEXT - /// tag (if any). The tag is parsed to determine the setting change to be applied to the last set - /// of settings, and if the text is not blank, a new block is added to rich text. - /// </summary> - /// <param name="range"></param> - /// <param name="html">The HTML to parse into RichText</param> - /// <param name="defaultFontName"></param> - /// <param name="defaultFontSize"></param> +public class ExcelRichTextHtmlUtility { + /// <summary> + /// Provides basic HTML support by converting well-behaved HTML into appropriate RichText blocks. + /// HTML support is limited, and does not include font colors, sizes, or typefaces at this time, + /// and also does not support CSS style attributes. It does support line breaks using the BR tag. + /// + /// This routine parses the HTML into RegEx pairings of an HTML tag and the text until the NEXT + /// tag (if any). The tag is parsed to determine the setting change to be applied to the last set + /// of settings, and if the text is not blank, a new block is added to rich text. + /// </summary> + /// <param name="range"></param> + /// <param name="html">The HTML to parse into RichText</param> + /// <param name="defaultFontName"></param> + /// <param name="defaultFontSize"></param> + public static void SetRichTextFromHtml( + ExcelRange range, + string html, + string defaultFontName, + short defaultFontSize) { + // Reset the cell value, just in case there is an existing RichText value. + range.Value = ""; - public static void SetRichTextFromHtml(ExcelRange range, string html, string defaultFontName, short defaultFontSize) - { - // Reset the cell value, just in case there is an existing RichText value. - range.Value = ""; + // Sanity check for blank values, skips creating Regex objects for performance. + if (String.IsNullOrEmpty(html)) { + range.IsRichText = false; + return; + } - // Sanity check for blank values, skips creating Regex objects for performance. - if (String.IsNullOrEmpty(html)) - { - range.IsRichText = false; - return; - } + // Change all BR tags to line breaks. http://epplus.codeplex.com/discussions/238692/ + // Cells with line breaks aren't necessarily considered rich text, so this is performed + // before parsing the HTML tags. + html = Regex.Replace( + html, + "<br[^>]*>", + "\r\n", + RegexOptions.Compiled | RegexOptions.IgnoreCase); - // Change all BR tags to line breaks. http://epplus.codeplex.com/discussions/238692/ - // Cells with line breaks aren't necessarily considered rich text, so this is performed - // before parsing the HTML tags. - html = System.Text.RegularExpressions.Regex.Replace(html, @"<br[^>]*>", "\r\n", RegexOptions.Compiled | RegexOptions.IgnoreCase); + string tag; + string text; + ExcelRichText thisrt = null; + bool isFirst = true; - string tag; - string text; - ExcelRichText thisrt = null; - bool isFirst = true; + // Get all pairs of legitimate tags and the text between them. This loop will + // only execute if there is at least one start or end tag. + foreach (Match m in Regex.Matches( + html, + @"<(/?[a-z]+)[^<>]*>([\s\S]*?)(?=</?[a-z]+[^<>]*>|$)", + RegexOptions.Compiled | RegexOptions.IgnoreCase)) { + if (isFirst) { + // On the very first match, set up the initial rich text object with + // the defaults for the text BEFORE the match. + range.IsRichText = true; + thisrt = range.RichText.Add(CleanText(html.Substring(0, m.Index))); // May be 0-length + thisrt.Size = defaultFontSize; // Set the default font size + thisrt.FontName = defaultFontName; // Set the default font name + isFirst = false; + } + // Get the tag and the block of text until the NEXT tag or EOS. If there are HTML entities + // encoded, unencode them, they should be passed to RichText as normal characters (other + // than non-breaking spaces, which should be replaced with normal spaces, they break Excel. + tag = m.Groups[1].Captures[0].Value; + text = CleanText(m.Groups[2].Captures[0].Value); - // Get all pairs of legitimate tags and the text between them. This loop will - // only execute if there is at least one start or end tag. - foreach (Match m in System.Text.RegularExpressions.Regex.Matches(html, @"<(/?[a-z]+)[^<>]*>([\s\S]*?)(?=</?[a-z]+[^<>]*>|$)", RegexOptions.Compiled | RegexOptions.IgnoreCase)) - { - if (isFirst) - { - // On the very first match, set up the initial rich text object with - // the defaults for the text BEFORE the match. - range.IsRichText = true; - thisrt = range.RichText.Add(CleanText(html.Substring(0, m.Index))); // May be 0-length - thisrt.Size = defaultFontSize; // Set the default font size - thisrt.FontName = defaultFontName; // Set the default font name - isFirst = false; - } - // Get the tag and the block of text until the NEXT tag or EOS. If there are HTML entities - // encoded, unencode them, they should be passed to RichText as normal characters (other - // than non-breaking spaces, which should be replaced with normal spaces, they break Excel. - tag = m.Groups[1].Captures[0].Value; - text = CleanText(m.Groups[2].Captures[0].Value); + if (thisrt.Text == "") { + // The most recent rich text block wasn't *actually* used last time around, so update + // the text and keep it as the "current" block. This happens with the first block if + // it starts with a tag, and may happen later if tags come one right after the other. + thisrt.Text = text; + } else { + // The current rich text block has some text, so create a new one. RichText.Add() + // automatically applies the settings from the previous block, other than vertical + // alignment. + thisrt = range.RichText.Add(text); + } + // Override the settings based on the current tag, keep all other settings. + SetStyleFromTag(tag, thisrt); + } - if (thisrt.Text == "") - { - // The most recent rich text block wasn't *actually* used last time around, so update - // the text and keep it as the "current" block. This happens with the first block if - // it starts with a tag, and may happen later if tags come one right after the other. - thisrt.Text = text; - } - else - { - // The current rich text block has some text, so create a new one. RichText.Add() - // automatically applies the settings from the previous block, other than vertical - // alignment. - thisrt = range.RichText.Add(text); - } - // Override the settings based on the current tag, keep all other settings. - SetStyleFromTag(tag, thisrt); - } + if (thisrt == null) { + // No HTML tags were found, so treat this as a normal text value. + range.IsRichText = false; + range.Value = CleanText(html); + } else if (String.IsNullOrEmpty(thisrt.Text)) { + // Rich text was found, but the last node contains no text, so remove it. This can happen if, + // say, the end of the string is an end tag or unsupported tag (common). + range.RichText.Remove(thisrt); - if (thisrt == null) - { - // No HTML tags were found, so treat this as a normal text value. - range.IsRichText = false; - range.Value = CleanText(html); - } - else if (String.IsNullOrEmpty(thisrt.Text)) - { - // Rich text was found, but the last node contains no text, so remove it. This can happen if, - // say, the end of the string is an end tag or unsupported tag (common). - range.RichText.Remove(thisrt); + // Failsafe -- the HTML may be just tags, no text, in which case there may be no rich text + // directives that remain. If that is the case, turn off rich text and treat this like a blank + // cell value. + if (range.RichText.Count == 0) { + range.IsRichText = false; + range.Value = ""; + } + } + } - // Failsafe -- the HTML may be just tags, no text, in which case there may be no rich text - // directives that remain. If that is the case, turn off rich text and treat this like a blank - // cell value. - if (range.RichText.Count == 0) - { - range.IsRichText = false; - range.Value = ""; - } + private static void SetStyleFromTag(string tag, ExcelRichText settings) { + switch (tag.ToLower()) { + case "b": + case "strong": + settings.Bold = true; + break; + case "i": + case "em": + settings.Italic = true; + break; + case "u": + settings.UnderLine = true; + break; + case "s": + case "strike": + settings.Strike = true; + break; + case "sup": + settings.VerticalAlign = ExcelVerticalAlignmentFont.Superscript; + break; + case "sub": + settings.VerticalAlign = ExcelVerticalAlignmentFont.Subscript; + break; + case "/b": + case "/strong": + settings.Bold = false; + break; + case "/i": + case "/em": + settings.Italic = false; + break; + case "/u": + settings.UnderLine = false; + break; + case "/s": + case "/strike": + settings.Strike = false; + break; + case "/sup": + case "/sub": + settings.VerticalAlign = ExcelVerticalAlignmentFont.None; + break; + } + } - } - - } - - private static void SetStyleFromTag(string tag, ExcelRichText settings) - { - switch (tag.ToLower()) - { - case "b": - case "strong": - settings.Bold = true; - break; - case "i": - case "em": - settings.Italic = true; - break; - case "u": - settings.UnderLine = true; - break; - case "s": - case "strike": - settings.Strike = true; - break; - case "sup": - settings.VerticalAlign = ExcelVerticalAlignmentFont.Superscript; - break; - case "sub": - settings.VerticalAlign = ExcelVerticalAlignmentFont.Subscript; - break; - case "/b": - case "/strong": - settings.Bold = false; - break; - case "/i": - case "/em": - settings.Italic = false; - break; - case "/u": - settings.UnderLine = false; - break; - case "/s": - case "/strike": - settings.Strike = false; - break; - case "/sup": - case "/sub": - settings.VerticalAlign = ExcelVerticalAlignmentFont.None; - break; - default: - // unsupported HTML, no style change - break; - } - } - - private static string CleanText(string s) - { - // Need to convert HTML entities (named or numbered) into actual Unicode characters - s = System.Web.HttpUtility.HtmlDecode(s); - // Remove any non-breaking spaces, kills Excel - s = s.Replace("\u00A0", " "); - return s; - } - - } + private static string CleanText(string s) { + // Need to convert HTML entities (named or numbered) into actual Unicode characters + s = HttpUtility.HtmlDecode(s); + // Remove any non-breaking spaces, kills Excel + s = s.Replace("\u00A0", " "); + return s; + } }
diff --git a/EPPlus/Style/ExcelStyle.cs b/EPPlus/Style/ExcelStyle.cs index a3edaae..f9ad943 100644 --- a/EPPlus/Style/ExcelStyle.cs +++ b/EPPlus/Style/ExcelStyle.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,240 +13,216 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; using OfficeOpenXml.Style.XmlAccess; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Toplevel class for cell styling - /// </summary> - public sealed class ExcelStyle : StyleBase - { - internal ExcelStyle(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int positionID, string Address, int xfsId) : - base(styles, ChangedEvent, positionID, Address) - { - Index = xfsId; - ExcelXfs xfs; - if (positionID > -1) - { - xfs = _styles.CellXfs[xfsId]; - } - else - { - xfs = _styles.CellStyleXfs[xfsId]; - } - Styles = styles; - PositionID = positionID; - Numberformat = new ExcelNumberFormat(styles, ChangedEvent, PositionID, Address, xfs.NumberFormatId); - Font = new ExcelFont(styles, ChangedEvent, PositionID, Address, xfs.FontId); - Fill = new ExcelFill(styles, ChangedEvent, PositionID, Address, xfs.FillId); - Border = new Border(styles, ChangedEvent, PositionID, Address, xfs.BorderId); - } - /// <summary> - /// Numberformat - /// </summary> - public ExcelNumberFormat Numberformat { get; set; } - /// <summary> - /// Font styling - /// </summary> - public ExcelFont Font { get; set; } - /// <summary> - /// Fill Styling - /// </summary> - public ExcelFill Fill { get; set; } - /// <summary> - /// Border - /// </summary> - public Border Border { get; set; } - /// <summary> - /// The horizontal alignment in the cell - /// </summary> - public ExcelHorizontalAlignment HorizontalAlignment - { - get - { - return _styles.CellXfs[Index].HorizontalAlignment; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.HorizontalAlign, value, _positionID, _address)); - } - } - /// <summary> - /// The vertical alignment in the cell - /// </summary> - public ExcelVerticalAlignment VerticalAlignment - { - get - { - return _styles.CellXfs[Index].VerticalAlignment; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.VerticalAlign, value, _positionID, _address)); - } - } - /// <summary> - /// Wrap the text - /// </summary> - public bool WrapText - { - get - { - return _styles.CellXfs[Index].WrapText; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.WrapText, value, _positionID, _address)); - } - } - /// <summary> - /// Readingorder - /// </summary> - public ExcelReadingOrder ReadingOrder - { - get - { - return _styles.CellXfs[Index].ReadingOrder; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.ReadingOrder, value, _positionID, _address)); - } - } - /// <summary> - /// Shrink the text to fit - /// </summary> - public bool ShrinkToFit - { - get - { - return _styles.CellXfs[Index].ShrinkToFit; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.ShrinkToFit, value, _positionID, _address)); - } - } - /// <summary> - /// The margin between the border and the text - /// </summary> - public int Indent - { - get - { - return _styles.CellXfs[Index].Indent; - } - set - { - if (value <0 || value > 250) - { - throw(new ArgumentOutOfRangeException("Indent must be between 0 and 250")); - } - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.Indent, value, _positionID, _address)); - } - } - /// <summary> - /// Text orientation in degrees. Values range from 0 to 180. - /// </summary> - public int TextRotation - { - get - { - return _styles.CellXfs[Index].TextRotation; - } - set - { - if (value < 0 || value > 180) - { - throw new ArgumentOutOfRangeException("TextRotation out of range."); - } - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.TextRotation, value, _positionID, _address)); - } - } - /// <summary> - /// If true the cell is locked for editing when the sheet is protected - /// <seealso cref="ExcelWorksheet.Protection"/> - /// </summary> - public bool Locked - { - get - { - return _styles.CellXfs[Index].Locked; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.Locked, value, _positionID, _address)); - } - } - /// <summary> - /// If true the formula is hidden when the sheet is protected. - /// <seealso cref="ExcelWorksheet.Protection"/> - /// </summary> - public bool Hidden - { - get - { - return _styles.CellXfs[Index].Hidden; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.Hidden, value, _positionID, _address)); - } - } +namespace OfficeOpenXml.Style; - - const string xfIdPath = "@xfId"; - /// <summary> - /// The index in the style collection - /// </summary> - public int XfId - { - get - { - return _styles.CellXfs[Index].XfId; - } - set - { - _ChangedEvent(this, new StyleChangeEventArgs(eStyleClass.Style, eStyleProperty.XfId, value, _positionID, _address)); - } - } - internal int PositionID - { - get; - set; - } - internal ExcelStyles Styles - { - get; - set; - } - internal override string Id - { - get - { - return Numberformat.Id + "|" + Font.Id + "|" + Fill.Id + "|" + Border.Id + "|" + VerticalAlignment + "|" + HorizontalAlignment + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString() + "|" + XfId.ToString(); - } - } - +/// <summary> +/// Toplevel class for cell styling +/// </summary> +public sealed class ExcelStyle : StyleBase { + internal ExcelStyle( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int positionId, + string address, + int xfsId) + : base(styles, changedEvent, positionId, address) { + Index = xfsId; + ExcelXfs xfs; + if (positionId > -1) { + xfs = _styles.CellXfs[xfsId]; + } else { + xfs = _styles.CellStyleXfs[xfsId]; } + Styles = styles; + PositionID = positionId; + Numberformat = new(styles, changedEvent, PositionID, address, xfs.NumberFormatId); + Font = new(styles, changedEvent, PositionID, address, xfs.FontId); + Fill = new(styles, changedEvent, PositionID, address, xfs.FillId); + Border = new(styles, changedEvent, PositionID, address, xfs.BorderId); + } + + /// <summary> + /// Numberformat + /// </summary> + public ExcelNumberFormat Numberformat { get; set; } + + /// <summary> + /// Font styling + /// </summary> + public ExcelFont Font { get; set; } + + /// <summary> + /// Fill Styling + /// </summary> + public ExcelFill Fill { get; set; } + + /// <summary> + /// Border + /// </summary> + public Border Border { get; set; } + + /// <summary> + /// The horizontal alignment in the cell + /// </summary> + public ExcelHorizontalAlignment HorizontalAlignment { + get => _styles.CellXfs[Index].HorizontalAlignment; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.HorizontalAlign, value, _positionID, _address)); + } + + /// <summary> + /// The vertical alignment in the cell + /// </summary> + public ExcelVerticalAlignment VerticalAlignment { + get => _styles.CellXfs[Index].VerticalAlignment; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.VerticalAlign, value, _positionID, _address)); + } + + /// <summary> + /// Wrap the text + /// </summary> + public bool WrapText { + get => _styles.CellXfs[Index].WrapText; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.WrapText, value, _positionID, _address)); + } + + /// <summary> + /// Readingorder + /// </summary> + public ExcelReadingOrder ReadingOrder { + get => _styles.CellXfs[Index].ReadingOrder; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.ReadingOrder, value, _positionID, _address)); + } + + /// <summary> + /// Shrink the text to fit + /// </summary> + public bool ShrinkToFit { + get => _styles.CellXfs[Index].ShrinkToFit; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.ShrinkToFit, value, _positionID, _address)); + } + + /// <summary> + /// The margin between the border and the text + /// </summary> + public int Indent { + get => _styles.CellXfs[Index].Indent; + set { + if (value < 0 || value > 250) { + throw (new ArgumentOutOfRangeException("Indent must be between 0 and 250")); + } + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.Indent, value, _positionID, _address)); + } + } + + /// <summary> + /// Text orientation in degrees. Values range from 0 to 180. + /// </summary> + public int TextRotation { + get => _styles.CellXfs[Index].TextRotation; + set { + if (value < 0 || value > 180) { + throw new ArgumentOutOfRangeException("TextRotation out of range."); + } + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.TextRotation, value, _positionID, _address)); + } + } + + /// <summary> + /// If true the cell is locked for editing when the sheet is protected + /// <seealso cref="ExcelWorksheet.Protection"/> + /// </summary> + public bool Locked { + get => _styles.CellXfs[Index].Locked; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.Locked, value, _positionID, _address)); + } + + /// <summary> + /// If true the formula is hidden when the sheet is protected. + /// <seealso cref="ExcelWorksheet.Protection"/> + /// </summary> + public bool Hidden { + get => _styles.CellXfs[Index].Hidden; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.Hidden, value, _positionID, _address)); + } + + private const string _xfIdPath = "@xfId"; + + /// <summary> + /// The index in the style collection + /// </summary> + public int XfId { + get => _styles.CellXfs[Index].XfId; + set => + _ChangedEvent( + this, + new(eStyleClass.Style, eStyleProperty.XfId, value, _positionID, _address)); + } + + internal int PositionID { get; set; } + + internal ExcelStyles Styles { get; set; } + + internal override string Id => + Numberformat.Id + + "|" + + Font.Id + + "|" + + Fill.Id + + "|" + + Border.Id + + "|" + + VerticalAlignment + + "|" + + HorizontalAlignment + + "|" + + WrapText + + "|" + + ReadingOrder + + "|" + + XfId; }
diff --git a/EPPlus/Style/ExcelTextFont.cs b/EPPlus/Style/ExcelTextFont.cs index 7af62e3..13b7ae1 100644 --- a/EPPlus/Style/ExcelTextFont.cs +++ b/EPPlus/Style/ExcelTextFont.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,295 +13,263 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Xml; -using OfficeOpenXml.Drawing; using System.Drawing; +using System.Globalization; +using System.Xml; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Linestyle - /// </summary> - public enum eUnderLineType - { - Dash, - DashHeavy, - DashLong, - DashLongHeavy, - Double, - DotDash, - DotDashHeavy, - DotDotDash, - DotDotDashHeavy, - Dotted, - DottedHeavy, - Heavy, - None, - Single, - Wavy, - WavyDbl, - WavyHeavy, - Words - } - /// <summary> - /// Type of font strike - /// </summary> - public enum eStrikeType - { - Double, - No, - Single - } - /// <summary> - /// Used by Rich-text and Paragraphs. - /// </summary> - public class ExcelTextFont : XmlHelper - { - string _path; - XmlNode _rootNode; - internal ExcelTextFont(XmlNamespaceManager namespaceManager, XmlNode rootNode, string path, string[] schemaNodeOrder) - : base(namespaceManager, rootNode) - { - SchemaNodeOrder = schemaNodeOrder; - _rootNode = rootNode; - if (path != "") - { - XmlNode node = rootNode.SelectSingleNode(path, namespaceManager); - if (node != null) - { - TopNode = node; - } - } - _path = path; - } - string _fontLatinPath = "a:latin/@typeface"; - public string LatinFont - { - get - { - return GetXmlNodeString(_fontLatinPath); - } - set - { - CreateTopNode(); - SetXmlNodeString(_fontLatinPath, value); - } - } +namespace OfficeOpenXml.Style; - protected internal void CreateTopNode() - { - if (_path!="" && TopNode == _rootNode) - { - CreateNode(_path); - TopNode = _rootNode.SelectSingleNode(_path, NameSpaceManager); - } - } - string _fontCsPath = "a:cs/@typeface"; - public string ComplexFont - { - get - { - return GetXmlNodeString(_fontCsPath); - } - set - { - CreateTopNode(); - SetXmlNodeString(_fontCsPath, value); - } - } - string _boldPath = "@b"; - public bool Bold - { - get - { - return GetXmlNodeBool(_boldPath); - } - set - { - CreateTopNode(); - SetXmlNodeString(_boldPath, value ? "1" : "0"); - } - } - string _underLinePath = "@u"; - public eUnderLineType UnderLine - { - get - { - return TranslateUnderline(GetXmlNodeString(_underLinePath)); - } - set - { - CreateTopNode(); - SetXmlNodeString(_underLinePath, TranslateUnderlineText(value)); - } - } - string _underLineColorPath = "a:uFill/a:solidFill/a:srgbClr/@val"; - public Color UnderLineColor - { - get - { - string col = GetXmlNodeString(_underLineColorPath); - if (col == "") - { - return Color.Empty; - } - else - { - return Color.FromArgb(int.Parse(col, System.Globalization.NumberStyles.AllowHexSpecifier)); - } - } - set - { - CreateTopNode(); - SetXmlNodeString(_underLineColorPath, value.ToArgb().ToString("X").Substring(2, 6)); - } - } - string _italicPath = "@i"; - public bool Italic - { - get - { - return GetXmlNodeBool(_italicPath); - } - set - { - CreateTopNode(); - SetXmlNodeString(_italicPath, value ? "1" : "0"); - } - } - string _strikePath = "@strike"; - public eStrikeType Strike - { - get - { - return TranslateStrike(GetXmlNodeString(_strikePath)); - } - set - { - CreateTopNode(); - SetXmlNodeString(_strikePath, TranslateStrikeText(value)); - } - } - string _sizePath = "@sz"; - public float Size - { - get - { - return GetXmlNodeInt(_sizePath) / 100; - } - set - { - CreateTopNode(); - SetXmlNodeString(_sizePath, ((int)(value * 100)).ToString()); - } - } - string _colorPath = "a:solidFill/a:srgbClr/@val"; - public Color Color - { - get - { - string col = GetXmlNodeString(_colorPath); - if (col == "") - { - return Color.Empty; - } - else - { - return Color.FromArgb(int.Parse(col, System.Globalization.NumberStyles.AllowHexSpecifier)); - } - } - set - { - CreateTopNode(); - SetXmlNodeString(_colorPath, value.ToArgb().ToString("X").Substring(2, 6)); - } - } - #region "Translate methods" - private eUnderLineType TranslateUnderline(string text) - { - switch (text) - { - case "sng": - return eUnderLineType.Single; - case "dbl": - return eUnderLineType.Double; - case "": - return eUnderLineType.None; - default: - return (eUnderLineType)Enum.Parse(typeof(eUnderLineType), text); - } - } - private string TranslateUnderlineText(eUnderLineType value) - { - switch (value) - { - case eUnderLineType.Single: - return "sng"; - case eUnderLineType.Double: - return "dbl"; - default: - string ret = value.ToString(); - return ret.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + ret.Substring(1, ret.Length - 1); - } - } - private eStrikeType TranslateStrike(string text) - { - switch (text) - { - case "dblStrike": - return eStrikeType.Double; - case "sngStrike": - return eStrikeType.Single; - default: - return eStrikeType.No; - } - } - private string TranslateStrikeText(eStrikeType value) - { - switch (value) - { - case eStrikeType.Single: - return "sngStrike"; - case eStrikeType.Double: - return "dblStrike"; - default: - return "noStrike"; - } - } - #endregion - /// <summary> - /// Set the font style from a font object - /// </summary> - /// <param name="Font"></param> - public void SetFromFont(Font Font) - { - LatinFont = Font.Name; - ComplexFont = Font.Name; - Size = Font.Size; - if (Font.Bold) Bold = Font.Bold; - if (Font.Italic) Italic = Font.Italic; - if (Font.Underline) UnderLine = eUnderLineType.Single; - if (Font.Strikeout) Strike = eStrikeType.Single; - } +/// <summary> +/// Linestyle +/// </summary> +public enum eUnderLineType { + Dash, + DashHeavy, + DashLong, + DashLongHeavy, + Double, + DotDash, + DotDashHeavy, + DotDotDash, + DotDotDashHeavy, + Dotted, + DottedHeavy, + Heavy, + None, + Single, + Wavy, + WavyDbl, + WavyHeavy, + Words, +} + +/// <summary> +/// Type of font strike +/// </summary> +public enum eStrikeType { + Double, + No, + Single, +} + +/// <summary> +/// Used by Rich-text and Paragraphs. +/// </summary> +public class ExcelTextFont : XmlHelper { + private string _path; + private XmlNode _rootNode; + + internal ExcelTextFont( + XmlNamespaceManager namespaceManager, + XmlNode rootNode, + string path, + string[] schemaNodeOrder) + : base(namespaceManager, rootNode) { + SchemaNodeOrder = schemaNodeOrder; + _rootNode = rootNode; + if (path != "") { + XmlNode node = rootNode.SelectSingleNode(path, namespaceManager); + if (node != null) { + TopNode = node; + } } + _path = path; + } + + private string _fontLatinPath = "a:latin/@typeface"; + + public string LatinFont { + get => GetXmlNodeString(_fontLatinPath); + set { + CreateTopNode(); + SetXmlNodeString(_fontLatinPath, value); + } + } + + protected internal void CreateTopNode() { + if (_path != "" && TopNode == _rootNode) { + CreateNode(_path); + TopNode = _rootNode.SelectSingleNode(_path, NameSpaceManager); + } + } + + private string _fontCsPath = "a:cs/@typeface"; + + public string ComplexFont { + get => GetXmlNodeString(_fontCsPath); + set { + CreateTopNode(); + SetXmlNodeString(_fontCsPath, value); + } + } + + private string _boldPath = "@b"; + + public bool Bold { + get => GetXmlNodeBool(_boldPath); + set { + CreateTopNode(); + SetXmlNodeString(_boldPath, value ? "1" : "0"); + } + } + + private string _underLinePath = "@u"; + + public eUnderLineType UnderLine { + get => TranslateUnderline(GetXmlNodeString(_underLinePath)); + set { + CreateTopNode(); + SetXmlNodeString(_underLinePath, TranslateUnderlineText(value)); + } + } + + private string _underLineColorPath = "a:uFill/a:solidFill/a:srgbClr/@val"; + + public Color UnderLineColor { + get { + string col = GetXmlNodeString(_underLineColorPath); + if (col == "") { + return Color.Empty; + } + return Color.FromArgb(int.Parse(col, NumberStyles.AllowHexSpecifier)); + } + set { + CreateTopNode(); + SetXmlNodeString(_underLineColorPath, value.ToArgb().ToString("X").Substring(2, 6)); + } + } + + private string _italicPath = "@i"; + + public bool Italic { + get => GetXmlNodeBool(_italicPath); + set { + CreateTopNode(); + SetXmlNodeString(_italicPath, value ? "1" : "0"); + } + } + + private string _strikePath = "@strike"; + + public eStrikeType Strike { + get => TranslateStrike(GetXmlNodeString(_strikePath)); + set { + CreateTopNode(); + SetXmlNodeString(_strikePath, TranslateStrikeText(value)); + } + } + + private string _sizePath = "@sz"; + + public float Size { + get => GetXmlNodeInt(_sizePath) / 100; + set { + CreateTopNode(); + SetXmlNodeString(_sizePath, ((int)(value * 100)).ToString()); + } + } + + private string _colorPath = "a:solidFill/a:srgbClr/@val"; + + public Color Color { + get { + string col = GetXmlNodeString(_colorPath); + if (col == "") { + return Color.Empty; + } + return Color.FromArgb(int.Parse(col, NumberStyles.AllowHexSpecifier)); + } + set { + CreateTopNode(); + SetXmlNodeString(_colorPath, value.ToArgb().ToString("X").Substring(2, 6)); + } + } + + private eUnderLineType TranslateUnderline(string text) { + switch (text) { + case "sng": + return eUnderLineType.Single; + case "dbl": + return eUnderLineType.Double; + case "": + return eUnderLineType.None; + default: + return (eUnderLineType)Enum.Parse(typeof(eUnderLineType), text); + } + } + + private string TranslateUnderlineText(eUnderLineType value) { + switch (value) { + case eUnderLineType.Single: + return "sng"; + case eUnderLineType.Double: + return "dbl"; + default: + string ret = value.ToString(); + return ret.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + + ret.Substring(1, ret.Length - 1); + } + } + + private eStrikeType TranslateStrike(string text) { + switch (text) { + case "dblStrike": + return eStrikeType.Double; + case "sngStrike": + return eStrikeType.Single; + default: + return eStrikeType.No; + } + } + + private string TranslateStrikeText(eStrikeType value) { + switch (value) { + case eStrikeType.Single: + return "sngStrike"; + case eStrikeType.Double: + return "dblStrike"; + default: + return "noStrike"; + } + } + + /// <summary> + /// Set the font style from a font object + /// </summary> + /// <param name="font"></param> + public void SetFromFont(Font font) { + LatinFont = font.Name; + ComplexFont = font.Name; + Size = font.Size; + if (font.Bold) { + Bold = font.Bold; + } + if (font.Italic) { + Italic = font.Italic; + } + if (font.Underline) { + UnderLine = eUnderLineType.Single; + } + if (font.Strikeout) { + Strike = eStrikeType.Single; + } + } }
diff --git a/EPPlus/Style/IStyle.cs b/EPPlus/Style/IStyle.cs index 38235aa..f1f492e 100644 --- a/EPPlus/Style/IStyle.cs +++ b/EPPlus/Style/IStyle.cs
@@ -13,32 +13,29 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -using OfficeOpenXml.Style; -namespace OfficeOpenXml.Style -{ - internal interface IStyle - { - void SetNewStyleID(string value); - ulong Id {get;} - ExcelStyle ExcelStyle{get;} - } + +namespace OfficeOpenXml.Style; + +internal interface IStyle { + void SetNewStyleId(string value); + + ulong Id { get; } + + ExcelStyle ExcelStyle { get; } }
diff --git a/EPPlus/Style/StyleBase.cs b/EPPlus/Style/StyleBase.cs index aedddf2..fa1b390 100644 --- a/EPPlus/Style/StyleBase.cs +++ b/EPPlus/Style/StyleBase.cs
@@ -13,172 +13,176 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -namespace OfficeOpenXml.Style -{ - /// <summary> - /// Border line style - /// </summary> - public enum ExcelBorderStyle - { - None, - Hair, - Dotted, - DashDot, - Thin, - DashDotDot, - Dashed, - MediumDashDotDot, - MediumDashed, - MediumDashDot, - Thick, - Medium, - Double - }; - /// <summary> - /// Horizontal text alignment - /// </summary> - public enum ExcelHorizontalAlignment - { - General, - Left, - Center, - CenterContinuous, - Right, - Fill, - Distributed, - Justify - } - /// <summary> - /// Vertical text alignment - /// </summary> - public enum ExcelVerticalAlignment - { - Top, - Center, - Bottom, - Distributed, - Justify - } - /// <summary> - /// Font-Vertical Align - /// </summary> - public enum ExcelVerticalAlignmentFont - { - None, - Subscript, - Superscript - } - /// <summary> - /// Font-Underlinestyle for - /// </summary> - public enum ExcelUnderLineType - { - None, - Single, - Double, - SingleAccounting, - DoubleAccounting - } - /// <summary> - /// Fill pattern - /// </summary> - public enum ExcelFillStyle - { - None, - Solid, - DarkGray, - MediumGray, - LightGray, - Gray125, - Gray0625, - DarkVertical, - DarkHorizontal, - DarkDown, - DarkUp, - DarkGrid, - DarkTrellis, - LightVertical, - LightHorizontal, - LightDown, - LightUp, - LightGrid, - LightTrellis - } - /// <summary> - /// Type of gradient fill - /// </summary> - public enum ExcelFillGradientType - { - /// <summary> - /// No gradient fill. - /// </summary> - None, - /// <summary> - /// This gradient fill is of linear gradient type. Linear gradient type means that the transition from one color to the next is along a line (e.g., horizontal, vertical,diagonal, etc.) - /// </summary> - Linear, - /// <summary> - /// This gradient fill is of path gradient type. Path gradient type means the that the boundary of transition from one color to the next is a rectangle, defined by top,bottom, left, and right attributes on the gradientFill element. - /// </summary> - Path - } - /// <summary> - /// The reading order - /// </summary> - public enum ExcelReadingOrder - { - /// <summary> - /// Reading order is determined by scanning the text for the first non-whitespace character: if it is a strong right-to-left character, the reading order is right-to-left; otherwise, the reading order left-to-right. - /// </summary> - ContextDependent=0, - /// <summary> - /// Left to Right - /// </summary> - LeftToRight=1, - /// <summary> - /// Right to Left - /// </summary> - RightToLeft=2 - } - public abstract class StyleBase - { - protected ExcelStyles _styles; - internal OfficeOpenXml.XmlHelper.ChangedEventHandler _ChangedEvent; - protected int _positionID; - protected string _address; - internal StyleBase(ExcelStyles styles, OfficeOpenXml.XmlHelper.ChangedEventHandler ChangedEvent, int PositionID, string Address) - { - _styles = styles; - _ChangedEvent = ChangedEvent; - _address = Address; - _positionID = PositionID; - } - internal int Index { get; set;} - internal abstract string Id {get;} +namespace OfficeOpenXml.Style; - internal virtual void SetIndex(int index) - { - Index = index; - } - } +/// <summary> +/// Border line style +/// </summary> +public enum ExcelBorderStyle { + None, + Hair, + Dotted, + DashDot, + Thin, + DashDotDot, + Dashed, + MediumDashDotDot, + MediumDashed, + MediumDashDot, + Thick, + Medium, + Double, +} + +/// <summary> +/// Horizontal text alignment +/// </summary> +public enum ExcelHorizontalAlignment { + General, + Left, + Center, + CenterContinuous, + Right, + Fill, + Distributed, + Justify, +} + +/// <summary> +/// Vertical text alignment +/// </summary> +public enum ExcelVerticalAlignment { + Top, + Center, + Bottom, + Distributed, + Justify, +} + +/// <summary> +/// Font-Vertical Align +/// </summary> +public enum ExcelVerticalAlignmentFont { + None, + Subscript, + Superscript, +} + +/// <summary> +/// Font-Underlinestyle for +/// </summary> +public enum ExcelUnderLineType { + None, + Single, + Double, + SingleAccounting, + DoubleAccounting, +} + +/// <summary> +/// Fill pattern +/// </summary> +public enum ExcelFillStyle { + None, + Solid, + DarkGray, + MediumGray, + LightGray, + Gray125, + Gray0625, + DarkVertical, + DarkHorizontal, + DarkDown, + DarkUp, + DarkGrid, + DarkTrellis, + LightVertical, + LightHorizontal, + LightDown, + LightUp, + LightGrid, + LightTrellis, +} + +/// <summary> +/// Type of gradient fill +/// </summary> +public enum ExcelFillGradientType { + /// <summary> + /// No gradient fill. + /// </summary> + None, + + /// <summary> + /// This gradient fill is of linear gradient type. Linear gradient type means that the transition from one color to the next is along a line (e.g., horizontal, vertical,diagonal, etc.) + /// </summary> + Linear, + + /// <summary> + /// This gradient fill is of path gradient type. Path gradient type means the that the boundary of transition from one color to the next is a rectangle, defined by top,bottom, left, and right attributes on the gradientFill element. + /// </summary> + Path, +} + +/// <summary> +/// The reading order +/// </summary> +public enum ExcelReadingOrder { + /// <summary> + /// Reading order is determined by scanning the text for the first non-whitespace character: if it is a strong right-to-left character, the reading order is right-to-left; otherwise, the reading order left-to-right. + /// </summary> + ContextDependent = 0, + + /// <summary> + /// Left to Right + /// </summary> + LeftToRight = 1, + + /// <summary> + /// Right to Left + /// </summary> + RightToLeft = 2, +} + +public abstract class StyleBase { + protected ExcelStyles _styles; + internal XmlHelper.ChangedEventHandler _ChangedEvent; + protected int _positionID; + protected string _address; + + internal StyleBase( + ExcelStyles styles, + XmlHelper.ChangedEventHandler changedEvent, + int positionId, + string address) { + _styles = styles; + _ChangedEvent = changedEvent; + _address = address; + _positionID = positionId; + } + + internal int Index { get; set; } + + internal abstract string Id { get; } + + internal virtual void SetIndex(int index) { + Index = index; + } }
diff --git a/EPPlus/Style/StyleChangeEventArgs.cs b/EPPlus/Style/StyleChangeEventArgs.cs index f671df0..352dc51 100644 --- a/EPPlus/Style/StyleChangeEventArgs.cs +++ b/EPPlus/Style/StyleChangeEventArgs.cs
@@ -13,101 +13,107 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -namespace OfficeOpenXml.Style -{ - internal enum eStyleClass - { - Numberformat, - Font, - Border, - BorderTop, - BorderLeft, - BorderBottom, - BorderRight, - BorderDiagonal, - Fill, - GradientFill, - FillBackgroundColor, - FillPatternColor, - FillGradientColor1, - FillGradientColor2, - NamedStyle, - Style - }; - internal enum eStyleProperty - { - Format, - Name, - Size, - Bold, - Italic, - Strike, - Color, - Tint, - IndexedColor, - AutoColor, - GradientColor, - Family, - Scheme, - UnderlineType, - HorizontalAlign, - VerticalAlign, - Border, - NamedStyle, - Style, - PatternType, - ReadingOrder, - WrapText, - TextRotation, - Locked, - Hidden, - ShrinkToFit, - BorderDiagonalUp, - BorderDiagonalDown, - GradientDegree, - GradientType, - GradientTop, - GradientBottom, - GradientLeft, - GradientRight, - XfId, - Indent - } - internal class StyleChangeEventArgs : EventArgs - { - internal StyleChangeEventArgs(eStyleClass styleclass, eStyleProperty styleProperty, object value, int positionID, string address) - { - StyleClass = styleclass; - StyleProperty=styleProperty; - Value = value; - Address = address; - PositionID = positionID; - } - internal eStyleClass StyleClass; - internal eStyleProperty StyleProperty; - //internal string PropertyName; - internal object Value; - internal int PositionID { get; set; } - //internal string Address; - internal string Address; - } + +namespace OfficeOpenXml.Style; + +internal enum eStyleClass { + Numberformat, + Font, + Border, + BorderTop, + BorderLeft, + BorderBottom, + BorderRight, + BorderDiagonal, + Fill, + GradientFill, + FillBackgroundColor, + FillPatternColor, + FillGradientColor1, + FillGradientColor2, + NamedStyle, + Style, +} + +internal enum eStyleProperty { + Format, + Name, + Size, + Bold, + Italic, + Strike, + Color, + Tint, + IndexedColor, + AutoColor, + GradientColor, + Family, + Scheme, + UnderlineType, + HorizontalAlign, + VerticalAlign, + Border, + NamedStyle, + Style, + PatternType, + ReadingOrder, + WrapText, + TextRotation, + Locked, + Hidden, + ShrinkToFit, + BorderDiagonalUp, + BorderDiagonalDown, + GradientDegree, + GradientType, + GradientTop, + GradientBottom, + GradientLeft, + GradientRight, + XfId, + Indent, +} + +internal class StyleChangeEventArgs : EventArgs { + internal StyleChangeEventArgs( + eStyleClass styleclass, + eStyleProperty styleProperty, + object value, + int positionId, + string address) { + StyleClass = styleclass; + StyleProperty = styleProperty; + Value = value; + Address = address; + PositionID = positionId; + } + + internal eStyleClass StyleClass; + internal eStyleProperty StyleProperty; + + //internal string PropertyName; + internal object Value; + + internal int PositionID { get; set; } + + //internal string Address; + internal string Address; }
diff --git a/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs b/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs index e2f91b2..7e94481 100644 --- a/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelBorderItemXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,145 +13,123 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Xml; -using OfficeOpenXml.Style; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for border items - /// </summary> - public sealed class ExcelBorderItemXml : StyleXmlHelper - { - internal ExcelBorderItemXml(XmlNamespaceManager nameSpaceManager) : base(nameSpaceManager) - { - _borderStyle=ExcelBorderStyle.None; - _color = new ExcelColorXml(NameSpaceManager); - } - internal ExcelBorderItemXml(XmlNamespaceManager nsm, XmlNode topNode) : - base(nsm, topNode) - { - if (topNode != null) - { - _borderStyle = GetBorderStyle(GetXmlNodeString("@style")); - _color = new ExcelColorXml(nsm, topNode.SelectSingleNode(_colorPath, nsm)); - Exists = true; - } - else - { - Exists = false; - } - } - private ExcelBorderStyle GetBorderStyle(string style) - { - if(style=="") return ExcelBorderStyle.None; - string sInStyle = style.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + style.Substring(1, style.Length - 1); - try - { - return (ExcelBorderStyle)Enum.Parse(typeof(ExcelBorderStyle), sInStyle); - } - catch - { - return ExcelBorderStyle.None; - } +namespace OfficeOpenXml.Style.XmlAccess; - } - ExcelBorderStyle _borderStyle = ExcelBorderStyle.None; - /// <summary> - /// Cell Border style - /// </summary> - public ExcelBorderStyle Style - { - get - { - return _borderStyle; - } - set - { - _borderStyle = value; - Exists = true; - } - } - ExcelColorXml _color = null; - const string _colorPath = "d:color"; - /// <summary> - /// Border style - /// </summary> - public ExcelColorXml Color - { - get - { - return _color; - } - internal set - { - _color = value; - } - } - internal override string Id - { - get - { - if (Exists) - { - return Style + Color.Id; - } - else - { - return "None"; - } - } - } +/// <summary> +/// Xml access class for border items +/// </summary> +public sealed class ExcelBorderItemXml : StyleXmlHelper { + internal ExcelBorderItemXml(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) { + _borderStyle = ExcelBorderStyle.None; + _color = new(NameSpaceManager); + } - internal ExcelBorderItemXml Copy() - { - ExcelBorderItemXml borderItem = new ExcelBorderItemXml(NameSpaceManager); - borderItem.Style = _borderStyle; - borderItem.Color = _color.Copy(); - return borderItem; - } - - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - TopNode = topNode; - - if (Style != ExcelBorderStyle.None) - { - SetXmlNodeString("@style", SetBorderString(Style)); - if (Color.Exists) - { - CreateNode(_colorPath); - topNode.AppendChild(Color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath,NameSpaceManager))); - } - } - return TopNode; - } - - private string SetBorderString(ExcelBorderStyle Style) - { - string newName=Enum.GetName(typeof(ExcelBorderStyle), Style); - return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + newName.Substring(1, newName.Length - 1); - } - public bool Exists { get; private set; } + internal ExcelBorderItemXml(XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + if (topNode != null) { + _borderStyle = GetBorderStyle(GetXmlNodeString("@style")); + _color = new(nsm, topNode.SelectSingleNode(_colorPath, nsm)); + Exists = true; + } else { + Exists = false; } + } + + private ExcelBorderStyle GetBorderStyle(string style) { + if (style == "") { + return ExcelBorderStyle.None; + } + string sInStyle = + style.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + + style.Substring(1, style.Length - 1); + try { + return (ExcelBorderStyle)Enum.Parse(typeof(ExcelBorderStyle), sInStyle); + } catch { + return ExcelBorderStyle.None; + } + } + + private ExcelBorderStyle _borderStyle = ExcelBorderStyle.None; + + /// <summary> + /// Cell Border style + /// </summary> + public ExcelBorderStyle Style { + get => _borderStyle; + set { + _borderStyle = value; + Exists = true; + } + } + + private ExcelColorXml _color; + private const string _colorPath = "d:color"; + + /// <summary> + /// Border style + /// </summary> + public ExcelColorXml Color { + get => _color; + internal set => _color = value; + } + + internal override string Id { + get { + if (Exists) { + return Style + Color.Id; + } + return "None"; + } + } + + internal ExcelBorderItemXml Copy() { + ExcelBorderItemXml borderItem = new ExcelBorderItemXml(NameSpaceManager); + borderItem.Style = _borderStyle; + borderItem.Color = _color.Copy(); + return borderItem; + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + TopNode = topNode; + + if (Style != ExcelBorderStyle.None) { + SetXmlNodeString("@style", SetBorderString(Style)); + if (Color.Exists) { + CreateNode(_colorPath); + topNode.AppendChild( + Color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath, NameSpaceManager))); + } + } + return TopNode; + } + + private string SetBorderString(ExcelBorderStyle style) { + string newName = Enum.GetName(typeof(ExcelBorderStyle), style); + return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + + newName.Substring(1, newName.Length - 1); + } + + public bool Exists { get; private set; } }
diff --git a/EPPlus/Style/XmlAccess/ExcelBorderXml.cs b/EPPlus/Style/XmlAccess/ExcelBorderXml.cs index 700f319..9a7e12c 100644 --- a/EPPlus/Style/XmlAccess/ExcelBorderXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelBorderXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,206 +13,159 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; + using System.Xml; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for border top level - /// </summary> - public sealed class ExcelBorderXml : StyleXmlHelper - { - internal ExcelBorderXml(XmlNamespaceManager nameSpaceManager) - : base(nameSpaceManager) - { - } - internal ExcelBorderXml(XmlNamespaceManager nsm, XmlNode topNode) : - base(nsm, topNode) - { - _left = new ExcelBorderItemXml(nsm, topNode.SelectSingleNode(leftPath, nsm)); - _right = new ExcelBorderItemXml(nsm, topNode.SelectSingleNode(rightPath, nsm)); - _top = new ExcelBorderItemXml(nsm, topNode.SelectSingleNode(topPath, nsm)); - _bottom = new ExcelBorderItemXml(nsm, topNode.SelectSingleNode(bottomPath, nsm)); - _diagonal = new ExcelBorderItemXml(nsm, topNode.SelectSingleNode(diagonalPath, nsm)); - _diagonalUp = GetBoolValue(topNode, diagonalUpPath); - _diagonalDown = GetBoolValue(topNode, diagonalDownPath); - } - internal override string Id - { - get - { - return Left.Id + Right.Id + Top.Id + Bottom.Id + Diagonal.Id + DiagonalUp.ToString() + DiagonalDown.ToString(); - } - } - const string leftPath = "d:left"; - ExcelBorderItemXml _left = null; - /// <summary> - /// Left border style properties - /// </summary> - public ExcelBorderItemXml Left - { - get - { - return _left; - } - internal set - { - _left = value; - } - } - const string rightPath = "d:right"; - ExcelBorderItemXml _right = null; - /// <summary> - /// Right border style properties - /// </summary> - public ExcelBorderItemXml Right - { - get - { - return _right; - } - internal set - { - _right = value; - } - } - const string topPath = "d:top"; - ExcelBorderItemXml _top = null; - /// <summary> - /// Top border style properties - /// </summary> - public ExcelBorderItemXml Top - { - get - { - return _top; - } - internal set - { - _top = value; - } - } - const string bottomPath = "d:bottom"; - ExcelBorderItemXml _bottom = null; - /// <summary> - /// Bottom border style properties - /// </summary> - public ExcelBorderItemXml Bottom - { - get - { - return _bottom; - } - internal set - { - _bottom = value; - } - } - const string diagonalPath = "d:diagonal"; - ExcelBorderItemXml _diagonal = null; - /// <summary> - /// Diagonal border style properties - /// </summary> - public ExcelBorderItemXml Diagonal - { - get - { - return _diagonal; - } - internal set - { - _diagonal = value; - } - } - const string diagonalUpPath = "@diagonalUp"; - bool _diagonalUp = false; - /// <summary> - /// Diagonal up border - /// </summary> - public bool DiagonalUp - { - get - { - return _diagonalUp; - } - internal set - { - _diagonalUp = value; - } - } - const string diagonalDownPath = "@diagonalDown"; - bool _diagonalDown = false; - /// <summary> - /// Diagonal down border - /// </summary> - public bool DiagonalDown - { - get - { - return _diagonalDown; - } - internal set - { - _diagonalDown = value; - } - } +namespace OfficeOpenXml.Style.XmlAccess; - internal ExcelBorderXml Copy() - { - ExcelBorderXml newBorder = new ExcelBorderXml(NameSpaceManager); - newBorder.Bottom = _bottom.Copy(); - newBorder.Diagonal = _diagonal.Copy(); - newBorder.Left = _left.Copy(); - newBorder.Right = _right.Copy(); - newBorder.Top = _top.Copy(); - newBorder.DiagonalUp = _diagonalUp; - newBorder.DiagonalDown = _diagonalDown; +/// <summary> +/// Xml access class for border top level +/// </summary> +public sealed class ExcelBorderXml : StyleXmlHelper { + internal ExcelBorderXml(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) {} - return newBorder; + internal ExcelBorderXml(XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + _left = new(nsm, topNode.SelectSingleNode(_leftPath, nsm)); + _right = new(nsm, topNode.SelectSingleNode(_rightPath, nsm)); + _top = new(nsm, topNode.SelectSingleNode(_topPath, nsm)); + _bottom = new(nsm, topNode.SelectSingleNode(_bottomPath, nsm)); + _diagonal = new(nsm, topNode.SelectSingleNode(_diagonalPath, nsm)); + _diagonalUp = GetBoolValue(topNode, _diagonalUpPath); + _diagonalDown = GetBoolValue(topNode, _diagonalDownPath); + } - } + internal override string Id => + Left.Id + Right.Id + Top.Id + Bottom.Id + Diagonal.Id + DiagonalUp + DiagonalDown; - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - TopNode = topNode; - CreateNode(leftPath); - topNode.AppendChild(_left.CreateXmlNode(TopNode.SelectSingleNode(leftPath, NameSpaceManager))); - CreateNode(rightPath); - topNode.AppendChild(_right.CreateXmlNode(TopNode.SelectSingleNode(rightPath, NameSpaceManager))); - CreateNode(topPath); - topNode.AppendChild(_top.CreateXmlNode(TopNode.SelectSingleNode(topPath, NameSpaceManager))); - CreateNode(bottomPath); - topNode.AppendChild(_bottom.CreateXmlNode(TopNode.SelectSingleNode(bottomPath, NameSpaceManager))); - CreateNode(diagonalPath); - topNode.AppendChild(_diagonal.CreateXmlNode(TopNode.SelectSingleNode(diagonalPath, NameSpaceManager))); - if (_diagonalUp) - { - SetXmlNodeString(diagonalUpPath, "1"); - } - if (_diagonalDown) - { - SetXmlNodeString(diagonalDownPath, "1"); - } - return topNode; - } + private const string _leftPath = "d:left"; + private ExcelBorderItemXml _left; + + /// <summary> + /// Left border style properties + /// </summary> + public ExcelBorderItemXml Left { + get { return _left; } + internal set { _left = value; } + } + + private const string _rightPath = "d:right"; + private ExcelBorderItemXml _right; + + /// <summary> + /// Right border style properties + /// </summary> + public ExcelBorderItemXml Right { + get { return _right; } + internal set { _right = value; } + } + + private const string _topPath = "d:top"; + private ExcelBorderItemXml _top; + + /// <summary> + /// Top border style properties + /// </summary> + public ExcelBorderItemXml Top { + get { return _top; } + internal set { _top = value; } + } + + private const string _bottomPath = "d:bottom"; + private ExcelBorderItemXml _bottom; + + /// <summary> + /// Bottom border style properties + /// </summary> + public ExcelBorderItemXml Bottom { + get { return _bottom; } + internal set { _bottom = value; } + } + + private const string _diagonalPath = "d:diagonal"; + private ExcelBorderItemXml _diagonal; + + /// <summary> + /// Diagonal border style properties + /// </summary> + public ExcelBorderItemXml Diagonal { + get { return _diagonal; } + internal set { _diagonal = value; } + } + + private const string _diagonalUpPath = "@diagonalUp"; + private bool _diagonalUp; + + /// <summary> + /// Diagonal up border + /// </summary> + public bool DiagonalUp { + get { return _diagonalUp; } + internal set { _diagonalUp = value; } + } + + private const string _diagonalDownPath = "@diagonalDown"; + private bool _diagonalDown; + + /// <summary> + /// Diagonal down border + /// </summary> + public bool DiagonalDown { + get { return _diagonalDown; } + internal set { _diagonalDown = value; } + } + + internal ExcelBorderXml Copy() { + ExcelBorderXml newBorder = new ExcelBorderXml(NameSpaceManager); + newBorder.Bottom = _bottom.Copy(); + newBorder.Diagonal = _diagonal.Copy(); + newBorder.Left = _left.Copy(); + newBorder.Right = _right.Copy(); + newBorder.Top = _top.Copy(); + newBorder.DiagonalUp = _diagonalUp; + newBorder.DiagonalDown = _diagonalDown; + + return newBorder; + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + TopNode = topNode; + CreateNode(_leftPath); + topNode.AppendChild(_left.CreateXmlNode(TopNode.SelectSingleNode(_leftPath, NameSpaceManager))); + CreateNode(_rightPath); + topNode.AppendChild( + _right.CreateXmlNode(TopNode.SelectSingleNode(_rightPath, NameSpaceManager))); + CreateNode(_topPath); + topNode.AppendChild(_top.CreateXmlNode(TopNode.SelectSingleNode(_topPath, NameSpaceManager))); + CreateNode(_bottomPath); + topNode.AppendChild( + _bottom.CreateXmlNode(TopNode.SelectSingleNode(_bottomPath, NameSpaceManager))); + CreateNode(_diagonalPath); + topNode.AppendChild( + _diagonal.CreateXmlNode(TopNode.SelectSingleNode(_diagonalPath, NameSpaceManager))); + if (_diagonalUp) { + SetXmlNodeString(_diagonalUpPath, "1"); } + if (_diagonalDown) { + SetXmlNodeString(_diagonalDownPath, "1"); + } + return topNode; + } }
diff --git a/EPPlus/Style/XmlAccess/ExcelColorXml.cs b/EPPlus/Style/XmlAccess/ExcelColorXml.cs index b636119..ba1fd11 100644 --- a/EPPlus/Style/XmlAccess/ExcelColorXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelColorXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,207 +13,169 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; +using System.Drawing; using System.Globalization; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for color - /// </summary> - public sealed class ExcelColorXml : StyleXmlHelper - { - internal ExcelColorXml(XmlNamespaceManager nameSpaceManager) - : base(nameSpaceManager) - { - _auto = false; - _theme = ""; - _tint = 0; - _rgb = ""; - _indexed = int.MinValue; - } - internal ExcelColorXml(XmlNamespaceManager nsm, XmlNode topNode) : - base(nsm, topNode) - { - if(topNode==null) - { - _exists=false; - } - else - { - _exists = true; - _auto = GetXmlNodeBool("@auto"); - _theme = GetXmlNodeString("@theme"); - _tint = GetXmlNodeDecimalNull("@tint")??decimal.MinValue; - _rgb = GetXmlNodeString("@rgb"); - _indexed = GetXmlNodeIntNull("@indexed") ?? int.MinValue; - } - } - - internal override string Id - { - get - { - return _auto.ToString() + "|" + _theme + "|" + _tint + "|" + _rgb + "|" + _indexed; - } - } - bool _auto; - public bool Auto - { - get - { - return _auto; - } - set - { - _auto = value; - _exists = true; - Clear(); - } - } - string _theme; - /// <summary> - /// Theme color value - /// </summary> - public string Theme - { - get - { - return _theme; - } - } - decimal _tint; - /// <summary> - /// Tint - /// </summary> - public decimal Tint - { - get - { - if (_tint == decimal.MinValue) - { - return 0; - } - else - { - return _tint; - } - } - set - { - _tint = value; - _exists = true; - } - } - string _rgb; - /// <summary> - /// RGB value - /// </summary> - public string Rgb - { - get - { - return _rgb; - } - set - { - _rgb = value; - _exists=true; - _indexed = int.MinValue; - _auto = false; - } - } - int _indexed; - /// <summary> - /// Indexed color value - /// </summary> - public int Indexed - { - get - { - return (_indexed == int.MinValue ? 0 : _indexed); - } - set - { - if (value < 0 || value > 65) - { - throw (new ArgumentOutOfRangeException("Index out of range")); - } - Clear(); - _indexed = value; - _exists = true; - } - } - internal void Clear() - { - _theme = ""; - _tint = decimal.MinValue; - _indexed = int.MinValue; - _rgb = ""; - _auto = false; - } - public void SetColor(System.Drawing.Color color) - { - Clear(); - _rgb = color.ToArgb().ToString("X"); - } +using System.Xml; - internal ExcelColorXml Copy() - { - return new ExcelColorXml(NameSpaceManager) {_indexed=_indexed, _tint=_tint, _rgb=_rgb, _theme=_theme, _auto=_auto, _exists=_exists }; - } +namespace OfficeOpenXml.Style.XmlAccess; - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - TopNode = topNode; - if(_rgb!="") - { - SetXmlNodeString("@rgb", _rgb); - } - else if (_indexed >= 0) - { - SetXmlNodeString("@indexed", _indexed.ToString()); - } - else if (_auto) - { - SetXmlNodeBool("@auto", _auto); - } - else - { - SetXmlNodeString("@theme", _theme.ToString()); - } - if (_tint != decimal.MinValue) - { - SetXmlNodeString("@tint", _tint.ToString(CultureInfo.InvariantCulture)); - } - return TopNode; - } +/// <summary> +/// Xml access class for color +/// </summary> +public sealed class ExcelColorXml : StyleXmlHelper { + internal ExcelColorXml(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) { + _auto = false; + _theme = ""; + _tint = 0; + _rgb = ""; + _indexed = int.MinValue; + } - bool _exists; - internal bool Exists - { - get - { - return _exists; - } - } + internal ExcelColorXml(XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + if (topNode == null) { + _exists = false; + } else { + _exists = true; + _auto = GetXmlNodeBool("@auto"); + _theme = GetXmlNodeString("@theme"); + _tint = GetXmlNodeDecimalNull("@tint") ?? decimal.MinValue; + _rgb = GetXmlNodeString("@rgb"); + _indexed = GetXmlNodeIntNull("@indexed") ?? int.MinValue; } + } + + internal override string Id => _auto + "|" + _theme + "|" + _tint + "|" + _rgb + "|" + _indexed; + + private bool _auto; + + public bool Auto { + get => _auto; + set { + _auto = value; + _exists = true; + Clear(); + } + } + + private string _theme; + + /// <summary> + /// Theme color value + /// </summary> + public string Theme => _theme; + + private decimal _tint; + + /// <summary> + /// Tint + /// </summary> + public decimal Tint { + get { + if (_tint == decimal.MinValue) { + return 0; + } + return _tint; + } + set { + _tint = value; + _exists = true; + } + } + + private string _rgb; + + /// <summary> + /// RGB value + /// </summary> + public string Rgb { + get => _rgb; + set { + _rgb = value; + _exists = true; + _indexed = int.MinValue; + _auto = false; + } + } + + private int _indexed; + + /// <summary> + /// Indexed color value + /// </summary> + public int Indexed { + get => (_indexed == int.MinValue ? 0 : _indexed); + set { + if (value < 0 || value > 65) { + throw (new ArgumentOutOfRangeException("Index out of range")); + } + Clear(); + _indexed = value; + _exists = true; + } + } + + internal void Clear() { + _theme = ""; + _tint = decimal.MinValue; + _indexed = int.MinValue; + _rgb = ""; + _auto = false; + } + + public void SetColor(Color color) { + Clear(); + _rgb = color.ToArgb().ToString("X"); + } + + internal ExcelColorXml Copy() { + return new(NameSpaceManager) { + _indexed = _indexed, + _tint = _tint, + _rgb = _rgb, + _theme = _theme, + _auto = _auto, + _exists = _exists, + }; + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + TopNode = topNode; + if (_rgb != "") { + SetXmlNodeString("@rgb", _rgb); + } else if (_indexed >= 0) { + SetXmlNodeString("@indexed", _indexed.ToString()); + } else if (_auto) { + SetXmlNodeBool("@auto", _auto); + } else { + SetXmlNodeString("@theme", _theme); + } + if (_tint != decimal.MinValue) { + SetXmlNodeString("@tint", _tint.ToString(CultureInfo.InvariantCulture)); + } + return TopNode; + } + + private bool _exists; + + internal bool Exists => _exists; }
diff --git a/EPPlus/Style/XmlAccess/ExcelFillXml.cs b/EPPlus/Style/XmlAccess/ExcelFillXml.cs index 2cea423..98b7c9d 100644 --- a/EPPlus/Style/XmlAccess/ExcelFillXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelFillXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,162 +13,126 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Xml; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for fills - /// </summary> - public class ExcelFillXml : StyleXmlHelper - { - internal ExcelFillXml(XmlNamespaceManager nameSpaceManager) - : base(nameSpaceManager) - { - _fillPatternType = ExcelFillStyle.None; - _backgroundColor = new ExcelColorXml(NameSpaceManager); - _patternColor = new ExcelColorXml(NameSpaceManager); - } - internal ExcelFillXml(XmlNamespaceManager nsm, XmlNode topNode): - base(nsm, topNode) - { - PatternType = GetPatternType(GetXmlNodeString(fillPatternTypePath)); - _backgroundColor = new ExcelColorXml(nsm, topNode.SelectSingleNode(_backgroundColorPath, nsm)); - _patternColor = new ExcelColorXml(nsm, topNode.SelectSingleNode(_patternColorPath, nsm)); - } - private ExcelFillStyle GetPatternType(string patternType) - { - if (patternType == "") return ExcelFillStyle.None; - patternType = patternType.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + patternType.Substring(1, patternType.Length - 1); - try - { - return (ExcelFillStyle)Enum.Parse(typeof(ExcelFillStyle), patternType); - } - catch - { - return ExcelFillStyle.None; - } - } - internal override string Id - { - get - { - return PatternType + PatternColor.Id + BackgroundColor.Id; - } - } - #region Public Properties - const string fillPatternTypePath = "d:patternFill/@patternType"; - protected ExcelFillStyle _fillPatternType; - /// <summary> - /// Cell fill pattern style - /// </summary> - public ExcelFillStyle PatternType - { - get - { - return _fillPatternType; - } - set - { - _fillPatternType=value; - } - } - protected ExcelColorXml _patternColor = null; - const string _patternColorPath = "d:patternFill/d:bgColor"; - /// <summary> - /// Pattern color - /// </summary> - public ExcelColorXml PatternColor - { - get - { - return _patternColor; - } - internal set - { - _patternColor = value; - } - } - protected ExcelColorXml _backgroundColor = null; - const string _backgroundColorPath = "d:patternFill/d:fgColor"; - /// <summary> - /// Cell background color - /// </summary> - public ExcelColorXml BackgroundColor - { - get - { - return _backgroundColor; - } - internal set - { - _backgroundColor=value; - } - } - #endregion +namespace OfficeOpenXml.Style.XmlAccess; +/// <summary> +/// Xml access class for fills +/// </summary> +public class ExcelFillXml : StyleXmlHelper { + internal ExcelFillXml(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) { + _fillPatternType = ExcelFillStyle.None; + _backgroundColor = new(NameSpaceManager); + _patternColor = new(NameSpaceManager); + } - //internal Fill Copy() - //{ - // Fill newFill = new Fill(NameSpaceManager, TopNode.Clone()); - // return newFill; - //} + internal ExcelFillXml(XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + PatternType = GetPatternType(GetXmlNodeString(_fillPatternTypePath)); + _backgroundColor = new(nsm, topNode.SelectSingleNode(_backgroundColorPath, nsm)); + _patternColor = new(nsm, topNode.SelectSingleNode(_patternColorPath, nsm)); + } - internal virtual ExcelFillXml Copy() - { - ExcelFillXml newFill = new ExcelFillXml(NameSpaceManager); - newFill.PatternType = _fillPatternType; - newFill.BackgroundColor = _backgroundColor.Copy(); - newFill.PatternColor = _patternColor.Copy(); - return newFill; - } - - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - TopNode = topNode; - SetXmlNodeString(fillPatternTypePath, SetPatternString(_fillPatternType)); - if (PatternType != ExcelFillStyle.None) - { - XmlNode pattern = topNode.SelectSingleNode(fillPatternTypePath, NameSpaceManager); - if (BackgroundColor.Exists) - { - CreateNode(_backgroundColorPath); - BackgroundColor.CreateXmlNode(topNode.SelectSingleNode(_backgroundColorPath, NameSpaceManager)); - if (PatternColor.Exists) - { - CreateNode(_patternColorPath); - //topNode.AppendChild(PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager))); - PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager)); - } - } - } - return topNode; - } - - private string SetPatternString(ExcelFillStyle pattern) - { - string newName = Enum.GetName(typeof(ExcelFillStyle), pattern); - return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + newName.Substring(1, newName.Length - 1); - } + private ExcelFillStyle GetPatternType(string patternType) { + if (patternType == "") { + return ExcelFillStyle.None; } + patternType = + patternType.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + + patternType.Substring(1, patternType.Length - 1); + try { + return (ExcelFillStyle)Enum.Parse(typeof(ExcelFillStyle), patternType); + } catch { + return ExcelFillStyle.None; + } + } + + internal override string Id => PatternType + PatternColor.Id + BackgroundColor.Id; + + private const string _fillPatternTypePath = "d:patternFill/@patternType"; + protected ExcelFillStyle _fillPatternType; + + /// <summary> + /// Cell fill pattern style + /// </summary> + public ExcelFillStyle PatternType { + get => _fillPatternType; + set => _fillPatternType = value; + } + + protected ExcelColorXml _patternColor; + private const string _patternColorPath = "d:patternFill/d:bgColor"; + + /// <summary> + /// Pattern color + /// </summary> + public ExcelColorXml PatternColor { + get => _patternColor; + internal set => _patternColor = value; + } + + protected ExcelColorXml _backgroundColor; + private const string _backgroundColorPath = "d:patternFill/d:fgColor"; + + /// <summary> + /// Cell background color + /// </summary> + public ExcelColorXml BackgroundColor { + get => _backgroundColor; + internal set => _backgroundColor = value; + } + + internal virtual ExcelFillXml Copy() { + ExcelFillXml newFill = new ExcelFillXml(NameSpaceManager); + newFill.PatternType = _fillPatternType; + newFill.BackgroundColor = _backgroundColor.Copy(); + newFill.PatternColor = _patternColor.Copy(); + return newFill; + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + TopNode = topNode; + SetXmlNodeString(_fillPatternTypePath, SetPatternString(_fillPatternType)); + if (PatternType != ExcelFillStyle.None) { + XmlNode pattern = topNode.SelectSingleNode(_fillPatternTypePath, NameSpaceManager); + if (BackgroundColor.Exists) { + CreateNode(_backgroundColorPath); + BackgroundColor.CreateXmlNode( + topNode.SelectSingleNode(_backgroundColorPath, NameSpaceManager)); + if (PatternColor.Exists) { + CreateNode(_patternColorPath); + //topNode.AppendChild(PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager))); + PatternColor.CreateXmlNode(topNode.SelectSingleNode(_patternColorPath, NameSpaceManager)); + } + } + } + return topNode; + } + + private string SetPatternString(ExcelFillStyle pattern) { + string newName = Enum.GetName(typeof(ExcelFillStyle), pattern); + return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + + newName.Substring(1, newName.Length - 1); + } }
diff --git a/EPPlus/Style/XmlAccess/ExcelFontXml.cs b/EPPlus/Style/XmlAccess/ExcelFontXml.cs index 0247591..11b6bb9 100644 --- a/EPPlus/Style/XmlAccess/ExcelFontXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelFontXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,321 +13,294 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; +using System.Drawing; using System.Globalization; -using System.Text; using System.Xml; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for fonts - /// </summary> - public sealed class ExcelFontXml : StyleXmlHelper - { - internal ExcelFontXml(XmlNamespaceManager nameSpaceManager) - : base(nameSpaceManager) - { - _name = ""; - _size = 0; - _family = int.MinValue; - _scheme = ""; - _color = _color = new ExcelColorXml(NameSpaceManager); - _bold = false; - _italic = false; - _strike = false; - _underlineType = ExcelUnderLineType.None ; - _verticalAlign = ""; - } - internal ExcelFontXml(XmlNamespaceManager nsm, XmlNode topNode) : - base(nsm, topNode) - { - _name = GetXmlNodeString(namePath); - _size = (float)GetXmlNodeDecimal(sizePath); - _family = GetXmlNodeIntNull(familyPath)??int.MinValue; - _scheme = GetXmlNodeString(schemePath); - _color = new ExcelColorXml(nsm, topNode.SelectSingleNode(_colorPath, nsm)); - _bold = GetBoolValue(topNode, boldPath); - _italic = GetBoolValue(topNode, italicPath); - _strike = GetBoolValue(topNode, strikePath); - _verticalAlign = GetXmlNodeString(verticalAlignPath); - if (topNode.SelectSingleNode(underLinedPath, NameSpaceManager) != null) - { - string ut = GetXmlNodeString(underLinedPath + "/@val"); - if (ut == "") - { - _underlineType = ExcelUnderLineType.Single; - } - else - { - _underlineType = (ExcelUnderLineType)Enum.Parse(typeof(ExcelUnderLineType), ut, true); - } - } - else - { - _underlineType = ExcelUnderLineType.None; - } - } - internal override string Id - { - get - { - return Name + "|" + Size + "|" + Family + "|" + Color.Id + "|" + Scheme + "|" + Bold.ToString() + "|" + Italic.ToString() + "|" + Strike.ToString() + "|" + VerticalAlign + "|" + UnderLineType.ToString(); - } - } - const string namePath = "d:name/@val"; - string _name; - /// <summary> - /// The name of the font - /// </summary> - public string Name - { - get - { - return _name; - } - set - { - Scheme = ""; //Reset schema to avoid corrupt file if unsupported font is selected. - _name = value; - } - } - const string sizePath = "d:sz/@val"; - float _size; - /// <summary> - /// Font size - /// </summary> - public float Size - { - get - { - return _size; - } - set - { - _size = value; - } - } - const string familyPath = "d:family/@val"; - int _family; - /// <summary> - /// Font family - /// </summary> - public int Family - { - get - { - return (_family == int.MinValue ? 0 : _family); ; - } - set - { - _family=value; - } - } - ExcelColorXml _color = null; - const string _colorPath = "d:color"; - /// <summary> - /// Text color - /// </summary> - public ExcelColorXml Color - { - get - { - return _color; - } - internal set - { - _color=value; - } - } - const string schemePath = "d:scheme/@val"; - string _scheme=""; - /// <summary> - /// Font Scheme - /// </summary> - public string Scheme - { - get - { - return _scheme; - } - private set - { - _scheme=value; - } - } - const string boldPath = "d:b"; - bool _bold; - /// <summary> - /// If the font is bold - /// </summary> - public bool Bold - { - get - { - return _bold; - } - set - { - _bold=value; - } - } - const string italicPath = "d:i"; - bool _italic; - /// <summary> - /// If the font is italic - /// </summary> - public bool Italic - { - get - { - return _italic; - } - set - { - _italic=value; - } - } - const string strikePath = "d:strike"; - bool _strike; - /// <summary> - /// If the font is striked out - /// </summary> - public bool Strike - { - get - { - return _strike; - } - set - { - _strike=value; - } - } - const string underLinedPath = "d:u"; - /// <summary> - /// If the font is underlined. - /// When set to true a the text is underlined with a single line - /// </summary> - public bool UnderLine - { - get - { - return UnderLineType!=ExcelUnderLineType.None; - } - set - { - _underlineType=value ? ExcelUnderLineType.Single : ExcelUnderLineType.None; - } - } - ExcelUnderLineType _underlineType; - /// <summary> - /// If the font is underlined - /// </summary> - public ExcelUnderLineType UnderLineType - { - get - { - return _underlineType; - } - set - { - _underlineType = value; - } - } - const string verticalAlignPath = "d:vertAlign/@val"; - string _verticalAlign; - /// <summary> - /// Vertical aligned - /// </summary> - public string VerticalAlign - { - get - { - return _verticalAlign; - } - set - { - _verticalAlign=value; - } - } - public void SetFromFont(System.Drawing.Font Font) - { - Name=Font.Name; - //Family=fnt.FontFamily.; - Size=(int)Font.Size; - Strike=Font.Strikeout; - Bold = Font.Bold; - UnderLine=Font.Underline; - Italic=Font.Italic; - } - internal ExcelFontXml Copy() - { - ExcelFontXml newFont = new ExcelFontXml(NameSpaceManager); - newFont.Name = _name; - newFont.Size = _size; - newFont.Family = _family; - newFont.Scheme = _scheme; - newFont.Bold = _bold; - newFont.Italic = _italic; - newFont.UnderLineType = _underlineType; - newFont.Strike = _strike; - newFont.VerticalAlign = _verticalAlign; - newFont.Color = Color.Copy(); - return newFont; - } +namespace OfficeOpenXml.Style.XmlAccess; - internal override XmlNode CreateXmlNode(XmlNode topElement) - { - TopNode = topElement; +/// <summary> +/// Xml access class for fonts +/// </summary> +public sealed class ExcelFontXml : StyleXmlHelper { + internal ExcelFontXml(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) { + _name = ""; + _size = 0; + _family = int.MinValue; + _scheme = ""; + _color = _color = new(NameSpaceManager); + _bold = false; + _italic = false; + _strike = false; + _underlineType = ExcelUnderLineType.None; + _verticalAlign = ""; + } - if (_bold) CreateNode(boldPath); else DeleteAllNode(boldPath); - if (_italic) CreateNode(italicPath); else DeleteAllNode(italicPath); - if (_strike) CreateNode(strikePath); else DeleteAllNode(strikePath); - - if (_underlineType == ExcelUnderLineType.None) - { - DeleteAllNode(underLinedPath); - } - else if(_underlineType==ExcelUnderLineType.Single) - { - CreateNode(underLinedPath); - } - else - { - var v=_underlineType.ToString(); - SetXmlNodeString(underLinedPath + "/@val", v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1)); - } - - if (_verticalAlign!="") SetXmlNodeString(verticalAlignPath, _verticalAlign.ToString()); - if(_size>0) SetXmlNodeString(sizePath, _size.ToString(System.Globalization.CultureInfo.InvariantCulture)); - if (_color.Exists) - { - CreateNode(_colorPath); - TopNode.AppendChild(_color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath, NameSpaceManager))); - } - if(!string.IsNullOrEmpty(_name)) SetXmlNodeString(namePath, _name); - if(_family>int.MinValue) SetXmlNodeString(familyPath, _family.ToString()); - if (_scheme != "") SetXmlNodeString(schemePath, _scheme.ToString()); - - return TopNode; - } + internal ExcelFontXml(XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + _name = GetXmlNodeString(_namePath); + _size = (float)GetXmlNodeDecimal(_sizePath); + _family = GetXmlNodeIntNull(_familyPath) ?? int.MinValue; + _scheme = GetXmlNodeString(_schemePath); + _color = new(nsm, topNode.SelectSingleNode(_colorPath, nsm)); + _bold = GetBoolValue(topNode, _boldPath); + _italic = GetBoolValue(topNode, _italicPath); + _strike = GetBoolValue(topNode, _strikePath); + _verticalAlign = GetXmlNodeString(_verticalAlignPath); + if (topNode.SelectSingleNode(_underLinedPath, NameSpaceManager) != null) { + string ut = GetXmlNodeString(_underLinedPath + "/@val"); + if (ut == "") { + _underlineType = ExcelUnderLineType.Single; + } else { + _underlineType = (ExcelUnderLineType)Enum.Parse(typeof(ExcelUnderLineType), ut, true); + } + } else { + _underlineType = ExcelUnderLineType.None; } + } + + internal override string Id => + Name + + "|" + + Size + + "|" + + Family + + "|" + + Color.Id + + "|" + + Scheme + + "|" + + Bold + + "|" + + Italic + + "|" + + Strike + + "|" + + VerticalAlign + + "|" + + UnderLineType; + + private const string _namePath = "d:name/@val"; + private string _name; + + /// <summary> + /// The name of the font + /// </summary> + public string Name { + get { return _name; } + set { + Scheme = ""; //Reset schema to avoid corrupt file if unsupported font is selected. + _name = value; + } + } + + private const string _sizePath = "d:sz/@val"; + private float _size; + + /// <summary> + /// Font size + /// </summary> + public float Size { + get { return _size; } + set { _size = value; } + } + + private const string _familyPath = "d:family/@val"; + private int _family; + + /// <summary> + /// Font family + /// </summary> + public int Family { + get { + return (_family == int.MinValue ? 0 : _family); + ; + } + set { _family = value; } + } + + private ExcelColorXml _color; + private const string _colorPath = "d:color"; + + /// <summary> + /// Text color + /// </summary> + public ExcelColorXml Color { + get { return _color; } + internal set { _color = value; } + } + + private const string _schemePath = "d:scheme/@val"; + private string _scheme = ""; + + /// <summary> + /// Font Scheme + /// </summary> + public string Scheme { + get { return _scheme; } + private set { _scheme = value; } + } + + private const string _boldPath = "d:b"; + private bool _bold; + + /// <summary> + /// If the font is bold + /// </summary> + public bool Bold { + get { return _bold; } + set { _bold = value; } + } + + private const string _italicPath = "d:i"; + private bool _italic; + + /// <summary> + /// If the font is italic + /// </summary> + public bool Italic { + get { return _italic; } + set { _italic = value; } + } + + private const string _strikePath = "d:strike"; + private bool _strike; + + /// <summary> + /// If the font is striked out + /// </summary> + public bool Strike { + get { return _strike; } + set { _strike = value; } + } + + private const string _underLinedPath = "d:u"; + + /// <summary> + /// If the font is underlined. + /// When set to true a the text is underlined with a single line + /// </summary> + public bool UnderLine { + get { return UnderLineType != ExcelUnderLineType.None; } + set { _underlineType = value ? ExcelUnderLineType.Single : ExcelUnderLineType.None; } + } + + private ExcelUnderLineType _underlineType; + + /// <summary> + /// If the font is underlined + /// </summary> + public ExcelUnderLineType UnderLineType { + get { return _underlineType; } + set { _underlineType = value; } + } + + private const string _verticalAlignPath = "d:vertAlign/@val"; + private string _verticalAlign; + + /// <summary> + /// Vertical aligned + /// </summary> + public string VerticalAlign { + get { return _verticalAlign; } + set { _verticalAlign = value; } + } + + public void SetFromFont(Font font) { + Name = font.Name; + //Family=fnt.FontFamily.; + Size = (int)font.Size; + Strike = font.Strikeout; + Bold = font.Bold; + UnderLine = font.Underline; + Italic = font.Italic; + } + + internal ExcelFontXml Copy() { + ExcelFontXml newFont = new ExcelFontXml(NameSpaceManager); + newFont.Name = _name; + newFont.Size = _size; + newFont.Family = _family; + newFont.Scheme = _scheme; + newFont.Bold = _bold; + newFont.Italic = _italic; + newFont.UnderLineType = _underlineType; + newFont.Strike = _strike; + newFont.VerticalAlign = _verticalAlign; + newFont.Color = Color.Copy(); + return newFont; + } + + internal override XmlNode CreateXmlNode(XmlNode topElement) { + TopNode = topElement; + + if (_bold) { + CreateNode(_boldPath); + } else { + DeleteAllNode(_boldPath); + } + if (_italic) { + CreateNode(_italicPath); + } else { + DeleteAllNode(_italicPath); + } + if (_strike) { + CreateNode(_strikePath); + } else { + DeleteAllNode(_strikePath); + } + + if (_underlineType == ExcelUnderLineType.None) { + DeleteAllNode(_underLinedPath); + } else if (_underlineType == ExcelUnderLineType.Single) { + CreateNode(_underLinedPath); + } else { + var v = _underlineType.ToString(); + SetXmlNodeString( + _underLinedPath + "/@val", + v.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + v.Substring(1)); + } + + if (_verticalAlign != "") { + SetXmlNodeString(_verticalAlignPath, _verticalAlign); + } + if (_size > 0) { + SetXmlNodeString(_sizePath, _size.ToString(CultureInfo.InvariantCulture)); + } + if (_color.Exists) { + CreateNode(_colorPath); + TopNode.AppendChild( + _color.CreateXmlNode(TopNode.SelectSingleNode(_colorPath, NameSpaceManager))); + } + if (!string.IsNullOrEmpty(_name)) { + SetXmlNodeString(_namePath, _name); + } + if (_family > int.MinValue) { + SetXmlNodeString(_familyPath, _family.ToString()); + } + if (_scheme != "") { + SetXmlNodeString(_schemePath, _scheme); + } + + return TopNode; + } }
diff --git a/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs b/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs index adaf0a5..00adf5e 100644 --- a/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelGradientFillXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,186 +13,172 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; + using System.Globalization; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for gradient fillsde - /// </summary> - public sealed class ExcelGradientFillXml : ExcelFillXml - { - internal ExcelGradientFillXml(XmlNamespaceManager nameSpaceManager) - : base(nameSpaceManager) - { - GradientColor1 = new ExcelColorXml(nameSpaceManager); - GradientColor2 = new ExcelColorXml(nameSpaceManager); - } - internal ExcelGradientFillXml(XmlNamespaceManager nsm, XmlNode topNode) : - base(nsm, topNode) - { - Degree = GetXmlNodeDouble(_degreePath); - Type = GetXmlNodeString(_typePath)=="path" ? ExcelFillGradientType.Path : ExcelFillGradientType.Linear; - GradientColor1 = new ExcelColorXml(nsm, topNode.SelectSingleNode(_gradientColor1Path, nsm)); - GradientColor2 = new ExcelColorXml(nsm, topNode.SelectSingleNode(_gradientColor2Path, nsm)); - - Top = GetXmlNodeDouble(_topPath); - Bottom = GetXmlNodeDouble(_bottomPath); - Left = GetXmlNodeDouble(_leftPath); - Right = GetXmlNodeDouble(_rightPath); - } - const string _typePath = "d:gradientFill/@type"; - /// <summary> - /// Type of gradient fill. - /// </summary> - public ExcelFillGradientType Type - { - get; - internal set; - } - const string _degreePath = "d:gradientFill/@degree"; - /// <summary> - /// Angle of the linear gradient - /// </summary> - public double Degree - { - get; - internal set; - } - const string _gradientColor1Path = "d:gradientFill/d:stop[@position=\"0\"]/d:color"; - /// <summary> - /// Gradient color 1 - /// </summary> - public ExcelColorXml GradientColor1 - { - get; - private set; - } - const string _gradientColor2Path = "d:gradientFill/d:stop[@position=\"1\"]/d:color"; - /// <summary> - /// Gradient color 2 - /// </summary> - public ExcelColorXml GradientColor2 - { - get; - private set; - } - const string _bottomPath = "d:gradientFill/@bottom"; - /// <summary> - /// Percentage format bottom - /// </summary> - public double Bottom - { - get; - internal set; - } - const string _topPath = "d:gradientFill/@top"; - /// <summary> - /// Percentage format top - /// </summary> - public double Top - { - get; - internal set; - } - const string _leftPath = "d:gradientFill/@left"; - /// <summary> - /// Percentage format left - /// </summary> - public double Left - { - get; - internal set; - } - const string _rightPath = "d:gradientFill/@right"; - /// <summary> - /// Percentage format right - /// </summary> - public double Right - { - get; - internal set; - } - internal override string Id - { - get - { - return base.Id + Degree.ToString() + GradientColor1.Id + GradientColor2.Id + Type + Left.ToString() + Right.ToString() + Bottom.ToString() + Top.ToString(); - } - } +using System.Xml; - #region Public Properties - #endregion - internal override ExcelFillXml Copy() - { - ExcelGradientFillXml newFill = new ExcelGradientFillXml(NameSpaceManager); - newFill.PatternType = base._fillPatternType; - newFill.BackgroundColor = _backgroundColor.Copy(); - newFill.PatternColor = _patternColor.Copy(); +namespace OfficeOpenXml.Style.XmlAccess; - newFill.GradientColor1 = GradientColor1.Copy(); - newFill.GradientColor2 = GradientColor2.Copy(); - newFill.Type = Type; - newFill.Degree = Degree; - newFill.Top = Top; - newFill.Bottom = Bottom; - newFill.Left = Left; - newFill.Right = Right; - - return newFill; - } +/// <summary> +/// Xml access class for gradient fillsde +/// </summary> +public sealed class ExcelGradientFillXml : ExcelFillXml { + internal ExcelGradientFillXml(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) { + GradientColor1 = new(nameSpaceManager); + GradientColor2 = new(nameSpaceManager); + } - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - TopNode = topNode; - CreateNode("d:gradientFill"); - if(Type==ExcelFillGradientType.Path) SetXmlNodeString(_typePath, "path"); - if(!double.IsNaN(Degree)) SetXmlNodeString(_degreePath, Degree.ToString(CultureInfo.InvariantCulture)); - if (GradientColor1!=null) - { - /*** Gradient color node 1***/ - var node = TopNode.SelectSingleNode("d:gradientFill", NameSpaceManager); - var stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage.schemaMain); - stopNode.SetAttribute("position", "0"); - node.AppendChild(stopNode); - var colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage.schemaMain); - stopNode.AppendChild(colorNode); - GradientColor1.CreateXmlNode(colorNode); + internal ExcelGradientFillXml(XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + Degree = GetXmlNodeDouble(_degreePath); + Type = + GetXmlNodeString(_typePath) == "path" + ? ExcelFillGradientType.Path + : ExcelFillGradientType.Linear; + GradientColor1 = new(nsm, topNode.SelectSingleNode(_gradientColor1Path, nsm)); + GradientColor2 = new(nsm, topNode.SelectSingleNode(_gradientColor2Path, nsm)); - /*** Gradient color node 2***/ - stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage.schemaMain); - stopNode.SetAttribute("position", "1"); - node.AppendChild(stopNode); - colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage.schemaMain); - stopNode.AppendChild(colorNode); + Top = GetXmlNodeDouble(_topPath); + Bottom = GetXmlNodeDouble(_bottomPath); + Left = GetXmlNodeDouble(_leftPath); + Right = GetXmlNodeDouble(_rightPath); + } - GradientColor2.CreateXmlNode(colorNode); - } - if (!double.IsNaN(Top)) SetXmlNodeString(_topPath, Top.ToString("F5",CultureInfo.InvariantCulture)); - if (!double.IsNaN(Bottom)) SetXmlNodeString(_bottomPath, Bottom.ToString("F5", CultureInfo.InvariantCulture)); - if (!double.IsNaN(Left)) SetXmlNodeString(_leftPath, Left.ToString("F5", CultureInfo.InvariantCulture)); - if (!double.IsNaN(Right)) SetXmlNodeString(_rightPath, Right.ToString("F5", CultureInfo.InvariantCulture)); + private const string _typePath = "d:gradientFill/@type"; - return topNode; - } + /// <summary> + /// Type of gradient fill. + /// </summary> + public ExcelFillGradientType Type { get; internal set; } + + private const string _degreePath = "d:gradientFill/@degree"; + + /// <summary> + /// Angle of the linear gradient + /// </summary> + public double Degree { get; internal set; } + + private const string _gradientColor1Path = "d:gradientFill/d:stop[@position=\"0\"]/d:color"; + + /// <summary> + /// Gradient color 1 + /// </summary> + public ExcelColorXml GradientColor1 { get; private set; } + + private const string _gradientColor2Path = "d:gradientFill/d:stop[@position=\"1\"]/d:color"; + + /// <summary> + /// Gradient color 2 + /// </summary> + public ExcelColorXml GradientColor2 { get; private set; } + + private const string _bottomPath = "d:gradientFill/@bottom"; + + /// <summary> + /// Percentage format bottom + /// </summary> + public double Bottom { get; internal set; } + + private const string _topPath = "d:gradientFill/@top"; + + /// <summary> + /// Percentage format top + /// </summary> + public double Top { get; internal set; } + + private const string _leftPath = "d:gradientFill/@left"; + + /// <summary> + /// Percentage format left + /// </summary> + public double Left { get; internal set; } + + private const string _rightPath = "d:gradientFill/@right"; + + /// <summary> + /// Percentage format right + /// </summary> + public double Right { get; internal set; } + + internal override string Id => + base.Id + Degree + GradientColor1.Id + GradientColor2.Id + Type + Left + Right + Bottom + Top; + + internal override ExcelFillXml Copy() { + ExcelGradientFillXml newFill = new ExcelGradientFillXml(NameSpaceManager); + newFill.PatternType = _fillPatternType; + newFill.BackgroundColor = _backgroundColor.Copy(); + newFill.PatternColor = _patternColor.Copy(); + + newFill.GradientColor1 = GradientColor1.Copy(); + newFill.GradientColor2 = GradientColor2.Copy(); + newFill.Type = Type; + newFill.Degree = Degree; + newFill.Top = Top; + newFill.Bottom = Bottom; + newFill.Left = Left; + newFill.Right = Right; + + return newFill; + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + TopNode = topNode; + CreateNode("d:gradientFill"); + if (Type == ExcelFillGradientType.Path) { + SetXmlNodeString(_typePath, "path"); } + if (!double.IsNaN(Degree)) { + SetXmlNodeString(_degreePath, Degree.ToString(CultureInfo.InvariantCulture)); + } + if (GradientColor1 != null) { + /*** Gradient color node 1***/ + var node = TopNode.SelectSingleNode("d:gradientFill", NameSpaceManager); + var stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage._schemaMain); + stopNode.SetAttribute("position", "0"); + node.AppendChild(stopNode); + var colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage._schemaMain); + stopNode.AppendChild(colorNode); + GradientColor1.CreateXmlNode(colorNode); + + /*** Gradient color node 2***/ + stopNode = node.OwnerDocument.CreateElement("stop", ExcelPackage._schemaMain); + stopNode.SetAttribute("position", "1"); + node.AppendChild(stopNode); + colorNode = node.OwnerDocument.CreateElement("color", ExcelPackage._schemaMain); + stopNode.AppendChild(colorNode); + + GradientColor2.CreateXmlNode(colorNode); + } + if (!double.IsNaN(Top)) { + SetXmlNodeString(_topPath, Top.ToString("F5", CultureInfo.InvariantCulture)); + } + if (!double.IsNaN(Bottom)) { + SetXmlNodeString(_bottomPath, Bottom.ToString("F5", CultureInfo.InvariantCulture)); + } + if (!double.IsNaN(Left)) { + SetXmlNodeString(_leftPath, Left.ToString("F5", CultureInfo.InvariantCulture)); + } + if (!double.IsNaN(Right)) { + SetXmlNodeString(_rightPath, Right.ToString("F5", CultureInfo.InvariantCulture)); + } + + return topNode; + } }
diff --git a/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs b/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs index 77de394..599052c 100644 --- a/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelNamedStyleXml.cs
@@ -13,133 +13,115 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; + using System.Xml; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for named styles - /// </summary> - public sealed class ExcelNamedStyleXml : StyleXmlHelper - { - ExcelStyles _styles; - internal ExcelNamedStyleXml(XmlNamespaceManager nameSpaceManager, ExcelStyles styles) - : base(nameSpaceManager) - { - _styles = styles; - BuildInId = int.MinValue; - } - internal ExcelNamedStyleXml(XmlNamespaceManager NameSpaceManager, XmlNode topNode, ExcelStyles styles) : - base(NameSpaceManager, topNode) - { - StyleXfId = GetXmlNodeInt(idPath); - Name = GetXmlNodeString(namePath); - BuildInId = GetXmlNodeInt(buildInIdPath); - CustomBuildin = GetXmlNodeBool(customBuiltinPath); - _styles = styles; - _style = new ExcelStyle(styles, styles.NamedStylePropertyChange, -1, Name, _styleXfId); - } - internal override string Id - { - get - { - return Name; - } - } - int _styleXfId=0; - const string idPath = "@xfId"; - /// <summary> - /// Named style index - /// </summary> - public int StyleXfId - { - get - { - return _styleXfId; - } - set - { - _styleXfId = value; - } - } - int _xfId = int.MinValue; - /// <summary> - /// Style index - /// </summary> - internal int XfId - { - get - { - return _xfId; - } - set - { - _xfId = value; - } - } - const string buildInIdPath = "@builtinId"; - public int BuildInId { get; set; } - const string customBuiltinPath = "@customBuiltin"; - public bool CustomBuildin { get; set; } - const string namePath = "@name"; - string _name; - /// <summary> - /// Name of the style - /// </summary> - public string Name - { - get - { - return _name; - } - internal set - { - _name = value; - } - } - ExcelStyle _style = null; - /// <summary> - /// The style object - /// </summary> - public ExcelStyle Style - { - get - { - return _style; - } - internal set - { - _style = value; - } - } +namespace OfficeOpenXml.Style.XmlAccess; - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - TopNode = topNode; - SetXmlNodeString(namePath, _name); - SetXmlNodeString("@xfId", _styles.CellStyleXfs[StyleXfId].newID.ToString()); - if (BuildInId>=0) SetXmlNodeString("@builtinId", BuildInId.ToString()); - if(CustomBuildin) SetXmlNodeBool(customBuiltinPath, true); - return TopNode; - } +/// <summary> +/// Xml access class for named styles +/// </summary> +public sealed class ExcelNamedStyleXml : StyleXmlHelper { + private ExcelStyles _styles; + + internal ExcelNamedStyleXml(XmlNamespaceManager nameSpaceManager, ExcelStyles styles) + : base(nameSpaceManager) { + _styles = styles; + BuildInId = int.MinValue; + } + + internal ExcelNamedStyleXml( + XmlNamespaceManager nameSpaceManager, + XmlNode topNode, + ExcelStyles styles) + : base(nameSpaceManager, topNode) { + StyleXfId = GetXmlNodeInt(_idPath); + Name = GetXmlNodeString(_namePath); + BuildInId = GetXmlNodeInt(_buildInIdPath); + CustomBuildin = GetXmlNodeBool(_customBuiltinPath); + + _styles = styles; + _style = new(styles, styles.NamedStylePropertyChange, -1, Name, _styleXfId); + } + + internal override string Id => Name; + + private int _styleXfId; + private const string _idPath = "@xfId"; + + /// <summary> + /// Named style index + /// </summary> + public int StyleXfId { + get => _styleXfId; + set => _styleXfId = value; + } + + private int _xfId = int.MinValue; + + /// <summary> + /// Style index + /// </summary> + internal int XfId { + get => _xfId; + set => _xfId = value; + } + + private const string _buildInIdPath = "@builtinId"; + + public int BuildInId { get; set; } + + private const string _customBuiltinPath = "@customBuiltin"; + + public bool CustomBuildin { get; set; } + + private const string _namePath = "@name"; + private string _name; + + /// <summary> + /// Name of the style + /// </summary> + public string Name { + get => _name; + internal set => _name = value; + } + + private ExcelStyle _style; + + /// <summary> + /// The style object + /// </summary> + public ExcelStyle Style { + get => _style; + internal set => _style = value; + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + TopNode = topNode; + SetXmlNodeString(_namePath, _name); + SetXmlNodeString("@xfId", _styles.CellStyleXfs[StyleXfId].newID.ToString()); + if (BuildInId >= 0) { + SetXmlNodeString("@builtinId", BuildInId.ToString()); } + if (CustomBuildin) { + SetXmlNodeBool(_customBuiltinPath, true); + } + return TopNode; + } }
diff --git a/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs b/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs index 410a2dd..0d0b46f 100644 --- a/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelNumberFormatXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,658 +13,691 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Text; -using System.Xml; using System.Globalization; +using System.Text; using System.Text.RegularExpressions; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class for number formats - /// </summary> - public sealed class ExcelNumberFormatXml : StyleXmlHelper - { - internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager) : base(nameSpaceManager) - { - - } - internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager, bool buildIn): base(nameSpaceManager) - { - BuildIn = buildIn; - } - internal ExcelNumberFormatXml(XmlNamespaceManager nsm, XmlNode topNode) : - base(nsm, topNode) - { - _numFmtId = GetXmlNodeInt("@numFmtId"); - _format = GetXmlNodeString("@formatCode"); - } - public bool BuildIn { get; private set; } - int _numFmtId; -// const string idPath = "@numFmtId"; - /// <summary> - /// Id for number format - /// - /// Build in ID's - /// - /// 0 General - /// 1 0 - /// 2 0.00 - /// 3 #,##0 - /// 4 #,##0.00 - /// 9 0% - /// 10 0.00% - /// 11 0.00E+00 - /// 12 # ?/? - /// 13 # ??/?? - /// 14 mm-dd-yy - /// 15 d-mmm-yy - /// 16 d-mmm - /// 17 mmm-yy - /// 18 h:mm AM/PM - /// 19 h:mm:ss AM/PM - /// 20 h:mm - /// 21 h:mm:ss - /// 22 m/d/yy h:mm - /// 37 #,##0 ;(#,##0) - /// 38 #,##0 ;[Red](#,##0) - /// 39 #,##0.00;(#,##0.00) - /// 40 #,##0.00;[Red](#,##0.00) - /// 45 mm:ss - /// 46 [h]:mm:ss - /// 47 mmss.0 - /// 48 ##0.0E+0 - /// 49 @ - /// </summary> - public int NumFmtId - { - get - { - return _numFmtId; - } - set - { - _numFmtId = value; - } - } - internal override string Id - { - get - { - return _format; - } - } - const string fmtPath = "@formatCode"; - string _format = string.Empty; - public string Format - { - get - { - return _format; - } - set - { - _numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(value); - _format = value; - } - } - internal string GetNewID(int NumFmtId, string Format) - { - - if (NumFmtId < 0) - { - NumFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(Format); - } - return NumFmtId.ToString(); - } +using System.Xml; - internal static void AddBuildIn(XmlNamespaceManager NameSpaceManager, ExcelStyleCollection<ExcelNumberFormatXml> NumberFormats) - { - NumberFormats.Add("General",new ExcelNumberFormatXml(NameSpaceManager,true){NumFmtId=0,Format="General"}); - NumberFormats.Add("0", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 1, Format = "0" }); - NumberFormats.Add("0.00", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 2, Format = "0.00" }); - NumberFormats.Add("#,##0", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 3, Format = "#,##0" }); - NumberFormats.Add("#,##0.00", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 4, Format = "#,##0.00" }); - NumberFormats.Add("0%", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 9, Format = "0%" }); - NumberFormats.Add("0.00%", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 10, Format = "0.00%" }); - NumberFormats.Add("0.00E+00", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 11, Format = "0.00E+00" }); - NumberFormats.Add("# ?/?", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 12, Format = "# ?/?" }); - NumberFormats.Add("# ??/??", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 13, Format = "# ??/??" }); - NumberFormats.Add("mm-dd-yy", new ExcelNumberFormatXml(NameSpaceManager,true) { NumFmtId = 14, Format = "mm-dd-yy" }); - NumberFormats.Add("d-mmm-yy", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 15, Format = "d-mmm-yy" }); - NumberFormats.Add("d-mmm", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 16, Format = "d-mmm" }); - NumberFormats.Add("mmm-yy", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 17, Format = "mmm-yy" }); - NumberFormats.Add("h:mm AM/PM", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 18, Format = "h:mm AM/PM" }); - NumberFormats.Add("h:mm:ss AM/PM", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 19, Format = "h:mm:ss AM/PM" }); - NumberFormats.Add("h:mm", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 20, Format = "h:mm" }); - NumberFormats.Add("h:mm:ss", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 21, Format = "h:mm:ss" }); - NumberFormats.Add("m/d/yy h:mm", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 22, Format = "m/d/yy h:mm" }); - NumberFormats.Add("#,##0 ;(#,##0)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 37, Format = "#,##0 ;(#,##0)" }); - NumberFormats.Add("#,##0 ;[Red](#,##0)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 38, Format = "#,##0 ;[Red](#,##0)" }); - NumberFormats.Add("#,##0.00;(#,##0.00)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 39, Format = "#,##0.00;(#,##0.00)" }); - NumberFormats.Add("#,##0.00;[Red](#,##0.00)", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 40, Format = "#,##0.00;[Red](#,#)" }); - NumberFormats.Add("mm:ss", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 45, Format = "mm:ss" }); - NumberFormats.Add("[h]:mm:ss", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 46, Format = "[h]:mm:ss" }); - NumberFormats.Add("mmss.0", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 47, Format = "mmss.0" }); - NumberFormats.Add("##0.0", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 48, Format = "##0.0" }); - NumberFormats.Add("@", new ExcelNumberFormatXml(NameSpaceManager, true) { NumFmtId = 49, Format = "@" }); +namespace OfficeOpenXml.Style.XmlAccess; - NumberFormats.NextId = 164; //Start for custom formats. - } +/// <summary> +/// Xml access class for number formats +/// </summary> +public sealed class ExcelNumberFormatXml : StyleXmlHelper { + internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) {} - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - TopNode = topNode; - SetXmlNodeString("@numFmtId", NumFmtId.ToString()); - SetXmlNodeString("@formatCode", Format); - return TopNode; - } + internal ExcelNumberFormatXml(XmlNamespaceManager nameSpaceManager, bool buildIn) + : base(nameSpaceManager) { + BuildIn = buildIn; + } - internal enum eFormatType - { - Unknown = 0, - Number = 1, - DateTime = 2, - } - ExcelFormatTranslator _translator = null; - internal ExcelFormatTranslator FormatTranslator - { - get - { - if (_translator == null) - { - _translator = new ExcelFormatTranslator(Format, NumFmtId); - } - return _translator; - } - } - #region Excel --> .Net Format - internal class ExcelFormatTranslator - { - internal ExcelFormatTranslator(string format, int numFmtID) - { - if (numFmtID == 14) - { - NetFormat = NetFormatForWidth = "d"; - NetTextFormat = NetTextFormatForWidth = ""; - DataType = eFormatType.DateTime; - } - else if (format.Equals("general",StringComparison.InvariantCultureIgnoreCase)) - { - NetFormat = NetFormatForWidth = "0.#####"; - NetTextFormat = NetTextFormatForWidth = ""; - DataType = eFormatType.Number; - } - else - { - ToNetFormat(format, false); - ToNetFormat(format, true); - } - } - internal string NetTextFormat { get; private set; } - internal string NetFormat { get; private set; } - CultureInfo _ci = null; - internal CultureInfo Culture - { - get - { - if (_ci == null) - { - return CultureInfo.CurrentCulture; - } - return _ci; - } - private set - { - _ci = value; - } - } - internal eFormatType DataType { get; private set; } - internal string NetTextFormatForWidth { get; private set; } - internal string NetFormatForWidth { get; private set; } + internal ExcelNumberFormatXml(XmlNamespaceManager nsm, XmlNode topNode) + : base(nsm, topNode) { + _numFmtId = GetXmlNodeInt("@numFmtId"); + _format = GetXmlNodeString("@formatCode"); + } - //internal string FractionFormatInteger { get; private set; } - internal string FractionFormat { get; private set; } - //internal string FractionFormat2 { get; private set; } + public bool BuildIn { get; private set; } - private void ToNetFormat(string ExcelFormat, bool forColWidth) - { - DataType = eFormatType.Unknown; - int secCount = 0; - bool isText = false; - bool isBracket = false; - string bracketText = ""; - bool prevBslsh = false; - bool useMinute = false; - bool prevUnderScore = false; - bool ignoreNext = false; - int fractionPos = -1; - string specialDateFormat = ""; - bool containsAmPm = ExcelFormat.Contains("AM/PM"); - List<int> lstDec=new List<int>(); - StringBuilder sb = new StringBuilder(); - Culture = null; - var format = ""; - var text = ""; - char clc; + private int _numFmtId; - if (containsAmPm) - { - ExcelFormat = Regex.Replace(ExcelFormat, "AM/PM", ""); - DataType = eFormatType.DateTime; - } + // const string idPath = "@numFmtId"; + /// <summary> + /// Id for number format + /// + /// Build in ID's + /// + /// 0 General + /// 1 0 + /// 2 0.00 + /// 3 #,##0 + /// 4 #,##0.00 + /// 9 0% + /// 10 0.00% + /// 11 0.00E+00 + /// 12 # ?/? + /// 13 # ??/?? + /// 14 mm-dd-yy + /// 15 d-mmm-yy + /// 16 d-mmm + /// 17 mmm-yy + /// 18 h:mm AM/PM + /// 19 h:mm:ss AM/PM + /// 20 h:mm + /// 21 h:mm:ss + /// 22 m/d/yy h:mm + /// 37 #,##0 ;(#,##0) + /// 38 #,##0 ;[Red](#,##0) + /// 39 #,##0.00;(#,##0.00) + /// 40 #,##0.00;[Red](#,##0.00) + /// 45 mm:ss + /// 46 [h]:mm:ss + /// 47 mmss.0 + /// 48 ##0.0E+0 + /// 49 @ + /// </summary> + public int NumFmtId { + get => _numFmtId; + set => _numFmtId = value; + } - for (int pos = 0; pos < ExcelFormat.Length; pos++) - { - char c = ExcelFormat[pos]; - if (c == '"') - { - isText = !isText; - } - else - { - if (ignoreNext) - { - ignoreNext = false; - continue; - } - else if (isText && !isBracket) - { - sb.Append(c); - } - else if (isBracket) - { - if (c == ']') - { - isBracket = false; - if (bracketText[0] == '$') //Local Info - { - string[] li = Regex.Split(bracketText, "-"); - if (li[0].Length > 1) - { - sb.Append("\"" + li[0].Substring(1, li[0].Length - 1) + "\""); //Currency symbol - } - if (li.Length > 1) - { - if (li[1].Equals("f800", StringComparison.InvariantCultureIgnoreCase)) - { - specialDateFormat = "D"; - } - else if (li[1].Equals("f400", StringComparison.InvariantCultureIgnoreCase)) - { - specialDateFormat = "T"; - } - else - { - var num = int.Parse(li[1], NumberStyles.HexNumber); - try - { - Culture = CultureInfo.GetCultureInfo(num & 0xFFFF); - } - catch - { - Culture = null; - } - } - } - } - else if(bracketText[0]=='t') - { - sb.Append("hh"); //TODO:This will not be correct for dates over 24H. - } - else if (bracketText[0] == 'h') - { - specialDateFormat = "hh"; //TODO:This will not be correct for dates over 24H. - } - } - else - { - bracketText += c; - } - } - else if (prevUnderScore) - { - if (forColWidth) - { - sb.AppendFormat("\"{0}\"", c); - } - prevUnderScore = false; - } - else - { - if (c == ';') //We use first part (for positive only at this stage) - { - secCount++; - if (DataType == eFormatType.DateTime || secCount == 3) - { - //Add qoutes - if (DataType == eFormatType.DateTime) SetDecimal(lstDec, sb); //Remove? - lstDec = new List<int>(); - format = sb.ToString(); - sb = new StringBuilder(); - } - else - { - sb.Append(c); - } - } - else - { - clc = c.ToString().ToLower(CultureInfo.InvariantCulture)[0]; //Lowercase character - //Set the datetype - if (DataType == eFormatType.Unknown) - { - if (c == '0' || c == '#' || c == '.') - { - DataType = eFormatType.Number; - } - else if (clc == 'y' || clc == 'm' || clc == 'd' || clc == 'h' || clc == 'm' || clc == 's') - { - DataType = eFormatType.DateTime; - } - } + internal override string Id => _format; - if (prevBslsh) - { - if (c == '.' || c == ',') - { - sb.Append('\\'); - } - sb.Append(c); - prevBslsh = false; - } - else if (c == '[') - { - bracketText = ""; - isBracket = true; - } - else if (c == '\\') - { - prevBslsh = true; - } - else if (c == '0' || - c == '#' || - c == '.' || - c == ',' || - c == '%' || - clc == 'd' || - clc == 's') - { - sb.Append(c); - if(c=='.') - { - lstDec.Add(sb.Length - 1); - } - } - else if (clc == 'h') - { - if (containsAmPm) - { - sb.Append('h'); ; - } - else - { - sb.Append('H'); - } - useMinute = true; - } - else if (clc == 'm') - { - if (useMinute) - { - sb.Append('m'); - } - else - { - sb.Append('M'); - } - } - else if (c == '_') //Skip next but use for alignment - { - prevUnderScore = true; - } - else if (c == '?') - { - sb.Append(' '); - } - else if (c == '/') - { - if (DataType == eFormatType.Number) - { - fractionPos = sb.Length; - int startPos = pos - 1; - while (startPos >= 0 && - (ExcelFormat[startPos] == '?' || - ExcelFormat[startPos] == '#' || - ExcelFormat[startPos] == '0')) - { - startPos--; - } + private const string _fmtPath = "@formatCode"; + private string _format = string.Empty; - if (startPos > 0) //RemovePart - sb.Remove(sb.Length-(pos-startPos-1),(pos-startPos-1)) ; - - int endPos = pos + 1; - while (endPos < ExcelFormat.Length && - (ExcelFormat[endPos] == '?' || - ExcelFormat[endPos] == '#' || - (ExcelFormat[endPos] >= '0' && ExcelFormat[endPos]<= '9'))) - { - endPos++; - } - pos = endPos; - if (FractionFormat != "") - { - FractionFormat = ExcelFormat.Substring(startPos+1, endPos - startPos-1); - } - sb.Append('?'); //Will be replaced later on by the fraction - } - else - { - sb.Append('/'); - } - } - else if (c == '*') - { - //repeat char--> ignore - ignoreNext = true; - } - else if (c == '@') - { - sb.Append("{0}"); - } - else - { - sb.Append(c); - } - } - } - } - } - - //Add qoutes - if (DataType == eFormatType.DateTime) SetDecimal(lstDec, sb); //Remove? - - // AM/PM format - if (containsAmPm) - { - format += "tt"; - } - - - if (format == "") - format = sb.ToString(); - else - text = sb.ToString(); - if (specialDateFormat != "") - { - format = specialDateFormat; - } - - if (forColWidth) - { - NetFormatForWidth = format; - NetTextFormatForWidth = text; - } - else - { - NetFormat = format; - NetTextFormat = text; - } - if (Culture == null) - { - Culture = CultureInfo.CurrentCulture; - } - } - - private static void SetDecimal(List<int> lstDec, StringBuilder sb) - { - if (lstDec.Count > 1) - { - for (int i = lstDec.Count - 1; i >= 0; i--) - { - sb.Insert(lstDec[i] + 1, '\''); - sb.Insert(lstDec[i], '\''); - } - } - } - - internal string FormatFraction(double d) - { - int numerator, denomerator; - - int intPart = (int)d; - - string[] fmt = FractionFormat.Split('/'); - - int fixedDenominator; - if (!int.TryParse(fmt[1], out fixedDenominator)) - { - fixedDenominator = 0; - } - - if (d == 0 || double.IsNaN(d)) - { - if (fmt[0].Trim() == "" && fmt[1].Trim() == "") - { - return new string(' ', FractionFormat.Length); - } - else - { - return 0.ToString(fmt[0]) + "/" + 1.ToString(fmt[0]); - } - } - - int maxDigits = fmt[1].Length; - string sign = d < 0 ? "-" : ""; - if (fixedDenominator == 0) - { - List<double> numerators = new List<double>() { 1, 0 }; - List<double> denominators = new List<double>() { 0, 1 }; - - if (maxDigits < 1 && maxDigits > 12) - { - throw (new ArgumentException("Number of digits out of range (1-12)")); - } - - int maxNum = 0; - for (int i = 0; i < maxDigits; i++) - { - maxNum += 9 * (int)(Math.Pow((double)10, (double)i)); - } - - double divRes = 1 / ((double)Math.Abs(d) - intPart); - double result, prevResult = double.NaN; - int listPos = 2, index = 1; - while (true) - { - index++; - double intDivRes = Math.Floor(divRes); - numerators.Add((intDivRes * numerators[index - 1] + numerators[index - 2])); - if (numerators[index] > maxNum) - { - break; - } - - denominators.Add((intDivRes * denominators[index - 1] + denominators[index - 2])); - - result = numerators[index] / denominators[index]; - if (denominators[index] > maxNum) - { - break; - } - listPos = index; - - if (result == prevResult) break; - - if (result == d) break; - - prevResult = result; - - divRes = 1 / (divRes - intDivRes); //Rest - } - - numerator = (int)numerators[listPos]; - denomerator = (int)denominators[listPos]; - } - else - { - numerator = (int)Math.Round((d - intPart) / (1D / fixedDenominator), 0); - denomerator = fixedDenominator; - } - if (numerator == denomerator || numerator==0) - { - if(numerator == denomerator) intPart++; - return sign + intPart.ToString(NetFormat).Replace("?", new string(' ', FractionFormat.Length)); - } - else if (intPart == 0) - { - return sign + FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1]); - } - else - { - return sign + intPart.ToString(NetFormat).Replace("?", FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1])); - } - } - - private string FmtInt(double value, string format) - { - string v = value.ToString("#"); - string pad = ""; - if (v.Length < format.Length) - { - for (int i = format.Length - v.Length-1; i >= 0; i--) - { - if (format[i] == '?') - { - pad += " "; - } - else if (format[i] == ' ') - { - pad += "0"; - } - } - } - return pad + v; - } - } - #endregion + public string Format { + get => _format; + set { + _numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(value); + _format = value; } + } + + internal string GetNewId(int numFmtId, string format) { + if (numFmtId < 0) { + numFmtId = ExcelNumberFormat.GetFromBuildIdFromFormat(format); + } + return numFmtId.ToString(); + } + + internal static void AddBuildIn( + XmlNamespaceManager nameSpaceManager, + ExcelStyleCollection<ExcelNumberFormatXml> numberFormats) { + numberFormats.Add( + "General", + new(nameSpaceManager, true) { + NumFmtId = 0, + Format = "General", + }); + numberFormats.Add( + "0", + new(nameSpaceManager, true) { + NumFmtId = 1, + Format = "0", + }); + numberFormats.Add( + "0.00", + new(nameSpaceManager, true) { + NumFmtId = 2, + Format = "0.00", + }); + numberFormats.Add( + "#,##0", + new(nameSpaceManager, true) { + NumFmtId = 3, + Format = "#,##0", + }); + numberFormats.Add( + "#,##0.00", + new(nameSpaceManager, true) { + NumFmtId = 4, + Format = "#,##0.00", + }); + numberFormats.Add( + "0%", + new(nameSpaceManager, true) { + NumFmtId = 9, + Format = "0%", + }); + numberFormats.Add( + "0.00%", + new(nameSpaceManager, true) { + NumFmtId = 10, + Format = "0.00%", + }); + numberFormats.Add( + "0.00E+00", + new(nameSpaceManager, true) { + NumFmtId = 11, + Format = "0.00E+00", + }); + numberFormats.Add( + "# ?/?", + new(nameSpaceManager, true) { + NumFmtId = 12, + Format = "# ?/?", + }); + numberFormats.Add( + "# ??/??", + new(nameSpaceManager, true) { + NumFmtId = 13, + Format = "# ??/??", + }); + numberFormats.Add( + "mm-dd-yy", + new(nameSpaceManager, true) { + NumFmtId = 14, + Format = "mm-dd-yy", + }); + numberFormats.Add( + "d-mmm-yy", + new(nameSpaceManager, true) { + NumFmtId = 15, + Format = "d-mmm-yy", + }); + numberFormats.Add( + "d-mmm", + new(nameSpaceManager, true) { + NumFmtId = 16, + Format = "d-mmm", + }); + numberFormats.Add( + "mmm-yy", + new(nameSpaceManager, true) { + NumFmtId = 17, + Format = "mmm-yy", + }); + numberFormats.Add( + "h:mm AM/PM", + new(nameSpaceManager, true) { + NumFmtId = 18, + Format = "h:mm AM/PM", + }); + numberFormats.Add( + "h:mm:ss AM/PM", + new(nameSpaceManager, true) { + NumFmtId = 19, + Format = "h:mm:ss AM/PM", + }); + numberFormats.Add( + "h:mm", + new(nameSpaceManager, true) { + NumFmtId = 20, + Format = "h:mm", + }); + numberFormats.Add( + "h:mm:ss", + new(nameSpaceManager, true) { + NumFmtId = 21, + Format = "h:mm:ss", + }); + numberFormats.Add( + "m/d/yy h:mm", + new(nameSpaceManager, true) { + NumFmtId = 22, + Format = "m/d/yy h:mm", + }); + numberFormats.Add( + "#,##0 ;(#,##0)", + new(nameSpaceManager, true) { + NumFmtId = 37, + Format = "#,##0 ;(#,##0)", + }); + numberFormats.Add( + "#,##0 ;[Red](#,##0)", + new(nameSpaceManager, true) { + NumFmtId = 38, + Format = "#,##0 ;[Red](#,##0)", + }); + numberFormats.Add( + "#,##0.00;(#,##0.00)", + new(nameSpaceManager, true) { + NumFmtId = 39, + Format = "#,##0.00;(#,##0.00)", + }); + numberFormats.Add( + "#,##0.00;[Red](#,##0.00)", + new(nameSpaceManager, true) { + NumFmtId = 40, + Format = "#,##0.00;[Red](#,#)", + }); + numberFormats.Add( + "mm:ss", + new(nameSpaceManager, true) { + NumFmtId = 45, + Format = "mm:ss", + }); + numberFormats.Add( + "[h]:mm:ss", + new(nameSpaceManager, true) { + NumFmtId = 46, + Format = "[h]:mm:ss", + }); + numberFormats.Add( + "mmss.0", + new(nameSpaceManager, true) { + NumFmtId = 47, + Format = "mmss.0", + }); + numberFormats.Add( + "##0.0", + new(nameSpaceManager, true) { + NumFmtId = 48, + Format = "##0.0", + }); + numberFormats.Add( + "@", + new(nameSpaceManager, true) { + NumFmtId = 49, + Format = "@", + }); + + numberFormats.NextId = 164; //Start for custom formats. + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + TopNode = topNode; + SetXmlNodeString("@numFmtId", NumFmtId.ToString()); + SetXmlNodeString("@formatCode", Format); + return TopNode; + } + + internal enum eFormatType { + Unknown = 0, + Number = 1, + DateTime = 2, + } + + private ExcelFormatTranslator _translator; + + internal ExcelFormatTranslator FormatTranslator { + get { + if (_translator == null) { + _translator = new(Format, NumFmtId); + } + return _translator; + } + } + + internal class ExcelFormatTranslator { + internal ExcelFormatTranslator(string format, int numFmtId) { + if (numFmtId == 14) { + NetFormat = NetFormatForWidth = "d"; + NetTextFormat = NetTextFormatForWidth = ""; + DataType = eFormatType.DateTime; + } else if (format.Equals("general", StringComparison.InvariantCultureIgnoreCase)) { + NetFormat = NetFormatForWidth = "0.#####"; + NetTextFormat = NetTextFormatForWidth = ""; + DataType = eFormatType.Number; + } else { + ToNetFormat(format, false); + ToNetFormat(format, true); + } + } + + internal string NetTextFormat { get; private set; } + + internal string NetFormat { get; private set; } + + private CultureInfo _ci; + + internal CultureInfo Culture { + get { + if (_ci == null) { + return CultureInfo.CurrentCulture; + } + return _ci; + } + private set => _ci = value; + } + + internal eFormatType DataType { get; private set; } + + internal string NetTextFormatForWidth { get; private set; } + + internal string NetFormatForWidth { get; private set; } + + //internal string FractionFormatInteger { get; private set; } + internal string FractionFormat { get; private set; } + + //internal string FractionFormat2 { get; private set; } + + private void ToNetFormat(string excelFormat, bool forColWidth) { + DataType = eFormatType.Unknown; + int secCount = 0; + bool isText = false; + bool isBracket = false; + string bracketText = ""; + bool prevBslsh = false; + bool useMinute = false; + bool prevUnderScore = false; + bool ignoreNext = false; + int fractionPos = -1; + string specialDateFormat = ""; + bool containsAmPm = excelFormat.Contains("AM/PM"); + List<int> lstDec = new List<int>(); + StringBuilder sb = new StringBuilder(); + Culture = null; + var format = ""; + var text = ""; + char clc; + + if (containsAmPm) { + excelFormat = Regex.Replace(excelFormat, "AM/PM", ""); + DataType = eFormatType.DateTime; + } + + for (int pos = 0; pos < excelFormat.Length; pos++) { + char c = excelFormat[pos]; + if (c == '"') { + isText = !isText; + } else { + if (ignoreNext) { + ignoreNext = false; + continue; + } + if (isText && !isBracket) { + sb.Append(c); + } else if (isBracket) { + if (c == ']') { + isBracket = false; + if (bracketText[0] + == '$') //Local Info + { + string[] li = Regex.Split(bracketText, "-"); + if (li[0].Length > 1) { + sb.Append("\"" + li[0].Substring(1, li[0].Length - 1) + "\""); //Currency symbol + } + if (li.Length > 1) { + if (li[1].Equals("f800", StringComparison.InvariantCultureIgnoreCase)) { + specialDateFormat = "D"; + } else if (li[1].Equals("f400", StringComparison.InvariantCultureIgnoreCase)) { + specialDateFormat = "T"; + } else { + var num = int.Parse(li[1], NumberStyles.HexNumber); + try { + Culture = CultureInfo.GetCultureInfo(num & 0xFFFF); + } catch { + Culture = null; + } + } + } + } else if (bracketText[0] == 't') { + sb.Append("hh"); //TODO:This will not be correct for dates over 24H. + } else if (bracketText[0] == 'h') { + specialDateFormat = "hh"; //TODO:This will not be correct for dates over 24H. + } + } else { + bracketText += c; + } + } else if (prevUnderScore) { + if (forColWidth) { + sb.AppendFormat("\"{0}\"", c); + } + prevUnderScore = false; + } else { + if (c + == ';') //We use first part (for positive only at this stage) + { + secCount++; + if (DataType == eFormatType.DateTime || secCount == 3) { + //Add qoutes + if (DataType == eFormatType.DateTime) { + SetDecimal(lstDec, sb); //Remove? + } + lstDec = new(); + format = sb.ToString(); + sb = new(); + } else { + sb.Append(c); + } + } else { + clc = c.ToString().ToLower(CultureInfo.InvariantCulture)[0]; //Lowercase character + //Set the datetype + if (DataType == eFormatType.Unknown) { + if (c == '0' || c == '#' || c == '.') { + DataType = eFormatType.Number; + } else if (clc == 'y' + || clc == 'm' + || clc == 'd' + || clc == 'h' + || clc == 'm' + || clc == 's') { + DataType = eFormatType.DateTime; + } + } + + if (prevBslsh) { + if (c == '.' || c == ',') { + sb.Append('\\'); + } + sb.Append(c); + prevBslsh = false; + } else if (c == '[') { + bracketText = ""; + isBracket = true; + } else if (c == '\\') { + prevBslsh = true; + } else if (c == '0' + || c == '#' + || c == '.' + || c == ',' + || c == '%' + || clc == 'd' + || clc == 's') { + sb.Append(c); + if (c == '.') { + lstDec.Add(sb.Length - 1); + } + } else if (clc == 'h') { + if (containsAmPm) { + sb.Append('h'); + ; + } else { + sb.Append('H'); + } + useMinute = true; + } else if (clc == 'm') { + if (useMinute) { + sb.Append('m'); + } else { + sb.Append('M'); + } + } else if (c + == '_') //Skip next but use for alignment + { + prevUnderScore = true; + } else if (c == '?') { + sb.Append(' '); + } else if (c == '/') { + if (DataType == eFormatType.Number) { + fractionPos = sb.Length; + int startPos = pos - 1; + while (startPos >= 0 + && (excelFormat[startPos] == '?' + || excelFormat[startPos] == '#' + || excelFormat[startPos] == '0')) { + startPos--; + } + + if (startPos + > 0) //RemovePart + { + sb.Remove(sb.Length - (pos - startPos - 1), (pos - startPos - 1)); + } + + int endPos = pos + 1; + while (endPos < excelFormat.Length + && (excelFormat[endPos] == '?' + || excelFormat[endPos] == '#' + || (excelFormat[endPos] >= '0' && excelFormat[endPos] <= '9'))) { + endPos++; + } + pos = endPos; + if (FractionFormat != "") { + FractionFormat = excelFormat.Substring(startPos + 1, endPos - startPos - 1); + } + sb.Append('?'); //Will be replaced later on by the fraction + } else { + sb.Append('/'); + } + } else if (c == '*') { + //repeat char--> ignore + ignoreNext = true; + } else if (c == '@') { + sb.Append("{0}"); + } else { + sb.Append(c); + } + } + } + } + } + + //Add qoutes + if (DataType == eFormatType.DateTime) { + SetDecimal(lstDec, sb); //Remove? + } + + // AM/PM format + if (containsAmPm) { + format += "tt"; + } + + if (format == "") { + format = sb.ToString(); + } else { + text = sb.ToString(); + } + if (specialDateFormat != "") { + format = specialDateFormat; + } + + if (forColWidth) { + NetFormatForWidth = format; + NetTextFormatForWidth = text; + } else { + NetFormat = format; + NetTextFormat = text; + } + if (Culture == null) { + Culture = CultureInfo.CurrentCulture; + } + } + + private static void SetDecimal(List<int> lstDec, StringBuilder sb) { + if (lstDec.Count > 1) { + for (int i = lstDec.Count - 1; i >= 0; i--) { + sb.Insert(lstDec[i] + 1, '\''); + sb.Insert(lstDec[i], '\''); + } + } + } + + internal string FormatFraction(double d) { + int numerator, + denomerator; + + int intPart = (int)d; + + string[] fmt = FractionFormat.Split('/'); + + int fixedDenominator; + if (!int.TryParse(fmt[1], out fixedDenominator)) { + fixedDenominator = 0; + } + + if (d == 0 || double.IsNaN(d)) { + if (fmt[0].Trim() == "" && fmt[1].Trim() == "") { + return new(' ', FractionFormat.Length); + } + return 0.ToString(fmt[0]) + "/" + 1.ToString(fmt[0]); + } + + int maxDigits = fmt[1].Length; + string sign = d < 0 ? "-" : ""; + if (fixedDenominator == 0) { + List<double> numerators = new List<double> { 1, 0 }; + List<double> denominators = new List<double> { 0, 1 }; + + if (maxDigits < 1 && maxDigits > 12) { + throw (new ArgumentException("Number of digits out of range (1-12)")); + } + + int maxNum = 0; + for (int i = 0; i < maxDigits; i++) { + maxNum += 9 * (int)(Math.Pow(10, i)); + } + + double divRes = 1 / (Math.Abs(d) - intPart); + double result, + prevResult = double.NaN; + int listPos = 2, + index = 1; + while (true) { + index++; + double intDivRes = Math.Floor(divRes); + numerators.Add((intDivRes * numerators[index - 1] + numerators[index - 2])); + if (numerators[index] > maxNum) { + break; + } + + denominators.Add((intDivRes * denominators[index - 1] + denominators[index - 2])); + + result = numerators[index] / denominators[index]; + if (denominators[index] > maxNum) { + break; + } + listPos = index; + + if (result == prevResult) { + break; + } + + if (result == d) { + break; + } + + prevResult = result; + + divRes = 1 / (divRes - intDivRes); //Rest + } + + numerator = (int)numerators[listPos]; + denomerator = (int)denominators[listPos]; + } else { + numerator = (int)Math.Round((d - intPart) / (1D / fixedDenominator), 0); + denomerator = fixedDenominator; + } + if (numerator == denomerator || numerator == 0) { + if (numerator == denomerator) { + intPart++; + } + return sign + intPart.ToString(NetFormat).Replace("?", new(' ', FractionFormat.Length)); + } + if (intPart == 0) { + return sign + FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1]); + } + return sign + + intPart + .ToString(NetFormat) + .Replace("?", FmtInt(numerator, fmt[0]) + "/" + FmtInt(denomerator, fmt[1])); + } + + private string FmtInt(double value, string format) { + string v = value.ToString("#"); + string pad = ""; + if (v.Length < format.Length) { + for (int i = format.Length - v.Length - 1; i >= 0; i--) { + if (format[i] == '?') { + pad += " "; + } else if (format[i] == ' ') { + pad += "0"; + } + } + } + return pad + v; + } + } }
diff --git a/EPPlus/Style/XmlAccess/ExcelXfsXml.cs b/EPPlus/Style/XmlAccess/ExcelXfsXml.cs index bee3e40..3b6f823 100644 --- a/EPPlus/Style/XmlAccess/ExcelXfsXml.cs +++ b/EPPlus/Style/XmlAccess/ExcelXfsXml.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,848 +13,736 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Globalization; -using System.Text; -using System.Xml; using System.Drawing; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml access class xfs records. This is the top level style object. - /// </summary> - public sealed class ExcelXfs : StyleXmlHelper - { - ExcelStyles _styles; - internal ExcelXfs(XmlNamespaceManager nameSpaceManager, ExcelStyles styles) : base(nameSpaceManager) - { - _styles = styles; - isBuildIn = false; - } - internal ExcelXfs(XmlNamespaceManager nsm, XmlNode topNode, ExcelStyles styles) : - base(nsm, topNode) - { - _styles = styles; - _xfID = GetXmlNodeInt("@xfId"); - if (_xfID == 0) isBuildIn = true; //Normal taggen - _numFmtId = GetXmlNodeInt("@numFmtId"); - _fontId = GetXmlNodeInt("@fontId"); - _fillId = GetXmlNodeInt("@fillId"); - _borderId = GetXmlNodeInt("@borderId"); - _readingOrder = GetReadingOrder(GetXmlNodeString(readingOrderPath)); - _indent = GetXmlNodeInt(indentPath); - _shrinkToFit = GetXmlNodeString(shrinkToFitPath) == "1" ? true : false; - _verticalAlignment = GetVerticalAlign(GetXmlNodeString(verticalAlignPath)); - _horizontalAlignment = GetHorizontalAlign(GetXmlNodeString(horizontalAlignPath)); - _wrapText = GetXmlNodeBool(wrapTextPath); - _textRotation = GetXmlNodeInt(textRotationPath); - _hidden = GetXmlNodeBool(hiddenPath); - _locked = GetXmlNodeBool(lockedPath,true); - } +using System.Globalization; +using System.Xml; - private ExcelReadingOrder GetReadingOrder(string value) - { - switch(value) - { - case "1": - return ExcelReadingOrder.LeftToRight; - case "2": - return ExcelReadingOrder.RightToLeft; - default: - return ExcelReadingOrder.ContextDependent; - } - } +namespace OfficeOpenXml.Style.XmlAccess; - private ExcelHorizontalAlignment GetHorizontalAlign(string align) - { - if (align == "") return ExcelHorizontalAlignment.General; - align = align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + align.Substring(1, align.Length - 1); - try - { - return (ExcelHorizontalAlignment)Enum.Parse(typeof(ExcelHorizontalAlignment), align); - } - catch - { - return ExcelHorizontalAlignment.General; - } - } +/// <summary> +/// Xml access class xfs records. This is the top level style object. +/// </summary> +public sealed class ExcelXfs : StyleXmlHelper { + private ExcelStyles _styles; - private ExcelVerticalAlignment GetVerticalAlign(string align) - { - if (align == "") return ExcelVerticalAlignment.Bottom; - align = align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + align.Substring(1, align.Length - 1); - try - { - return (ExcelVerticalAlignment)Enum.Parse(typeof(ExcelVerticalAlignment), align); - } - catch - { - return ExcelVerticalAlignment.Bottom; - } - } - internal void Xf_ChangedEvent(object sender, EventArgs e) - { - //if (_cell != null) - //{ - // if (!Styles.ChangedCells.ContainsKey(_cell.Id)) - // { - // //_cell.Style = ""; - // _cell.SetNewStyleID(int.MinValue.ToString()); - // Styles.ChangedCells.Add(_cell.Id, _cell); - // } - //} - } - int _xfID; - /// <summary> - /// Style index - /// </summary> - public int XfId - { - get - { - return _xfID; - } - set - { - _xfID = value; - } - } - #region Internal Properties - int _numFmtId; - internal int NumberFormatId - { - get - { - return _numFmtId; - } - set - { - _numFmtId = value; - ApplyNumberFormat = (value>0); - } - } - int _fontId; - internal int FontId - { - get - { - return _fontId; - } - set - { - _fontId = value; - } - } - int _fillId; - internal int FillId - { - get - { - return _fillId; - } - set - { - _fillId = value; - } - } - int _borderId; - internal int BorderId - { - get - { - return _borderId; - } - set - { - _borderId = value; - } - } - private bool isBuildIn - { - get; - set; - } - internal bool ApplyNumberFormat - { - get; - set; - } - internal bool ApplyFont - { - get; - set; - } - internal bool ApplyFill - { - get; - set; - } - internal bool ApplyBorder - { - get; - set; - } - internal bool ApplyAlignment - { - get; - set; - } - internal bool ApplyProtection - { - get; - set; - } - #endregion - #region Public Properties - public ExcelStyles Styles { get; private set; } - /// <summary> - /// Numberformat properties - /// </summary> - public ExcelNumberFormatXml Numberformat - { - get - { - return _styles.NumberFormats[_numFmtId < 0 ? 0 : _numFmtId]; - } - } - /// <summary> - /// Font properties - /// </summary> - public ExcelFontXml Font - { - get - { - return _styles.Fonts[_fontId < 0 ? 0 : _fontId]; - } - } - /// <summary> - /// Fill properties - /// </summary> - public ExcelFillXml Fill - { - get - { - return _styles.Fills[_fillId < 0 ? 0 : _fillId]; - } - } - /// <summary> - /// Border style properties - /// </summary> - public ExcelBorderXml Border - { - get - { - return _styles.Borders[_borderId < 0 ? 0 : _borderId]; - } - } - const string horizontalAlignPath = "d:alignment/@horizontal"; - ExcelHorizontalAlignment _horizontalAlignment = ExcelHorizontalAlignment.General; - /// <summary> - /// Horizontal alignment - /// </summary> - public ExcelHorizontalAlignment HorizontalAlignment - { - get - { - return _horizontalAlignment; - } - set - { - _horizontalAlignment = value; - } - } - const string verticalAlignPath = "d:alignment/@vertical"; - ExcelVerticalAlignment _verticalAlignment=ExcelVerticalAlignment.Bottom; - /// <summary> - /// Vertical alignment - /// </summary> - public ExcelVerticalAlignment VerticalAlignment - { - get - { - return _verticalAlignment; - } - set - { - _verticalAlignment = value; - } - } - const string wrapTextPath = "d:alignment/@wrapText"; - bool _wrapText=false; - /// <summary> - /// Wraped text - /// </summary> - public bool WrapText - { - get - { - return _wrapText; - } - set - { - _wrapText = value; - } - } - string textRotationPath = "d:alignment/@textRotation"; - int _textRotation = 0; - /// <summary> - /// Text rotation angle - /// </summary> - public int TextRotation - { - get - { - return (_textRotation == int.MinValue ? 0 : _textRotation); - } - set - { - _textRotation = value; - } - } - const string lockedPath = "d:protection/@locked"; - bool _locked = true; - /// <summary> - /// Locked when sheet is protected - /// </summary> - public bool Locked - { - get - { - return _locked; - } - set - { - _locked = value; - } - } - const string hiddenPath = "d:protection/@hidden"; - bool _hidden = false; - /// <summary> - /// Hide formulas when sheet is protected - /// </summary> - public bool Hidden - { - get - { - return _hidden; - } - set - { - _hidden = value; - } - } - const string readingOrderPath = "d:alignment/@readingOrder"; - ExcelReadingOrder _readingOrder = ExcelReadingOrder.ContextDependent; - /// <summary> - /// Readingorder - /// </summary> - public ExcelReadingOrder ReadingOrder - { - get - { - return _readingOrder; - } - set - { - _readingOrder = value; - } - } - const string shrinkToFitPath = "d:alignment/@shrinkToFit"; - bool _shrinkToFit = false; - /// <summary> - /// Shrink to fit - /// </summary> - public bool ShrinkToFit - { - get - { - return _shrinkToFit; - } - set - { - _shrinkToFit = value; - } - } - const string indentPath = "d:alignment/@indent"; - int _indent = 0; - /// <summary> - /// Indentation - /// </summary> - public int Indent - { - get - { - return (_indent == int.MinValue ? 0 : _indent); - } - set - { - _indent=value; - } - } - #endregion - internal void RegisterEvent(ExcelXfs xf) - { - // RegisterEvent(xf, xf.Xf_ChangedEvent); - } - internal override string Id - { + internal ExcelXfs(XmlNamespaceManager nameSpaceManager, ExcelStyles styles) + : base(nameSpaceManager) { + _styles = styles; + isBuildIn = false; + } - get - { - return XfId + "|" + NumberFormatId.ToString() + "|" + FontId.ToString() + "|" + FillId.ToString() + "|" + BorderId.ToString() + VerticalAlignment.ToString() + "|" + HorizontalAlignment.ToString() + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString() + "|" + isBuildIn.ToString() + TextRotation.ToString() + Locked.ToString() + Hidden.ToString() + ShrinkToFit.ToString() + Indent.ToString(); - //return Numberformat.Id + "|" + Font.Id + "|" + Fill.Id + "|" + Border.Id + VerticalAlignment.ToString() + "|" + HorizontalAlignment.ToString() + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString(); - } - } - internal ExcelXfs Copy() - { - return Copy(_styles); - } - internal ExcelXfs Copy(ExcelStyles styles) - { - ExcelXfs newXF = new ExcelXfs(NameSpaceManager, styles); - newXF.NumberFormatId = _numFmtId; - newXF.FontId = _fontId; - newXF.FillId = _fillId; - newXF.BorderId = _borderId; - newXF.XfId = _xfID; - newXF.ReadingOrder = _readingOrder; - newXF.HorizontalAlignment = _horizontalAlignment; - newXF.VerticalAlignment = _verticalAlignment; - newXF.WrapText = _wrapText; - newXF.ShrinkToFit = _shrinkToFit; - newXF.Indent = _indent; - newXF.TextRotation = _textRotation; - newXF.Locked = _locked; - newXF.Hidden = _hidden; - return newXF; - } - - internal int GetNewID(ExcelStyleCollection<ExcelXfs> xfsCol, StyleBase styleObject, eStyleClass styleClass, eStyleProperty styleProperty, object value) - { - ExcelXfs newXfs = this.Copy(); - switch(styleClass) - { - case eStyleClass.Numberformat: - newXfs.NumberFormatId = GetIdNumberFormat(styleProperty, value); - styleObject.SetIndex(newXfs.NumberFormatId); - break; - case eStyleClass.Font: - { - newXfs.FontId = GetIdFont(styleProperty, value); - styleObject.SetIndex(newXfs.FontId); - break; - } - case eStyleClass.Fill: - case eStyleClass.FillBackgroundColor: - case eStyleClass.FillPatternColor: - newXfs.FillId = GetIdFill(styleClass, styleProperty, value); - styleObject.SetIndex(newXfs.FillId); - break; - case eStyleClass.GradientFill: - case eStyleClass.FillGradientColor1: - case eStyleClass.FillGradientColor2: - newXfs.FillId = GetIdGradientFill(styleClass, styleProperty, value); - styleObject.SetIndex(newXfs.FillId); - break; - case eStyleClass.Border: - case eStyleClass.BorderBottom: - case eStyleClass.BorderDiagonal: - case eStyleClass.BorderLeft: - case eStyleClass.BorderRight: - case eStyleClass.BorderTop: - newXfs.BorderId = GetIdBorder(styleClass, styleProperty, value); - styleObject.SetIndex(newXfs.BorderId); - break; - case eStyleClass.Style: - switch(styleProperty) - { - case eStyleProperty.XfId: - newXfs.XfId = (int)value; - break; - case eStyleProperty.HorizontalAlign: - newXfs.HorizontalAlignment=(ExcelHorizontalAlignment)value; - break; - case eStyleProperty.VerticalAlign: - newXfs.VerticalAlignment = (ExcelVerticalAlignment)value; - break; - case eStyleProperty.WrapText: - newXfs.WrapText = (bool)value; - break; - case eStyleProperty.ReadingOrder: - newXfs.ReadingOrder = (ExcelReadingOrder)value; - break; - case eStyleProperty.ShrinkToFit: - newXfs.ShrinkToFit=(bool)value; - break; - case eStyleProperty.Indent: - newXfs.Indent = (int)value; - break; - case eStyleProperty.TextRotation: - newXfs.TextRotation = (int)value; - break; - case eStyleProperty.Locked: - newXfs.Locked = (bool)value; - break; - case eStyleProperty.Hidden: - newXfs.Hidden = (bool)value; - break; - default: - throw (new Exception("Invalid property for class style.")); - - } - break; - default: - break; - } - int id = xfsCol.FindIndexByID(newXfs.Id); - if (id < 0) - { - return xfsCol.Add(newXfs.Id, newXfs); - } - return id; - } - - private int GetIdBorder(eStyleClass styleClass, eStyleProperty styleProperty, object value) - { - ExcelBorderXml border = Border.Copy(); - - switch (styleClass) - { - case eStyleClass.BorderBottom: - SetBorderItem(border.Bottom, styleProperty, value); - break; - case eStyleClass.BorderDiagonal: - SetBorderItem(border.Diagonal, styleProperty, value); - break; - case eStyleClass.BorderLeft: - SetBorderItem(border.Left, styleProperty, value); - break; - case eStyleClass.BorderRight: - SetBorderItem(border.Right, styleProperty, value); - break; - case eStyleClass.BorderTop: - SetBorderItem(border.Top, styleProperty, value); - break; - case eStyleClass.Border: - if (styleProperty == eStyleProperty.BorderDiagonalUp) - { - border.DiagonalUp = (bool)value; - } - else if (styleProperty == eStyleProperty.BorderDiagonalDown) - { - border.DiagonalDown = (bool)value; - } - else - { - throw (new Exception("Invalid property for class Border.")); - } - break; - default: - throw (new Exception("Invalid class/property for class Border.")); - } - int subId; - string id = border.Id; - subId = _styles.Borders.FindIndexByID(id); - if (subId == int.MinValue) - { - return _styles.Borders.Add(id, border); - } - return subId; - } - - private void SetBorderItem(ExcelBorderItemXml excelBorderItem, eStyleProperty styleProperty, object value) - { - if(styleProperty==eStyleProperty.Style) - { - excelBorderItem.Style = (ExcelBorderStyle)value; - } - else if (styleProperty == eStyleProperty.Color || styleProperty== eStyleProperty.Tint || styleProperty==eStyleProperty.IndexedColor) - { - if (excelBorderItem.Style == ExcelBorderStyle.None) - { - throw(new Exception("Can't set bordercolor when style is not set.")); - } - excelBorderItem.Color.Rgb = value.ToString(); - } - } - - private int GetIdFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) - { - ExcelFillXml fill = Fill.Copy(); - - switch (styleProperty) - { - case eStyleProperty.PatternType: - if (fill is ExcelGradientFillXml) - { - fill = new ExcelFillXml(NameSpaceManager); - } - fill.PatternType = (ExcelFillStyle)value; - break; - case eStyleProperty.Color: - case eStyleProperty.Tint: - case eStyleProperty.IndexedColor: - case eStyleProperty.AutoColor: - if (fill is ExcelGradientFillXml) - { - fill = new ExcelFillXml(NameSpaceManager); - } - if (fill.PatternType == ExcelFillStyle.None) - { - throw (new ArgumentException("Can't set color when patterntype is not set.")); - } - ExcelColorXml destColor; - if (styleClass==eStyleClass.FillPatternColor) - { - destColor = fill.PatternColor; - } - else - { - destColor = fill.BackgroundColor; - } - - if (styleProperty == eStyleProperty.Color) - { - destColor.Rgb = value.ToString(); - } - else if (styleProperty == eStyleProperty.Tint) - { - destColor.Tint = (decimal)value; - } - else if (styleProperty == eStyleProperty.IndexedColor) - { - destColor.Indexed = (int)value; - } - else - { - destColor.Auto = (bool)value; - } - - break; - default: - throw (new ArgumentException("Invalid class/property for class Fill.")); - } - int subId; - string id = fill.Id; - subId = _styles.Fills.FindIndexByID(id); - if (subId == int.MinValue) - { - return _styles.Fills.Add(id, fill); - } - return subId; - } - private int GetIdGradientFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) - { - ExcelGradientFillXml fill; - if(Fill is ExcelGradientFillXml) - { - fill = (ExcelGradientFillXml)Fill.Copy(); - } - else - { - fill = new ExcelGradientFillXml(Fill.NameSpaceManager); - fill.GradientColor1.SetColor(Color.White); - fill.GradientColor2.SetColor(Color.FromArgb(79,129,189)); - fill.Type=ExcelFillGradientType.Linear; - fill.Degree=90; - fill.Top = double.NaN; - fill.Bottom = double.NaN; - fill.Left = double.NaN; - fill.Right = double.NaN; - } - - switch (styleProperty) - { - case eStyleProperty.GradientType: - fill.Type = (ExcelFillGradientType)value; - break; - case eStyleProperty.GradientDegree: - fill.Degree = (double)value; - break; - case eStyleProperty.GradientTop: - fill.Top = (double)value; - break; - case eStyleProperty.GradientBottom: - fill.Bottom = (double)value; - break; - case eStyleProperty.GradientLeft: - fill.Left = (double)value; - break; - case eStyleProperty.GradientRight: - fill.Right = (double)value; - break; - case eStyleProperty.Color: - case eStyleProperty.Tint: - case eStyleProperty.IndexedColor: - case eStyleProperty.AutoColor: - ExcelColorXml destColor; - - if (styleClass == eStyleClass.FillGradientColor1) - { - destColor = fill.GradientColor1; - } - else - { - destColor = fill.GradientColor2; - } - - if (styleProperty == eStyleProperty.Color) - { - destColor.Rgb = value.ToString(); - } - else if (styleProperty == eStyleProperty.Tint) - { - destColor.Tint = (decimal)value; - } - else if (styleProperty == eStyleProperty.IndexedColor) - { - destColor.Indexed = (int)value; - } - else - { - destColor.Auto = (bool)value; - } - break; - default: - throw (new ArgumentException("Invalid class/property for class Fill.")); - } - int subId; - string id = fill.Id; - subId = _styles.Fills.FindIndexByID(id); - if (subId == int.MinValue) - { - return _styles.Fills.Add(id, fill); - } - return subId; - } - - private int GetIdNumberFormat(eStyleProperty styleProperty, object value) - { - if (styleProperty == eStyleProperty.Format) - { - ExcelNumberFormatXml item=null; - if (!_styles.NumberFormats.FindByID(value.ToString(), ref item)) - { - item = new ExcelNumberFormatXml(NameSpaceManager) { Format = value.ToString(), NumFmtId = _styles.NumberFormats.NextId++ }; - _styles.NumberFormats.Add(value.ToString(), item); - } - return item.NumFmtId; - } - else - { - throw (new Exception("Invalid property for class Numberformat")); - } - } - private int GetIdFont(eStyleProperty styleProperty, object value) - { - ExcelFontXml fnt = Font.Copy(); - - switch (styleProperty) - { - case eStyleProperty.Name: - fnt.Name = value.ToString(); - break; - case eStyleProperty.Size: - fnt.Size = (float)value; - break; - case eStyleProperty.Family: - fnt.Family = (int)value; - break; - case eStyleProperty.Bold: - fnt.Bold = (bool)value; - break; - case eStyleProperty.Italic: - fnt.Italic = (bool)value; - break; - case eStyleProperty.Strike: - fnt.Strike = (bool)value; - break; - case eStyleProperty.UnderlineType: - fnt.UnderLineType = (ExcelUnderLineType)value; - break; - case eStyleProperty.Color: - fnt.Color.Rgb=value.ToString(); - break; - case eStyleProperty.VerticalAlign: - fnt.VerticalAlign = ((ExcelVerticalAlignmentFont)value) == ExcelVerticalAlignmentFont.None ? "" : value.ToString().ToLower(CultureInfo.InvariantCulture); - break; - default: - throw (new Exception("Invalid property for class Font")); - } - int subId; - string id = fnt.Id; - subId = _styles.Fonts.FindIndexByID(id); - if (subId == int.MinValue) - { - return _styles.Fonts.Add(id,fnt); - } - return subId; - } - internal override XmlNode CreateXmlNode(XmlNode topNode) - { - return CreateXmlNode(topNode, false); - } - internal XmlNode CreateXmlNode(XmlNode topNode, bool isCellStyleXsf) - { - TopNode = topNode; - var doSetXfId = (!isCellStyleXsf && _xfID > int.MinValue && _styles.CellStyleXfs.Count > 0 && _styles.CellStyleXfs[_xfID].newID > int.MinValue); - if (_numFmtId > 0) - { - SetXmlNodeString("@numFmtId", _numFmtId.ToString()); - if(doSetXfId) SetXmlNodeString("@applyNumberFormat", "1"); - } - if (_fontId >= 0) - { - SetXmlNodeString("@fontId", _styles.Fonts[_fontId].newID.ToString()); - if (doSetXfId) SetXmlNodeString("@applyFont", "1"); - } - if (_fillId >= 0) - { - SetXmlNodeString("@fillId", _styles.Fills[_fillId].newID.ToString()); - if (doSetXfId) SetXmlNodeString("@applyFill", "1"); - } - if (_borderId >= 0) - { - SetXmlNodeString("@borderId", _styles.Borders[_borderId].newID.ToString()); - if (doSetXfId) SetXmlNodeString("@applyBorder", "1"); - } - if(_horizontalAlignment != ExcelHorizontalAlignment.General) this.SetXmlNodeString(horizontalAlignPath, SetAlignString(_horizontalAlignment)); - if (doSetXfId) - { - SetXmlNodeString("@xfId", _styles.CellStyleXfs[_xfID].newID.ToString()); - } - if (_verticalAlignment != ExcelVerticalAlignment.Bottom) this.SetXmlNodeString(verticalAlignPath, SetAlignString(_verticalAlignment)); - if(_wrapText) this.SetXmlNodeString(wrapTextPath, "1"); - if(_readingOrder!=ExcelReadingOrder.ContextDependent) this.SetXmlNodeString(readingOrderPath, ((int)_readingOrder).ToString()); - if (_shrinkToFit) this.SetXmlNodeString(shrinkToFitPath, "1"); - if (_indent > 0) SetXmlNodeString(indentPath, _indent.ToString()); - if (_textRotation > 0) this.SetXmlNodeString(textRotationPath, _textRotation.ToString()); - if (!_locked) this.SetXmlNodeString(lockedPath, "0"); - if (_hidden) this.SetXmlNodeString(hiddenPath, "1"); - return TopNode; - } - - private string SetAlignString(Enum align) - { - string newName = Enum.GetName(align.GetType(), align); - return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + newName.Substring(1, newName.Length - 1); - } + internal ExcelXfs(XmlNamespaceManager nsm, XmlNode topNode, ExcelStyles styles) + : base(nsm, topNode) { + _styles = styles; + _xfID = GetXmlNodeInt("@xfId"); + if (_xfID == 0) { + isBuildIn = true; //Normal taggen } -} \ No newline at end of file + _numFmtId = GetXmlNodeInt("@numFmtId"); + _fontId = GetXmlNodeInt("@fontId"); + _fillId = GetXmlNodeInt("@fillId"); + _borderId = GetXmlNodeInt("@borderId"); + _readingOrder = GetReadingOrder(GetXmlNodeString(_readingOrderPath)); + _indent = GetXmlNodeInt(_indentPath); + _shrinkToFit = GetXmlNodeString(_shrinkToFitPath) == "1" ? true : false; + _verticalAlignment = GetVerticalAlign(GetXmlNodeString(_verticalAlignPath)); + _horizontalAlignment = GetHorizontalAlign(GetXmlNodeString(_horizontalAlignPath)); + _wrapText = GetXmlNodeBool(_wrapTextPath); + _textRotation = GetXmlNodeInt(textRotationPath); + _hidden = GetXmlNodeBool(_hiddenPath); + _locked = GetXmlNodeBool(_lockedPath, true); + } + + private ExcelReadingOrder GetReadingOrder(string value) { + switch (value) { + case "1": + return ExcelReadingOrder.LeftToRight; + case "2": + return ExcelReadingOrder.RightToLeft; + default: + return ExcelReadingOrder.ContextDependent; + } + } + + private ExcelHorizontalAlignment GetHorizontalAlign(string align) { + if (align == "") { + return ExcelHorizontalAlignment.General; + } + align = + align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + + align.Substring(1, align.Length - 1); + try { + return (ExcelHorizontalAlignment)Enum.Parse(typeof(ExcelHorizontalAlignment), align); + } catch { + return ExcelHorizontalAlignment.General; + } + } + + private ExcelVerticalAlignment GetVerticalAlign(string align) { + if (align == "") { + return ExcelVerticalAlignment.Bottom; + } + align = + align.Substring(0, 1).ToUpper(CultureInfo.InvariantCulture) + + align.Substring(1, align.Length - 1); + try { + return (ExcelVerticalAlignment)Enum.Parse(typeof(ExcelVerticalAlignment), align); + } catch { + return ExcelVerticalAlignment.Bottom; + } + } + + internal void Xf_ChangedEvent(object sender, EventArgs e) { + //if (_cell != null) + //{ + // if (!Styles.ChangedCells.ContainsKey(_cell.Id)) + // { + // //_cell.Style = ""; + // _cell.SetNewStyleID(int.MinValue.ToString()); + // Styles.ChangedCells.Add(_cell.Id, _cell); + // } + //} + } + + private int _xfID; + + /// <summary> + /// Style index + /// </summary> + public int XfId { + get => _xfID; + set => _xfID = value; + } + + private int _numFmtId; + + internal int NumberFormatId { + get => _numFmtId; + set { + _numFmtId = value; + ApplyNumberFormat = (value > 0); + } + } + + private int _fontId; + + internal int FontId { + get => _fontId; + set => _fontId = value; + } + + private int _fillId; + + internal int FillId { + get => _fillId; + set => _fillId = value; + } + + private int _borderId; + + internal int BorderId { + get => _borderId; + set => _borderId = value; + } + + private bool isBuildIn { get; set; } + + internal bool ApplyNumberFormat { get; set; } + + internal bool ApplyFont { get; set; } + + internal bool ApplyFill { get; set; } + + internal bool ApplyBorder { get; set; } + + internal bool ApplyAlignment { get; set; } + + internal bool ApplyProtection { get; set; } + + public ExcelStyles Styles { get; private set; } + + /// <summary> + /// Numberformat properties + /// </summary> + public ExcelNumberFormatXml Numberformat => _styles.NumberFormats[_numFmtId < 0 ? 0 : _numFmtId]; + + /// <summary> + /// Font properties + /// </summary> + public ExcelFontXml Font => _styles.Fonts[_fontId < 0 ? 0 : _fontId]; + + /// <summary> + /// Fill properties + /// </summary> + public ExcelFillXml Fill => _styles.Fills[_fillId < 0 ? 0 : _fillId]; + + /// <summary> + /// Border style properties + /// </summary> + public ExcelBorderXml Border => _styles.Borders[_borderId < 0 ? 0 : _borderId]; + + private const string _horizontalAlignPath = "d:alignment/@horizontal"; + private ExcelHorizontalAlignment _horizontalAlignment = ExcelHorizontalAlignment.General; + + /// <summary> + /// Horizontal alignment + /// </summary> + public ExcelHorizontalAlignment HorizontalAlignment { + get => _horizontalAlignment; + set => _horizontalAlignment = value; + } + + private const string _verticalAlignPath = "d:alignment/@vertical"; + private ExcelVerticalAlignment _verticalAlignment = ExcelVerticalAlignment.Bottom; + + /// <summary> + /// Vertical alignment + /// </summary> + public ExcelVerticalAlignment VerticalAlignment { + get => _verticalAlignment; + set => _verticalAlignment = value; + } + + private const string _wrapTextPath = "d:alignment/@wrapText"; + private bool _wrapText; + + /// <summary> + /// Wraped text + /// </summary> + public bool WrapText { + get => _wrapText; + set => _wrapText = value; + } + + private string textRotationPath = "d:alignment/@textRotation"; + private int _textRotation; + + /// <summary> + /// Text rotation angle + /// </summary> + public int TextRotation { + get => (_textRotation == int.MinValue ? 0 : _textRotation); + set => _textRotation = value; + } + + private const string _lockedPath = "d:protection/@locked"; + private bool _locked = true; + + /// <summary> + /// Locked when sheet is protected + /// </summary> + public bool Locked { + get => _locked; + set => _locked = value; + } + + private const string _hiddenPath = "d:protection/@hidden"; + private bool _hidden; + + /// <summary> + /// Hide formulas when sheet is protected + /// </summary> + public bool Hidden { + get => _hidden; + set => _hidden = value; + } + + private const string _readingOrderPath = "d:alignment/@readingOrder"; + private ExcelReadingOrder _readingOrder = ExcelReadingOrder.ContextDependent; + + /// <summary> + /// Readingorder + /// </summary> + public ExcelReadingOrder ReadingOrder { + get => _readingOrder; + set => _readingOrder = value; + } + + private const string _shrinkToFitPath = "d:alignment/@shrinkToFit"; + private bool _shrinkToFit; + + /// <summary> + /// Shrink to fit + /// </summary> + public bool ShrinkToFit { + get => _shrinkToFit; + set => _shrinkToFit = value; + } + + private const string _indentPath = "d:alignment/@indent"; + private int _indent; + + /// <summary> + /// Indentation + /// </summary> + public int Indent { + get => (_indent == int.MinValue ? 0 : _indent); + set => _indent = value; + } + + internal void RegisterEvent(ExcelXfs xf) { + // RegisterEvent(xf, xf.Xf_ChangedEvent); + } + + internal override string Id => + XfId + + "|" + + NumberFormatId + + "|" + + FontId + + "|" + + FillId + + "|" + + BorderId + + VerticalAlignment + + "|" + + HorizontalAlignment + + "|" + + WrapText + + "|" + + ReadingOrder + + "|" + + isBuildIn + + TextRotation + + Locked + + Hidden + + ShrinkToFit + + Indent; + + //return Numberformat.Id + "|" + Font.Id + "|" + Fill.Id + "|" + Border.Id + VerticalAlignment.ToString() + "|" + HorizontalAlignment.ToString() + "|" + WrapText.ToString() + "|" + ReadingOrder.ToString(); + internal ExcelXfs Copy() { + return Copy(_styles); + } + + internal ExcelXfs Copy(ExcelStyles styles) { + ExcelXfs newXf = new ExcelXfs(NameSpaceManager, styles); + newXf.NumberFormatId = _numFmtId; + newXf.FontId = _fontId; + newXf.FillId = _fillId; + newXf.BorderId = _borderId; + newXf.XfId = _xfID; + newXf.ReadingOrder = _readingOrder; + newXf.HorizontalAlignment = _horizontalAlignment; + newXf.VerticalAlignment = _verticalAlignment; + newXf.WrapText = _wrapText; + newXf.ShrinkToFit = _shrinkToFit; + newXf.Indent = _indent; + newXf.TextRotation = _textRotation; + newXf.Locked = _locked; + newXf.Hidden = _hidden; + return newXf; + } + + internal int GetNewId( + ExcelStyleCollection<ExcelXfs> xfsCol, + StyleBase styleObject, + eStyleClass styleClass, + eStyleProperty styleProperty, + object value) { + ExcelXfs newXfs = Copy(); + switch (styleClass) { + case eStyleClass.Numberformat: + newXfs.NumberFormatId = GetIdNumberFormat(styleProperty, value); + styleObject.SetIndex(newXfs.NumberFormatId); + break; + case eStyleClass.Font: { + newXfs.FontId = GetIdFont(styleProperty, value); + styleObject.SetIndex(newXfs.FontId); + break; + } + case eStyleClass.Fill: + case eStyleClass.FillBackgroundColor: + case eStyleClass.FillPatternColor: + newXfs.FillId = GetIdFill(styleClass, styleProperty, value); + styleObject.SetIndex(newXfs.FillId); + break; + case eStyleClass.GradientFill: + case eStyleClass.FillGradientColor1: + case eStyleClass.FillGradientColor2: + newXfs.FillId = GetIdGradientFill(styleClass, styleProperty, value); + styleObject.SetIndex(newXfs.FillId); + break; + case eStyleClass.Border: + case eStyleClass.BorderBottom: + case eStyleClass.BorderDiagonal: + case eStyleClass.BorderLeft: + case eStyleClass.BorderRight: + case eStyleClass.BorderTop: + newXfs.BorderId = GetIdBorder(styleClass, styleProperty, value); + styleObject.SetIndex(newXfs.BorderId); + break; + case eStyleClass.Style: + switch (styleProperty) { + case eStyleProperty.XfId: + newXfs.XfId = (int)value; + break; + case eStyleProperty.HorizontalAlign: + newXfs.HorizontalAlignment = (ExcelHorizontalAlignment)value; + break; + case eStyleProperty.VerticalAlign: + newXfs.VerticalAlignment = (ExcelVerticalAlignment)value; + break; + case eStyleProperty.WrapText: + newXfs.WrapText = (bool)value; + break; + case eStyleProperty.ReadingOrder: + newXfs.ReadingOrder = (ExcelReadingOrder)value; + break; + case eStyleProperty.ShrinkToFit: + newXfs.ShrinkToFit = (bool)value; + break; + case eStyleProperty.Indent: + newXfs.Indent = (int)value; + break; + case eStyleProperty.TextRotation: + newXfs.TextRotation = (int)value; + break; + case eStyleProperty.Locked: + newXfs.Locked = (bool)value; + break; + case eStyleProperty.Hidden: + newXfs.Hidden = (bool)value; + break; + default: + throw (new("Invalid property for class style.")); + } + break; + } + int id = xfsCol.FindIndexById(newXfs.Id); + if (id < 0) { + return xfsCol.Add(newXfs.Id, newXfs); + } + return id; + } + + private int GetIdBorder(eStyleClass styleClass, eStyleProperty styleProperty, object value) { + ExcelBorderXml border = Border.Copy(); + + switch (styleClass) { + case eStyleClass.BorderBottom: + SetBorderItem(border.Bottom, styleProperty, value); + break; + case eStyleClass.BorderDiagonal: + SetBorderItem(border.Diagonal, styleProperty, value); + break; + case eStyleClass.BorderLeft: + SetBorderItem(border.Left, styleProperty, value); + break; + case eStyleClass.BorderRight: + SetBorderItem(border.Right, styleProperty, value); + break; + case eStyleClass.BorderTop: + SetBorderItem(border.Top, styleProperty, value); + break; + case eStyleClass.Border: + if (styleProperty == eStyleProperty.BorderDiagonalUp) { + border.DiagonalUp = (bool)value; + } else if (styleProperty == eStyleProperty.BorderDiagonalDown) { + border.DiagonalDown = (bool)value; + } else { + throw (new("Invalid property for class Border.")); + } + break; + default: + throw (new("Invalid class/property for class Border.")); + } + int subId; + string id = border.Id; + subId = _styles.Borders.FindIndexById(id); + if (subId == int.MinValue) { + return _styles.Borders.Add(id, border); + } + return subId; + } + + private void SetBorderItem( + ExcelBorderItemXml excelBorderItem, + eStyleProperty styleProperty, + object value) { + if (styleProperty == eStyleProperty.Style) { + excelBorderItem.Style = (ExcelBorderStyle)value; + } else if (styleProperty == eStyleProperty.Color + || styleProperty == eStyleProperty.Tint + || styleProperty == eStyleProperty.IndexedColor) { + if (excelBorderItem.Style == ExcelBorderStyle.None) { + throw (new("Can't set bordercolor when style is not set.")); + } + excelBorderItem.Color.Rgb = value.ToString(); + } + } + + private int GetIdFill(eStyleClass styleClass, eStyleProperty styleProperty, object value) { + ExcelFillXml fill = Fill.Copy(); + + switch (styleProperty) { + case eStyleProperty.PatternType: + if (fill is ExcelGradientFillXml) { + fill = new(NameSpaceManager); + } + fill.PatternType = (ExcelFillStyle)value; + break; + case eStyleProperty.Color: + case eStyleProperty.Tint: + case eStyleProperty.IndexedColor: + case eStyleProperty.AutoColor: + if (fill is ExcelGradientFillXml) { + fill = new(NameSpaceManager); + } + if (fill.PatternType == ExcelFillStyle.None) { + throw (new ArgumentException("Can't set color when patterntype is not set.")); + } + ExcelColorXml destColor; + if (styleClass == eStyleClass.FillPatternColor) { + destColor = fill.PatternColor; + } else { + destColor = fill.BackgroundColor; + } + + if (styleProperty == eStyleProperty.Color) { + destColor.Rgb = value.ToString(); + } else if (styleProperty == eStyleProperty.Tint) { + destColor.Tint = (decimal)value; + } else if (styleProperty == eStyleProperty.IndexedColor) { + destColor.Indexed = (int)value; + } else { + destColor.Auto = (bool)value; + } + + break; + default: + throw (new ArgumentException("Invalid class/property for class Fill.")); + } + int subId; + string id = fill.Id; + subId = _styles.Fills.FindIndexById(id); + if (subId == int.MinValue) { + return _styles.Fills.Add(id, fill); + } + return subId; + } + + private int GetIdGradientFill( + eStyleClass styleClass, + eStyleProperty styleProperty, + object value) { + ExcelGradientFillXml fill; + if (Fill is ExcelGradientFillXml) { + fill = (ExcelGradientFillXml)Fill.Copy(); + } else { + fill = new(Fill.NameSpaceManager); + fill.GradientColor1.SetColor(Color.White); + fill.GradientColor2.SetColor(Color.FromArgb(79, 129, 189)); + fill.Type = ExcelFillGradientType.Linear; + fill.Degree = 90; + fill.Top = double.NaN; + fill.Bottom = double.NaN; + fill.Left = double.NaN; + fill.Right = double.NaN; + } + + switch (styleProperty) { + case eStyleProperty.GradientType: + fill.Type = (ExcelFillGradientType)value; + break; + case eStyleProperty.GradientDegree: + fill.Degree = (double)value; + break; + case eStyleProperty.GradientTop: + fill.Top = (double)value; + break; + case eStyleProperty.GradientBottom: + fill.Bottom = (double)value; + break; + case eStyleProperty.GradientLeft: + fill.Left = (double)value; + break; + case eStyleProperty.GradientRight: + fill.Right = (double)value; + break; + case eStyleProperty.Color: + case eStyleProperty.Tint: + case eStyleProperty.IndexedColor: + case eStyleProperty.AutoColor: + ExcelColorXml destColor; + + if (styleClass == eStyleClass.FillGradientColor1) { + destColor = fill.GradientColor1; + } else { + destColor = fill.GradientColor2; + } + + if (styleProperty == eStyleProperty.Color) { + destColor.Rgb = value.ToString(); + } else if (styleProperty == eStyleProperty.Tint) { + destColor.Tint = (decimal)value; + } else if (styleProperty == eStyleProperty.IndexedColor) { + destColor.Indexed = (int)value; + } else { + destColor.Auto = (bool)value; + } + break; + default: + throw (new ArgumentException("Invalid class/property for class Fill.")); + } + int subId; + string id = fill.Id; + subId = _styles.Fills.FindIndexById(id); + if (subId == int.MinValue) { + return _styles.Fills.Add(id, fill); + } + return subId; + } + + private int GetIdNumberFormat(eStyleProperty styleProperty, object value) { + if (styleProperty == eStyleProperty.Format) { + ExcelNumberFormatXml item = null; + if (!_styles.NumberFormats.FindById(value.ToString(), ref item)) { + item = new(NameSpaceManager) { + Format = value.ToString(), + NumFmtId = _styles.NumberFormats.NextId++, + }; + _styles.NumberFormats.Add(value.ToString(), item); + } + return item.NumFmtId; + } + throw (new("Invalid property for class Numberformat")); + } + + private int GetIdFont(eStyleProperty styleProperty, object value) { + ExcelFontXml fnt = Font.Copy(); + + switch (styleProperty) { + case eStyleProperty.Name: + fnt.Name = value.ToString(); + break; + case eStyleProperty.Size: + fnt.Size = (float)value; + break; + case eStyleProperty.Family: + fnt.Family = (int)value; + break; + case eStyleProperty.Bold: + fnt.Bold = (bool)value; + break; + case eStyleProperty.Italic: + fnt.Italic = (bool)value; + break; + case eStyleProperty.Strike: + fnt.Strike = (bool)value; + break; + case eStyleProperty.UnderlineType: + fnt.UnderLineType = (ExcelUnderLineType)value; + break; + case eStyleProperty.Color: + fnt.Color.Rgb = value.ToString(); + break; + case eStyleProperty.VerticalAlign: + fnt.VerticalAlign = + ((ExcelVerticalAlignmentFont)value) == ExcelVerticalAlignmentFont.None + ? "" + : value.ToString().ToLower(CultureInfo.InvariantCulture); + break; + default: + throw (new("Invalid property for class Font")); + } + int subId; + string id = fnt.Id; + subId = _styles.Fonts.FindIndexById(id); + if (subId == int.MinValue) { + return _styles.Fonts.Add(id, fnt); + } + return subId; + } + + internal override XmlNode CreateXmlNode(XmlNode topNode) { + return CreateXmlNode(topNode, false); + } + + internal XmlNode CreateXmlNode(XmlNode topNode, bool isCellStyleXsf) { + TopNode = topNode; + var doSetXfId = + (!isCellStyleXsf + && _xfID > int.MinValue + && _styles.CellStyleXfs.Count > 0 + && _styles.CellStyleXfs[_xfID].newID > int.MinValue); + if (_numFmtId > 0) { + SetXmlNodeString("@numFmtId", _numFmtId.ToString()); + if (doSetXfId) { + SetXmlNodeString("@applyNumberFormat", "1"); + } + } + if (_fontId >= 0) { + SetXmlNodeString("@fontId", _styles.Fonts[_fontId].newID.ToString()); + if (doSetXfId) { + SetXmlNodeString("@applyFont", "1"); + } + } + if (_fillId >= 0) { + SetXmlNodeString("@fillId", _styles.Fills[_fillId].newID.ToString()); + if (doSetXfId) { + SetXmlNodeString("@applyFill", "1"); + } + } + if (_borderId >= 0) { + SetXmlNodeString("@borderId", _styles.Borders[_borderId].newID.ToString()); + if (doSetXfId) { + SetXmlNodeString("@applyBorder", "1"); + } + } + if (_horizontalAlignment != ExcelHorizontalAlignment.General) { + SetXmlNodeString(_horizontalAlignPath, SetAlignString(_horizontalAlignment)); + } + if (doSetXfId) { + SetXmlNodeString("@xfId", _styles.CellStyleXfs[_xfID].newID.ToString()); + } + if (_verticalAlignment != ExcelVerticalAlignment.Bottom) { + SetXmlNodeString(_verticalAlignPath, SetAlignString(_verticalAlignment)); + } + if (_wrapText) { + SetXmlNodeString(_wrapTextPath, "1"); + } + if (_readingOrder != ExcelReadingOrder.ContextDependent) { + SetXmlNodeString(_readingOrderPath, ((int)_readingOrder).ToString()); + } + if (_shrinkToFit) { + SetXmlNodeString(_shrinkToFitPath, "1"); + } + if (_indent > 0) { + SetXmlNodeString(_indentPath, _indent.ToString()); + } + if (_textRotation > 0) { + SetXmlNodeString(textRotationPath, _textRotation.ToString()); + } + if (!_locked) { + SetXmlNodeString(_lockedPath, "0"); + } + if (_hidden) { + SetXmlNodeString(_hiddenPath, "1"); + } + return TopNode; + } + + private string SetAlignString(Enum align) { + string newName = Enum.GetName(align.GetType(), align); + return newName.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + + newName.Substring(1, newName.Length - 1); + } +}
diff --git a/EPPlus/Style/XmlAccess/StyleXmlHelper.cs b/EPPlus/Style/XmlAccess/StyleXmlHelper.cs index 97eaefc..f735ef3 100644 --- a/EPPlus/Style/XmlAccess/StyleXmlHelper.cs +++ b/EPPlus/Style/XmlAccess/StyleXmlHelper.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,66 +13,54 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; + using System.Xml; -namespace OfficeOpenXml.Style.XmlAccess -{ - /// <summary> - /// Xml helper class for cell style classes - /// </summary> - public abstract class StyleXmlHelper : XmlHelper - { - internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager) : base(nameSpaceManager) - { - } - internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode) : base(nameSpaceManager, topNode) - { - } - internal abstract XmlNode CreateXmlNode(XmlNode top); - internal abstract string Id - { - get; - } - internal long useCnt=0; - internal int newID=int.MinValue; - protected bool GetBoolValue(XmlNode topNode, string path) - { - var node = topNode.SelectSingleNode(path, NameSpaceManager); - if (node is XmlAttribute) - { - return node.Value != "0"; - } - else - { - if (node != null && ((node.Attributes["val"] != null && node.Attributes["val"].Value != "0") || node.Attributes["val"] == null)) - { - return true; - } - else - { - return false; - } - } - } +namespace OfficeOpenXml.Style.XmlAccess; +/// <summary> +/// Xml helper class for cell style classes +/// </summary> +public abstract class StyleXmlHelper : XmlHelper { + internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager) + : base(nameSpaceManager) {} + + internal StyleXmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode) + : base(nameSpaceManager, topNode) {} + + internal abstract XmlNode CreateXmlNode(XmlNode top); + + internal abstract string Id { get; } + + internal long useCnt = 0; + internal int newID = int.MinValue; + + protected bool GetBoolValue(XmlNode topNode, string path) { + var node = topNode.SelectSingleNode(path, NameSpaceManager); + if (node is XmlAttribute) { + return node.Value != "0"; } + if (node != null + && ((node.Attributes["val"] != null && node.Attributes["val"].Value != "0") + || node.Attributes["val"] == null)) { + return true; + } + return false; + } }
diff --git a/EPPlus/Table/ExcelTable.cs b/EPPlus/Table/ExcelTable.cs index 1d58a01..0b9144a 100644 --- a/EPPlus/Table/ExcelTable.cs +++ b/EPPlus/Table/ExcelTable.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,627 +13,524 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 30-AUG-2010 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; using System.Collections.Generic; +using System.Security; using System.Text; -using System.Xml; using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.Excel.Functions.Math; +using System.Xml; +using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.Table -{ - /// <summary> - /// Table style Enum - /// </summary> - public enum TableStyles - { - None, - Custom, - Light1, - Light2, - Light3, - Light4, - Light5, - Light6, - Light7, - Light8, - Light9, - Light10, - Light11, - Light12, - Light13, - Light14, - Light15, - Light16, - Light17, - Light18, - Light19, - Light20, - Light21, - Medium1, - Medium2, - Medium3, - Medium4, - Medium5, - Medium6, - Medium7, - Medium8, - Medium9, - Medium10, - Medium11, - Medium12, - Medium13, - Medium14, - Medium15, - Medium16, - Medium17, - Medium18, - Medium19, - Medium20, - Medium21, - Medium22, - Medium23, - Medium24, - Medium25, - Medium26, - Medium27, - Medium28, - Dark1, - Dark2, - Dark3, - Dark4, - Dark5, - Dark6, - Dark7, - Dark8, - Dark9, - Dark10, - Dark11, +namespace OfficeOpenXml.Table; + +/// <summary> +/// Table style Enum +/// </summary> +public enum TableStyles { + None, + Custom, + Light1, + Light2, + Light3, + Light4, + Light5, + Light6, + Light7, + Light8, + Light9, + Light10, + Light11, + Light12, + Light13, + Light14, + Light15, + Light16, + Light17, + Light18, + Light19, + Light20, + Light21, + Medium1, + Medium2, + Medium3, + Medium4, + Medium5, + Medium6, + Medium7, + Medium8, + Medium9, + Medium10, + Medium11, + Medium12, + Medium13, + Medium14, + Medium15, + Medium16, + Medium17, + Medium18, + Medium19, + Medium20, + Medium21, + Medium22, + Medium23, + Medium24, + Medium25, + Medium26, + Medium27, + Medium28, + Dark1, + Dark2, + Dark3, + Dark4, + Dark5, + Dark6, + Dark7, + Dark8, + Dark9, + Dark10, + Dark11, +} + +/// <summary> +/// An Excel Table +/// </summary> +public class ExcelTable : XmlHelper, IEqualityComparer<ExcelTable> { + internal ExcelTable(ZipPackageRelationship rel, ExcelWorksheet sheet) + : base(sheet.NameSpaceManager) { + WorkSheet = sheet; + TableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); + RelationshipID = rel.Id; + var pck = sheet._package.Package; + Part = pck.GetPart(TableUri); + + TableXml = new(); + LoadXmlSafe(TableXml, Part.GetStream()); + Init(); + Address = new(GetXmlNodeString("@ref")); + } + + internal ExcelTable(ExcelWorksheet sheet, ExcelAddressBase address, string name, int tblId) + : base(sheet.NameSpaceManager) { + WorkSheet = sheet; + Address = address; + TableXml = new(); + LoadXmlSafe(TableXml, GetStartXml(name, tblId), Encoding.UTF8); + TopNode = TableXml.DocumentElement; + + Init(); + + //If the table is just one row we can not have a header. + if (address._fromRow == address._toRow) { + ShowHeader = false; } - /// <summary> - /// An Excel Table - /// </summary> - public class ExcelTable : XmlHelper, IEqualityComparer<ExcelTable> - { - internal ExcelTable(Packaging.ZipPackageRelationship rel, ExcelWorksheet sheet) : - base(sheet.NameSpaceManager) - { - WorkSheet = sheet; - TableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); - RelationshipID = rel.Id; - var pck = sheet._package.Package; - Part=pck.GetPart(TableUri); + } - TableXml = new XmlDocument(); - LoadXmlSafe(TableXml, Part.GetStream()); - init(); - Address = new ExcelAddressBase(GetXmlNodeString("@ref")); - } - internal ExcelTable(ExcelWorksheet sheet, ExcelAddressBase address, string name, int tblId) : - base(sheet.NameSpaceManager) - { - WorkSheet = sheet; - Address = address; - TableXml = new XmlDocument(); - LoadXmlSafe(TableXml, GetStartXml(name, tblId), Encoding.UTF8); - TopNode = TableXml.DocumentElement; + private void Init() { + TopNode = TableXml.DocumentElement; + SchemaNodeOrder = new[] { "autoFilter", "tableColumns", "tableStyleInfo" }; + } - init(); + private string GetStartXml(string name, int tblId) { + string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>"; + xml += string.Format( + "<table xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" id=\"{0}\" name=\"{1}\" displayName=\"{2}\" ref=\"{3}\" headerRowCount=\"1\">", + tblId, + name, + CleanDisplayName(name), + Address.Address); + xml += string.Format("<autoFilter ref=\"{0}\" />", Address.Address); - //If the table is just one row we can not have a header. - if (address._fromRow == address._toRow) - { - ShowHeader = false; - } - } - - private void init() - { - TopNode = TableXml.DocumentElement; - SchemaNodeOrder = new string[] { "autoFilter", "tableColumns", "tableStyleInfo" }; - } - private string GetStartXml(string name, int tblId) - { - string xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>"; - xml += string.Format("<table xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" id=\"{0}\" name=\"{1}\" displayName=\"{2}\" ref=\"{3}\" headerRowCount=\"1\">", - tblId, - name, - cleanDisplayName(name), - Address.Address); - xml += string.Format("<autoFilter ref=\"{0}\" />", Address.Address); - - int cols=Address._toCol-Address._fromCol+1; - xml += string.Format("<tableColumns count=\"{0}\">",cols); - var names = new Dictionary<string, string>(); - for(int i=1;i<=cols;i++) - { - var cell = WorkSheet.Cells[Address._fromRow, Address._fromCol+i-1]; - string colName; - if (cell.Value == null || names.ContainsKey(cell.Value.ToString())) - { - //Get an unique name - int a=i; - do - { - colName = string.Format("Column{0}", a++); - } - while (names.ContainsKey(colName)); - } - else - { - colName = System.Security.SecurityElement.Escape(cell.Value.ToString()); - } - names.Add(colName, colName); - xml += string.Format("<tableColumn id=\"{0}\" name=\"{1}\" />", i,colName); - } - xml += "</tableColumns>"; - xml += "<tableStyleInfo name=\"TableStyleMedium9\" showFirstColumn=\"0\" showLastColumn=\"0\" showRowStripes=\"1\" showColumnStripes=\"0\" /> "; - xml += "</table>"; - - return xml; - } - private string cleanDisplayName(string name) - { - return Regex.Replace(name, @"[^\w\.-_]", "_"); - } - internal Packaging.ZipPackagePart Part - { - get; - set; - } - /// <summary> - /// Provides access to the XML data representing the table in the package. - /// </summary> - public XmlDocument TableXml - { - get; - set; - } - /// <summary> - /// The package internal URI to the Table Xml Document. - /// </summary> - public Uri TableUri - { - get; - internal set; - } - internal string RelationshipID - { - get; - set; - } - const string ID_PATH = "@id"; - internal int Id - { - get - { - return GetXmlNodeInt(ID_PATH); - } - set - { - SetXmlNodeString(ID_PATH, value.ToString()); - } - } - const string NAME_PATH = "@name"; - const string DISPLAY_NAME_PATH = "@displayName"; - /// <summary> - /// The name of the table object in Excel - /// </summary> - public string Name - { - get - { - return GetXmlNodeString(NAME_PATH); - } - set - { - if(WorkSheet.Workbook.ExistsTableName(value)) - { - throw (new ArgumentException("Tablename is not unique")); - } - string prevName = Name; - if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) - { - int ix=WorkSheet.Tables._tableNames[prevName]; - WorkSheet.Tables._tableNames.Remove(prevName); - WorkSheet.Tables._tableNames.Add(value,ix); - } - SetXmlNodeString(NAME_PATH, value); - SetXmlNodeString(DISPLAY_NAME_PATH, cleanDisplayName(value)); - } - } - /// <summary> - /// The worksheet of the table - /// </summary> - public ExcelWorksheet WorkSheet - { - get; - set; - } - - private ExcelAddressBase _address = null; - /// <summary> - /// The address of the table - /// </summary> - public ExcelAddressBase Address - { - get - { - return _address; - } - set - { - _address = value; - SetXmlNodeString("@ref",value.Address); - WriteAutoFilter(ShowTotal); - } - } - internal ExcelTableColumnCollection _cols = null; - /// <summary> - /// Collection of the columns in the table - /// </summary> - public ExcelTableColumnCollection Columns - { - get - { - if(_cols==null) - { - _cols = new ExcelTableColumnCollection(this); - } - return _cols; - } - } - TableStyles _tableStyle = TableStyles.Medium6; - /// <summary> - /// The table style. If this property is cusom, the style from the StyleName propery is used. - /// </summary> - public TableStyles TableStyle - { - get - { - return _tableStyle; - } - set - { - _tableStyle=value; - if (value != TableStyles.Custom) - { - SetXmlNodeString(STYLENAME_PATH, "TableStyle" + value.ToString()); - } - } - } - const string HEADERROWCOUNT_PATH = "@headerRowCount"; - const string AUTOFILTER_PATH = "d:autoFilter/@ref"; - /// <summary> - /// If the header row is visible or not - /// </summary> - public bool ShowHeader - { - get - { - return GetXmlNodeInt(HEADERROWCOUNT_PATH)!=0; - } - set - { - if (Address._toRow - Address._fromRow < 0 && value || - Address._toRow - Address._fromRow == 1 && value && ShowTotal) - { - throw (new Exception("Cant set ShowHeader-property. Table has too few rows")); - } - - if(value) - { - DeleteNode(HEADERROWCOUNT_PATH); - WriteAutoFilter(ShowTotal); - //for (int i = 0; i < Columns.Count; i++) - //{ - // var v = WorkSheet.GetValue<string>(Address._fromRow, Address._fromCol + i); - // if (!string.IsNullOrEmpty(v) || v != _cols[i].Name) - // { - // _cols[i].Name = v; - // } - //} - } - else - { - SetXmlNodeString(HEADERROWCOUNT_PATH, "0"); - DeleteAllNode(AUTOFILTER_PATH); - } - } - } - internal ExcelAddressBase AutoFilterAddress - { - get - { - string a=GetXmlNodeString(AUTOFILTER_PATH); - if (a == "") - { - return null; - } - else - { - return new ExcelAddressBase(a); - } - } - } - private void WriteAutoFilter(bool showTotal) - { - string autofilterAddress; - if (ShowHeader) - { - if (showTotal) - { - autofilterAddress = ExcelCellBase.GetAddress(Address._fromRow, Address._fromCol, Address._toRow - 1, Address._toCol); - } - else - { - autofilterAddress = Address.Address; - } - SetXmlNodeString(AUTOFILTER_PATH, autofilterAddress); - } - } - /// <summary> - /// If the header row has an autofilter - /// </summary> - public bool ShowFilter - { - get - { - return ShowHeader && AutoFilterAddress != null; - } - set - { - if (ShowHeader) - { - if (value) - { - WriteAutoFilter(ShowTotal); - } - else - { - DeleteAllNode(AUTOFILTER_PATH); - } - } - else if(value) - { - throw(new InvalidOperationException("Filter can only be applied when ShowHeader is set to true")); - } - } - } - const string TOTALSROWCOUNT_PATH = "@totalsRowCount"; - const string TOTALSROWSHOWN_PATH = "@totalsRowShown"; - /// <summary> - /// If the total row is visible or not - /// </summary> - public bool ShowTotal - { - get - { - return GetXmlNodeInt(TOTALSROWCOUNT_PATH) == 1; - } - set - { - if (value != ShowTotal) - { - if (value) - { - Address=new ExcelAddress(WorkSheet.Name, ExcelAddressBase.GetAddress(Address.Start.Row, Address.Start.Column, Address.End.Row+1, Address.End.Column)); - } - else - { - Address = new ExcelAddress(WorkSheet.Name, ExcelAddressBase.GetAddress(Address.Start.Row, Address.Start.Column, Address.End.Row - 1, Address.End.Column)); - } - SetXmlNodeString("@ref", Address.Address); - if (value) - { - SetXmlNodeString(TOTALSROWCOUNT_PATH, "1"); - } - else - { - DeleteNode(TOTALSROWCOUNT_PATH); - } - WriteAutoFilter(value); - } - } - } - const string STYLENAME_PATH = "d:tableStyleInfo/@name"; - /// <summary> - /// The style name for custum styles - /// </summary> - public string StyleName - { - get - { - return GetXmlNodeString(STYLENAME_PATH); - } - set - { - if (value.StartsWith("TableStyle")) - { - try - { - _tableStyle = (TableStyles)Enum.Parse(typeof(TableStyles), value.Substring(10,value.Length-10), true); - } - catch - { - _tableStyle = TableStyles.Custom; - } - } - else if (value == "None") - { - _tableStyle = TableStyles.None; - value = ""; - } - else - { - _tableStyle = TableStyles.Custom; - } - SetXmlNodeString(STYLENAME_PATH,value,true); - } - } - const string SHOWFIRSTCOLUMN_PATH = "d:tableStyleInfo/@showFirstColumn"; - /// <summary> - /// Display special formatting for the first row - /// </summary> - public bool ShowFirstColumn - { - get - { - return GetXmlNodeBool(SHOWFIRSTCOLUMN_PATH); - } - set - { - SetXmlNodeBool(SHOWFIRSTCOLUMN_PATH, value, false); - } - } - const string SHOWLASTCOLUMN_PATH = "d:tableStyleInfo/@showLastColumn"; - /// <summary> - /// Display special formatting for the last row - /// </summary> - public bool ShowLastColumn - { - get - { - return GetXmlNodeBool(SHOWLASTCOLUMN_PATH); - } - set - { - SetXmlNodeBool(SHOWLASTCOLUMN_PATH, value, false); - } - } - const string SHOWROWSTRIPES_PATH = "d:tableStyleInfo/@showRowStripes"; - /// <summary> - /// Display banded rows - /// </summary> - public bool ShowRowStripes - { - get - { - return GetXmlNodeBool(SHOWROWSTRIPES_PATH); - } - set - { - SetXmlNodeBool(SHOWROWSTRIPES_PATH, value, false); - } - } - const string SHOWCOLUMNSTRIPES_PATH = "d:tableStyleInfo/@showColumnStripes"; - /// <summary> - /// Display banded columns - /// </summary> - public bool ShowColumnStripes - { - get - { - return GetXmlNodeBool(SHOWCOLUMNSTRIPES_PATH); - } - set - { - SetXmlNodeBool(SHOWCOLUMNSTRIPES_PATH, value, false); - } - } - - const string TOTALSROWCELLSTYLE_PATH = "@totalsRowCellStyle"; - /// <summary> - /// Named style used for the total row - /// </summary> - public string TotalsRowCellStyle - { - get - { - return GetXmlNodeString(TOTALSROWCELLSTYLE_PATH); - } - set - { - if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexByID(value) < 0) - { - throw (new Exception(string.Format("Named style {0} does not exist.", value))); - } - SetXmlNodeString(TopNode, TOTALSROWCELLSTYLE_PATH, value, true); - - if (ShowTotal) - { - WorkSheet.Cells[Address._toRow, Address._fromCol, Address._toRow, Address._toCol].StyleName = value; - } - } - } - const string DATACELLSTYLE_PATH = "@dataCellStyle"; - /// <summary> - /// Named style used for the data cells - /// </summary> - public string DataCellStyleName - { - get - { - return GetXmlNodeString(DATACELLSTYLE_PATH); - } - set - { - if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexByID(value) < 0) - { - throw (new Exception(string.Format("Named style {0} does not exist.", value))); - } - SetXmlNodeString(TopNode, DATACELLSTYLE_PATH, value, true); - - int fromRow = Address._fromRow + (ShowHeader ? 1 : 0), - toRow = Address._toRow - (ShowTotal ? 1 : 0); - - if (fromRow < toRow) - { - WorkSheet.Cells[fromRow, Address._fromCol, toRow, Address._toCol].StyleName = value; - } - } - } - const string HEADERROWCELLSTYLE_PATH = "@headerRowCellStyle"; - /// <summary> - /// Named style used for the header row - /// </summary> - public string HeaderRowCellStyle - { - get - { - return GetXmlNodeString(HEADERROWCELLSTYLE_PATH); - } - set - { - if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexByID(value) < 0) - { - throw (new Exception(string.Format("Named style {0} does not exist.", value))); - } - SetXmlNodeString(TopNode, HEADERROWCELLSTYLE_PATH, value, true); - - if (ShowHeader) - { - WorkSheet.Cells[Address._fromRow, Address._fromCol, Address._fromRow, Address._toCol].StyleName = value; - } - - } - } - - public bool Equals(ExcelTable x, ExcelTable y) - { - return x.WorkSheet == y.WorkSheet && x.Id == y.Id && x.TableXml.OuterXml == y.TableXml.OuterXml; - } - - public int GetHashCode(ExcelTable obj) - { - return obj.TableXml.OuterXml.GetHashCode(); - } + int cols = Address._toCol - Address._fromCol + 1; + xml += string.Format("<tableColumns count=\"{0}\">", cols); + var names = new Dictionary<string, string>(); + for (int i = 1; i <= cols; i++) { + var cell = WorkSheet.Cells[Address._fromRow, Address._fromCol + i - 1]; + string colName; + if (cell.Value == null || names.ContainsKey(cell.Value.ToString())) { + //Get an unique name + int a = i; + do { + colName = string.Format("Column{0}", a++); + } while (names.ContainsKey(colName)); + } else { + colName = SecurityElement.Escape(cell.Value.ToString()); + } + names.Add(colName, colName); + xml += string.Format("<tableColumn id=\"{0}\" name=\"{1}\" />", i, colName); } + xml += "</tableColumns>"; + xml += + "<tableStyleInfo name=\"TableStyleMedium9\" showFirstColumn=\"0\" showLastColumn=\"0\" showRowStripes=\"1\" showColumnStripes=\"0\" /> "; + xml += "</table>"; + + return xml; + } + + private string CleanDisplayName(string name) { + return Regex.Replace(name, @"[^\w\.-_]", "_"); + } + + internal ZipPackagePart Part { get; set; } + + /// <summary> + /// Provides access to the XML data representing the table in the package. + /// </summary> + public XmlDocument TableXml { get; set; } + + /// <summary> + /// The package internal URI to the Table Xml Document. + /// </summary> + public Uri TableUri { get; internal set; } + + internal string RelationshipID { get; set; } + + private const string _idPath = "@id"; + + internal int Id { + get => GetXmlNodeInt(_idPath); + set => SetXmlNodeString(_idPath, value.ToString()); + } + + private const string _namePath = "@name"; + private const string _displayNamePath = "@displayName"; + + /// <summary> + /// The name of the table object in Excel + /// </summary> + public string Name { + get => GetXmlNodeString(_namePath); + set { + if (WorkSheet.Workbook.ExistsTableName(value)) { + throw (new ArgumentException("Tablename is not unique")); + } + string prevName = Name; + if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) { + int ix = WorkSheet.Tables._tableNames[prevName]; + WorkSheet.Tables._tableNames.Remove(prevName); + WorkSheet.Tables._tableNames.Add(value, ix); + } + SetXmlNodeString(_namePath, value); + SetXmlNodeString(_displayNamePath, CleanDisplayName(value)); + } + } + + /// <summary> + /// The worksheet of the table + /// </summary> + public ExcelWorksheet WorkSheet { get; set; } + + private ExcelAddressBase _address; + + /// <summary> + /// The address of the table + /// </summary> + public ExcelAddressBase Address { + get => _address; + set { + _address = value; + SetXmlNodeString("@ref", value.Address); + WriteAutoFilter(ShowTotal); + } + } + + internal ExcelTableColumnCollection _cols; + + /// <summary> + /// Collection of the columns in the table + /// </summary> + public ExcelTableColumnCollection Columns { + get { + if (_cols == null) { + _cols = new(this); + } + return _cols; + } + } + + private TableStyles _tableStyle = TableStyles.Medium6; + + /// <summary> + /// The table style. If this property is cusom, the style from the StyleName propery is used. + /// </summary> + public TableStyles TableStyle { + get => _tableStyle; + set { + _tableStyle = value; + if (value != TableStyles.Custom) { + SetXmlNodeString(_stylenamePath, "TableStyle" + value); + } + } + } + + private const string _headerrowcountPath = "@headerRowCount"; + private const string _autofilterPath = "d:autoFilter/@ref"; + + /// <summary> + /// If the header row is visible or not + /// </summary> + public bool ShowHeader { + get => GetXmlNodeInt(_headerrowcountPath) != 0; + set { + if (Address._toRow - Address._fromRow < 0 && value + || Address._toRow - Address._fromRow == 1 && value && ShowTotal) { + throw (new("Cant set ShowHeader-property. Table has too few rows")); + } + + if (value) { + DeleteNode(_headerrowcountPath); + WriteAutoFilter(ShowTotal); + //for (int i = 0; i < Columns.Count; i++) + //{ + // var v = WorkSheet.GetValue<string>(Address._fromRow, Address._fromCol + i); + // if (!string.IsNullOrEmpty(v) || v != _cols[i].Name) + // { + // _cols[i].Name = v; + // } + //} + } else { + SetXmlNodeString(_headerrowcountPath, "0"); + DeleteAllNode(_autofilterPath); + } + } + } + + internal ExcelAddressBase AutoFilterAddress { + get { + string a = GetXmlNodeString(_autofilterPath); + if (a == "") { + return null; + } + return new(a); + } + } + + private void WriteAutoFilter(bool showTotal) { + string autofilterAddress; + if (ShowHeader) { + if (showTotal) { + autofilterAddress = ExcelCellBase.GetAddress( + Address._fromRow, + Address._fromCol, + Address._toRow - 1, + Address._toCol); + } else { + autofilterAddress = Address.Address; + } + SetXmlNodeString(_autofilterPath, autofilterAddress); + } + } + + /// <summary> + /// If the header row has an autofilter + /// </summary> + public bool ShowFilter { + get => ShowHeader && AutoFilterAddress != null; + set { + if (ShowHeader) { + if (value) { + WriteAutoFilter(ShowTotal); + } else { + DeleteAllNode(_autofilterPath); + } + } else if (value) { + throw (new InvalidOperationException( + "Filter can only be applied when ShowHeader is set to true")); + } + } + } + + private const string _totalsrowcountPath = "@totalsRowCount"; + private const string _totalsrowshownPath = "@totalsRowShown"; + + /// <summary> + /// If the total row is visible or not + /// </summary> + public bool ShowTotal { + get => GetXmlNodeInt(_totalsrowcountPath) == 1; + set { + if (value != ShowTotal) { + if (value) { + Address = new ExcelAddress( + WorkSheet.Name, + ExcelCellBase.GetAddress( + Address.Start.Row, + Address.Start.Column, + Address.End.Row + 1, + Address.End.Column)); + } else { + Address = new ExcelAddress( + WorkSheet.Name, + ExcelCellBase.GetAddress( + Address.Start.Row, + Address.Start.Column, + Address.End.Row - 1, + Address.End.Column)); + } + SetXmlNodeString("@ref", Address.Address); + if (value) { + SetXmlNodeString(_totalsrowcountPath, "1"); + } else { + DeleteNode(_totalsrowcountPath); + } + WriteAutoFilter(value); + } + } + } + + private const string _stylenamePath = "d:tableStyleInfo/@name"; + + /// <summary> + /// The style name for custum styles + /// </summary> + public string StyleName { + get => GetXmlNodeString(_stylenamePath); + set { + if (value.StartsWith("TableStyle")) { + try { + _tableStyle = (TableStyles) + Enum.Parse(typeof(TableStyles), value.Substring(10, value.Length - 10), true); + } catch { + _tableStyle = TableStyles.Custom; + } + } else if (value == "None") { + _tableStyle = TableStyles.None; + value = ""; + } else { + _tableStyle = TableStyles.Custom; + } + SetXmlNodeString(_stylenamePath, value, true); + } + } + + private const string _showfirstcolumnPath = "d:tableStyleInfo/@showFirstColumn"; + + /// <summary> + /// Display special formatting for the first row + /// </summary> + public bool ShowFirstColumn { + get => GetXmlNodeBool(_showfirstcolumnPath); + set => SetXmlNodeBool(_showfirstcolumnPath, value, false); + } + + private const string _showlastcolumnPath = "d:tableStyleInfo/@showLastColumn"; + + /// <summary> + /// Display special formatting for the last row + /// </summary> + public bool ShowLastColumn { + get => GetXmlNodeBool(_showlastcolumnPath); + set => SetXmlNodeBool(_showlastcolumnPath, value, false); + } + + private const string _showrowstripesPath = "d:tableStyleInfo/@showRowStripes"; + + /// <summary> + /// Display banded rows + /// </summary> + public bool ShowRowStripes { + get => GetXmlNodeBool(_showrowstripesPath); + set => SetXmlNodeBool(_showrowstripesPath, value, false); + } + + private const string _showcolumnstripesPath = "d:tableStyleInfo/@showColumnStripes"; + + /// <summary> + /// Display banded columns + /// </summary> + public bool ShowColumnStripes { + get => GetXmlNodeBool(_showcolumnstripesPath); + set => SetXmlNodeBool(_showcolumnstripesPath, value, false); + } + + private const string _totalsrowcellstylePath = "@totalsRowCellStyle"; + + /// <summary> + /// Named style used for the total row + /// </summary> + public string TotalsRowCellStyle { + get => GetXmlNodeString(_totalsrowcellstylePath); + set { + if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) { + throw (new(string.Format("Named style {0} does not exist.", value))); + } + SetXmlNodeString(TopNode, _totalsrowcellstylePath, value, true); + + if (ShowTotal) { + WorkSheet.Cells[Address._toRow, + Address._fromCol, + Address._toRow, + Address._toCol].StyleName = value; + } + } + } + + private const string _datacellstylePath = "@dataCellStyle"; + + /// <summary> + /// Named style used for the data cells + /// </summary> + public string DataCellStyleName { + get => GetXmlNodeString(_datacellstylePath); + set { + if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) { + throw (new(string.Format("Named style {0} does not exist.", value))); + } + SetXmlNodeString(TopNode, _datacellstylePath, value, true); + + int fromRow = Address._fromRow + (ShowHeader ? 1 : 0), + toRow = Address._toRow - (ShowTotal ? 1 : 0); + + if (fromRow < toRow) { + WorkSheet.Cells[fromRow, Address._fromCol, toRow, Address._toCol].StyleName = value; + } + } + } + + private const string _headerrowcellstylePath = "@headerRowCellStyle"; + + /// <summary> + /// Named style used for the header row + /// </summary> + public string HeaderRowCellStyle { + get => GetXmlNodeString(_headerrowcellstylePath); + set { + if (WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) { + throw (new(string.Format("Named style {0} does not exist.", value))); + } + SetXmlNodeString(TopNode, _headerrowcellstylePath, value, true); + + if (ShowHeader) { + WorkSheet.Cells[Address._fromRow, + Address._fromCol, + Address._fromRow, + Address._toCol].StyleName = value; + } + } + } + + public bool Equals(ExcelTable x, ExcelTable y) { + return x.WorkSheet == y.WorkSheet && x.Id == y.Id && x.TableXml.OuterXml == y.TableXml.OuterXml; + } + + public int GetHashCode(ExcelTable obj) { + return obj.TableXml.OuterXml.GetHashCode(); + } }
diff --git a/EPPlus/Table/ExcelTableCollection.cs b/EPPlus/Table/ExcelTableCollection.cs index b0df086..08576e4 100644 --- a/EPPlus/Table/ExcelTableCollection.cs +++ b/EPPlus/Table/ExcelTableCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,236 +13,201 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 30-AUG-2010 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml; -namespace OfficeOpenXml.Table -{ - /// <summary> - /// A collection of table objects - /// </summary> - public class ExcelTableCollection : IEnumerable<ExcelTable> - { - List<ExcelTable> _tables = new List<ExcelTable>(); - internal Dictionary<string, int> _tableNames = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase); - ExcelWorksheet _ws; - internal ExcelTableCollection(ExcelWorksheet ws) - { - var pck = ws._package.Package; - _ws = ws; - foreach(XmlElement node in ws.WorksheetXml.SelectNodes("//d:tableParts/d:tablePart", ws.NameSpaceManager)) - { - var rel = ws.Part.GetRelationship(node.GetAttribute("id",ExcelPackage.schemaRelationships)); - var tbl = new ExcelTable(rel, ws); - _tableNames.Add(tbl.Name, _tables.Count); - _tables.Add(tbl); - } - } - private ExcelTable Add(ExcelTable tbl) - { - _tables.Add(tbl); - _tableNames.Add(tbl.Name, _tables.Count - 1); - if (tbl.Id >= _ws.Workbook._nextTableID) - { - _ws.Workbook._nextTableID = tbl.Id + 1; - } - return tbl; - } +namespace OfficeOpenXml.Table; - /// <summary> - /// Create a table on the supplied range - /// </summary> - /// <param name="Range">The range address including header and total row</param> - /// <param name="Name">The name of the table. Must be unique </param> - /// <returns>The table object</returns> - public ExcelTable Add(ExcelAddressBase Range, string Name) - { - if (Range.WorkSheet != null && Range.WorkSheet != _ws.Name) - { - throw new ArgumentException("Range does not belong to worksheet", "Range"); - } - - if (string.IsNullOrEmpty(Name)) - { - Name = GetNewTableName(); - } - else if (_ws.Workbook.ExistsTableName(Name)) - { - throw (new ArgumentException("Tablename is not unique")); - } +/// <summary> +/// A collection of table objects +/// </summary> +public class ExcelTableCollection : IEnumerable<ExcelTable> { + private List<ExcelTable> _tables = new(); + internal Dictionary<string, int> _tableNames = new(StringComparer.InvariantCultureIgnoreCase); + private ExcelWorksheet _ws; - ValidateTableName(Name); - - foreach (var t in _tables) - { - if (t.Address.Collide(Range) != ExcelAddressBase.eAddressCollition.No) - { - throw (new ArgumentException(string.Format("Table range collides with table {0}", t.Name))); - } - } - return Add(new ExcelTable(_ws, Range, Name, _ws.Workbook._nextTableID)); - } - - private void ValidateTableName(string Name) - { - if (string.IsNullOrEmpty(Name)) - { - throw new ArgumentException("Tablename is null or empty"); - } - - char firstLetterOfName = Name[0]; - if (Char.IsLetter(firstLetterOfName) == false && firstLetterOfName != '_' && firstLetterOfName != '\\') - { - throw new ArgumentException("Tablename start with invalid character"); - } - - if (Name.Contains(" ")) - { - throw new ArgumentException("Tablename has spaces"); - } - - } - - public void Delete(int Index, bool ClearRange = false) - { - Delete(this[Index], ClearRange); - } - - public void Delete(string Name, bool ClearRange = false) - { - if (this[Name] == null) - { - throw new ArgumentOutOfRangeException(string.Format("Cannot delete non-existant table {0} in sheet {1}.", Name, _ws.Name)); - } - Delete(this[Name], ClearRange); - } - - - public void Delete(ExcelTable Table, bool ClearRange = false) - { - if (!this._tables.Contains(Table)) - { - throw new ArgumentOutOfRangeException("Table", String.Format("Table {0} does not exist in this collection", Table.Name)); - } - lock (this) - { - var range = _ws.Cells[Table.Address.Address]; - _tableNames.Remove(Table.Name); - _tables.Remove(Table); - foreach (var sheet in Table.WorkSheet.Workbook.Worksheets) - { - foreach (var table in sheet.Tables) - { - if (table.Id > Table.Id) table.Id--; - } - Table.WorkSheet.Workbook._nextTableID--; - } - if (ClearRange) - { - range.Clear(); - } - } - - } - - internal string GetNewTableName() - { - string name = "Table1"; - int i = 2; - while (_ws.Workbook.ExistsTableName(name)) - { - name = string.Format("Table{0}", i++); - } - return name; - } - /// <summary> - /// Number of items in the collection - /// </summary> - public int Count - { - get - { - return _tables.Count; - } - } - /// <summary> - /// Get the table object from a range. - /// </summary> - /// <param name="Range">The range</param> - /// <returns>The table. Null if no range matches</returns> - public ExcelTable GetFromRange(ExcelRangeBase Range) - { - foreach (var tbl in Range.Worksheet.Tables) - { - if (tbl.Address._address == Range._address) - { - return tbl; - } - } - return null; - } - /// <summary> - /// The table Index. Base 0. - /// </summary> - /// <param name="Index"></param> - /// <returns></returns> - public ExcelTable this[int Index] - { - get - { - if (Index < 0 || Index >= _tables.Count) - { - throw (new ArgumentOutOfRangeException("Table index out of range")); - } - return _tables[Index]; - } - } - /// <summary> - /// Indexer - /// </summary> - /// <param name="Name">The name of the table</param> - /// <returns>The table. Null if the table name is not found in the collection</returns> - public ExcelTable this[string Name] - { - get - { - if (_tableNames.ContainsKey(Name)) - { - return _tables[_tableNames[Name]]; - } - else - { - return null; - } - } - } - public IEnumerator<ExcelTable> GetEnumerator() - { - return _tables.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _tables.GetEnumerator(); - } + internal ExcelTableCollection(ExcelWorksheet ws) { + var pck = ws._package.Package; + _ws = ws; + foreach (XmlElement node in ws.WorksheetXml.SelectNodes( + "//d:tableParts/d:tablePart", + ws.NameSpaceManager)) { + var rel = ws.Part.GetRelationship(node.GetAttribute("id", ExcelPackage._schemaRelationships)); + var tbl = new ExcelTable(rel, ws); + _tableNames.Add(tbl.Name, _tables.Count); + _tables.Add(tbl); } + } + + private ExcelTable Add(ExcelTable tbl) { + _tables.Add(tbl); + _tableNames.Add(tbl.Name, _tables.Count - 1); + if (tbl.Id >= _ws.Workbook._nextTableID) { + _ws.Workbook._nextTableID = tbl.Id + 1; + } + return tbl; + } + + /// <summary> + /// Create a table on the supplied range + /// </summary> + /// <param name="range">The range address including header and total row</param> + /// <param name="name">The name of the table. Must be unique </param> + /// <returns>The table object</returns> + public ExcelTable Add(ExcelAddressBase range, string name) { + if (range.WorkSheet != null && range.WorkSheet != _ws.Name) { + throw new ArgumentException("Range does not belong to worksheet", "range"); + } + + if (string.IsNullOrEmpty(name)) { + name = GetNewTableName(); + } else if (_ws.Workbook.ExistsTableName(name)) { + throw (new ArgumentException("Tablename is not unique")); + } + + ValidateTableName(name); + + foreach (var t in _tables) { + if (t.Address.Collide(range) != ExcelAddressBase.eAddressCollition.No) { + throw (new ArgumentException(string.Format("Table range collides with table {0}", t.Name))); + } + } + return Add(new(_ws, range, name, _ws.Workbook._nextTableID)); + } + + private void ValidateTableName(string name) { + if (string.IsNullOrEmpty(name)) { + throw new ArgumentException("Tablename is null or empty"); + } + + char firstLetterOfName = name[0]; + if (Char.IsLetter(firstLetterOfName) == false + && firstLetterOfName != '_' + && firstLetterOfName != '\\') { + throw new ArgumentException("Tablename start with invalid character"); + } + + if (name.Contains(" ")) { + throw new ArgumentException("Tablename has spaces"); + } + } + + public void Delete(int index, bool clearRange = false) { + Delete(this[index], clearRange); + } + + public void Delete(string name, bool clearRange = false) { + if (this[name] == null) { + throw new ArgumentOutOfRangeException( + string.Format("Cannot delete non-existant table {0} in sheet {1}.", name, _ws.Name)); + } + Delete(this[name], clearRange); + } + + public void Delete(ExcelTable excelTable, bool clearRange = false) { + if (!_tables.Contains(excelTable)) { + throw new ArgumentOutOfRangeException( + "excelTable", + String.Format("Table {0} does not exist in this collection", excelTable.Name)); + } + lock (this) { + var range = _ws.Cells[excelTable.Address.Address]; + _tableNames.Remove(excelTable.Name); + _tables.Remove(excelTable); + foreach (var sheet in excelTable.WorkSheet.Workbook.Worksheets) { + foreach (var table in sheet.Tables) { + if (table.Id > excelTable.Id) { + table.Id--; + } + } + excelTable.WorkSheet.Workbook._nextTableID--; + } + if (clearRange) { + range.Clear(); + } + } + } + + internal string GetNewTableName() { + string name = "Table1"; + int i = 2; + while (_ws.Workbook.ExistsTableName(name)) { + name = string.Format("Table{0}", i++); + } + return name; + } + + /// <summary> + /// Number of items in the collection + /// </summary> + public int Count => _tables.Count; + + /// <summary> + /// Get the table object from a range. + /// </summary> + /// <param name="range">The range</param> + /// <returns>The table. Null if no range matches</returns> + public ExcelTable GetFromRange(ExcelRangeBase range) { + foreach (var tbl in range.Worksheet.Tables) { + if (tbl.Address._address == range._address) { + return tbl; + } + } + return null; + } + + /// <summary> + /// The table Index. Base 0. + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public ExcelTable this[int index] { + get { + if (index < 0 || index >= _tables.Count) { + throw (new ArgumentOutOfRangeException("Table index out of range")); + } + return _tables[index]; + } + } + + /// <summary> + /// Indexer + /// </summary> + /// <param name="name">The name of the table</param> + /// <returns>The table. Null if the table name is not found in the collection</returns> + public ExcelTable this[string name] { + get { + if (_tableNames.ContainsKey(name)) { + return _tables[_tableNames[name]]; + } + return null; + } + } + + public IEnumerator<ExcelTable> GetEnumerator() { + return _tables.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _tables.GetEnumerator(); + } }
diff --git a/EPPlus/Table/ExcelTableColumn.cs b/EPPlus/Table/ExcelTableColumn.cs index 0c45529..6680424 100644 --- a/EPPlus/Table/ExcelTableColumn.cs +++ b/EPPlus/Table/ExcelTableColumn.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,228 +13,191 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 30-AUG-2010 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Xml; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.Table -{ - /// <summary> - /// Build-in table row functions - /// </summary> - public enum RowFunctions - { - Average, - Count, - CountNums, - Custom, - Max, - Min, - None, - StdDev, - Sum, - Var +namespace OfficeOpenXml.Table; + +/// <summary> +/// Build-in table row functions +/// </summary> +public enum RowFunctions { + Average, + Count, + CountNums, + Custom, + Max, + Min, + None, + StdDev, + Sum, + Var, +} + +/// <summary> +/// A table column +/// </summary> +public class ExcelTableColumn : XmlHelper { + internal ExcelTable _tbl; + + internal ExcelTableColumn(XmlNamespaceManager ns, XmlNode topNode, ExcelTable tbl, int pos) + : base(ns, topNode) { + _tbl = tbl; + Position = pos; + } + + /// <summary> + /// The column id + /// </summary> + public int Id { + get => GetXmlNodeInt("@id"); + set => SetXmlNodeString("@id", value.ToString()); + } + + /// <summary> + /// The position of the column + /// </summary> + public int Position { get; private set; } + + /// <summary> + /// The name of the column + /// </summary> + public string Name { + get { + var n = GetXmlNodeString("@name"); + if (string.IsNullOrEmpty(n)) { + if (_tbl.ShowHeader) { + n = ConvertUtil.ExcelDecodeString( + _tbl.WorkSheet.GetValue<string>( + _tbl.Address._fromRow, + _tbl.Address._fromCol + Position)); + } else { + n = "Column" + (Position + 1); + } + } + return n; } - - /// <summary> - /// A table column - /// </summary> - public class ExcelTableColumn : XmlHelper - { - internal ExcelTable _tbl; - internal ExcelTableColumn(XmlNamespaceManager ns, XmlNode topNode, ExcelTable tbl, int pos) : - base(ns, topNode) - { - _tbl = tbl; - Position = pos; - } - /// <summary> - /// The column id - /// </summary> - public int Id - { - get - { - return GetXmlNodeInt("@id"); - } - set - { - SetXmlNodeString("@id", value.ToString()); - } - } - /// <summary> - /// The position of the column - /// </summary> - public int Position - { - get; - private set; - } - /// <summary> - /// The name of the column - /// </summary> - public string Name - { - get - { - var n=GetXmlNodeString("@name"); - if (string.IsNullOrEmpty(n)) - { - if (_tbl.ShowHeader) - { - n = ConvertUtil.ExcelDecodeString(_tbl.WorkSheet.GetValue<string>(_tbl.Address._fromRow, _tbl.Address._fromCol + this.Position)); - } - else - { - n = "Column" + (this.Position+1).ToString(); - } - } - return n; - } - set - { - var v = ConvertUtil.ExcelEncodeString(value); - SetXmlNodeString("@name", v); - if (_tbl.ShowHeader) - { - _tbl.WorkSheet.SetValue(_tbl.Address._fromRow, _tbl.Address._fromCol + this.Position, value); - } - _tbl.WorkSheet.SetTableTotalFunction(_tbl, this); - } - } - /// <summary> - /// A string text in the total row - /// </summary> - public string TotalsRowLabel - { - get - { - return GetXmlNodeString("@totalsRowLabel"); - } - set - { - SetXmlNodeString("@totalsRowLabel", value); - } - } - /// <summary> - /// Build-in total row functions. - /// To set a custom Total row formula use the TotalsRowFormula property - /// <seealso cref="TotalsRowFormula"/> - /// </summary> - public RowFunctions TotalsRowFunction - { - get - { - if (GetXmlNodeString("@totalsRowFunction") == "") - { - return RowFunctions.None; - } - else - { - return (RowFunctions)Enum.Parse(typeof(RowFunctions), GetXmlNodeString("@totalsRowFunction"), true); - } - } - set - { - if (value == RowFunctions.Custom) - { - throw(new Exception("Use the TotalsRowFormula-property to set a custom table formula")); - } - string s = value.ToString(); - s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1, s.Length - 1); - SetXmlNodeString("@totalsRowFunction", s); - _tbl.WorkSheet.SetTableTotalFunction(_tbl, this); - } - } - const string TOTALSROWFORMULA_PATH = "d:totalsRowFormula"; - /// <summary> - /// Sets a custom Totals row Formula. - /// Be carefull with this property since it is not validated. - /// <example> - /// tbl.Columns[9].TotalsRowFormula = string.Format("SUM([{0}])",tbl.Columns[9].Name); - /// </example> - /// </summary> - public string TotalsRowFormula - { - get - { - return GetXmlNodeString(TOTALSROWFORMULA_PATH); - } - set - { - if (value.StartsWith("=")) value = value.Substring(1, value.Length - 1); - SetXmlNodeString("@totalsRowFunction", "custom"); - SetXmlNodeString(TOTALSROWFORMULA_PATH, value); - _tbl.WorkSheet.SetTableTotalFunction(_tbl, this); - } - } - const string DATACELLSTYLE_PATH = "@dataCellStyle"; - /// <summary> - /// The named style for datacells in the column - /// </summary> - public string DataCellStyleName - { - get - { - return GetXmlNodeString(DATACELLSTYLE_PATH); - } - set - { - if(_tbl.WorkSheet.Workbook.Styles.NamedStyles.FindIndexByID(value)<0) - { - throw(new Exception(string.Format("Named style {0} does not exist.",value))); - } - SetXmlNodeString(TopNode, DATACELLSTYLE_PATH, value,true); - - int fromRow=_tbl.Address._fromRow + (_tbl.ShowHeader?1:0), - toRow=_tbl.Address._toRow - (_tbl.ShowTotal?1:0), - col=_tbl.Address._fromCol+Position; - - if (fromRow <= toRow) - { - _tbl.WorkSheet.Cells[fromRow, col, toRow, col].StyleName = value; - } - } - } - const string CALCULATEDCOLUMNFORMULA_PATH = "d:calculatedColumnFormula"; - /// <summary> - /// Sets a calculated column Formula. - /// Be carefull with this property since it is not validated. - /// <example> - /// tbl.Columns[9].CalculatedColumnFormula = string.Format("SUM(MyDataTable[[#This Row],[{0}]])",tbl.Columns[9].Name); - /// </example> - /// </summary> - public string CalculatedColumnFormula - { - get - { - return GetXmlNodeString(CALCULATEDCOLUMNFORMULA_PATH); - } - set - { - if (value.StartsWith("=")) value = value.Substring(1, value.Length - 1); - SetXmlNodeString(CALCULATEDCOLUMNFORMULA_PATH, value); - } - } - + set { + var v = ConvertUtil.ExcelEncodeString(value); + SetXmlNodeString("@name", v); + if (_tbl.ShowHeader) { + _tbl.WorkSheet.SetValue(_tbl.Address._fromRow, _tbl.Address._fromCol + Position, value); + } + _tbl.WorkSheet.SetTableTotalFunction(_tbl, this); } + } + + /// <summary> + /// A string text in the total row + /// </summary> + public string TotalsRowLabel { + get => GetXmlNodeString("@totalsRowLabel"); + set => SetXmlNodeString("@totalsRowLabel", value); + } + + /// <summary> + /// Build-in total row functions. + /// To set a custom Total row formula use the TotalsRowFormula property + /// <seealso cref="TotalsRowFormula"/> + /// </summary> + public RowFunctions TotalsRowFunction { + get { + if (GetXmlNodeString("@totalsRowFunction") == "") { + return RowFunctions.None; + } + return (RowFunctions) + Enum.Parse(typeof(RowFunctions), GetXmlNodeString("@totalsRowFunction"), true); + } + set { + if (value == RowFunctions.Custom) { + throw (new("Use the TotalsRowFormula-property to set a custom table formula")); + } + string s = value.ToString(); + s = s.Substring(0, 1).ToLower(CultureInfo.InvariantCulture) + s.Substring(1, s.Length - 1); + SetXmlNodeString("@totalsRowFunction", s); + _tbl.WorkSheet.SetTableTotalFunction(_tbl, this); + } + } + + private const string _totalsrowformulaPath = "d:totalsRowFormula"; + + /// <summary> + /// Sets a custom Totals row Formula. + /// Be carefull with this property since it is not validated. + /// <example> + /// tbl.Columns[9].TotalsRowFormula = string.Format("SUM([{0}])",tbl.Columns[9].Name); + /// </example> + /// </summary> + public string TotalsRowFormula { + get => GetXmlNodeString(_totalsrowformulaPath); + set { + if (value.StartsWith("=")) { + value = value.Substring(1, value.Length - 1); + } + SetXmlNodeString("@totalsRowFunction", "custom"); + SetXmlNodeString(_totalsrowformulaPath, value); + _tbl.WorkSheet.SetTableTotalFunction(_tbl, this); + } + } + + private const string _datacellstylePath = "@dataCellStyle"; + + /// <summary> + /// The named style for datacells in the column + /// </summary> + public string DataCellStyleName { + get => GetXmlNodeString(_datacellstylePath); + set { + if (_tbl.WorkSheet.Workbook.Styles.NamedStyles.FindIndexById(value) < 0) { + throw (new(string.Format("Named style {0} does not exist.", value))); + } + SetXmlNodeString(TopNode, _datacellstylePath, value, true); + + int fromRow = _tbl.Address._fromRow + (_tbl.ShowHeader ? 1 : 0), + toRow = _tbl.Address._toRow - (_tbl.ShowTotal ? 1 : 0), + col = _tbl.Address._fromCol + Position; + + if (fromRow <= toRow) { + _tbl.WorkSheet.Cells[fromRow, col, toRow, col].StyleName = value; + } + } + } + + private const string _calculatedcolumnformulaPath = "d:calculatedColumnFormula"; + + /// <summary> + /// Sets a calculated column Formula. + /// Be carefull with this property since it is not validated. + /// <example> + /// tbl.Columns[9].CalculatedColumnFormula = string.Format("SUM(MyDataTable[[#This Row],[{0}]])",tbl.Columns[9].Name); + /// </example> + /// </summary> + public string CalculatedColumnFormula { + get => GetXmlNodeString(_calculatedcolumnformulaPath); + set { + if (value.StartsWith("=")) { + value = value.Substring(1, value.Length - 1); + } + SetXmlNodeString(_calculatedcolumnformulaPath, value); + } + } }
diff --git a/EPPlus/Table/ExcelTableColumnCollection.cs b/EPPlus/Table/ExcelTableColumnCollection.cs index 3a4d23f..864e026 100644 --- a/EPPlus/Table/ExcelTableColumnCollection.cs +++ b/EPPlus/Table/ExcelTableColumnCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,123 +13,103 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 30-AUG-2010 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Xml; -namespace OfficeOpenXml.Table -{ - /// <summary> - /// A collection of table columns - /// </summary> - public class ExcelTableColumnCollection : IEnumerable<ExcelTableColumn> - { - List<ExcelTableColumn> _cols = new List<ExcelTableColumn>(); - Dictionary<string, int> _colNames = new Dictionary<string, int>(StringComparer.InvariantCultureIgnoreCase); - public ExcelTableColumnCollection(ExcelTable table) - { - Table = table; - foreach(XmlNode node in table.TableXml.SelectNodes("//d:table/d:tableColumns/d:tableColumn",table.NameSpaceManager)) - { - _cols.Add(new ExcelTableColumn(table.NameSpaceManager, node, table, _cols.Count)); - _colNames.Add(_cols[_cols.Count - 1].Name, _cols.Count - 1); - } - } - /// <summary> - /// A reference to the table object - /// </summary> - public ExcelTable Table - { - get; - private set; - } - /// <summary> - /// Number of items in the collection - /// </summary> - public int Count - { - get - { - return _cols.Count; - } - } - /// <summary> - /// The column Index. Base 0. - /// </summary> - /// <param name="Index"></param> - /// <returns></returns> - public ExcelTableColumn this[int Index] - { - get - { - if (Index < 0 || Index >= _cols.Count) - { - throw (new ArgumentOutOfRangeException("Column index out of range")); - } - return _cols[Index] as ExcelTableColumn; - } - } - /// <summary> - /// Indexer - /// </summary> - /// <param name="Name">The name of the table</param> - /// <returns>The table column. Null if the table name is not found in the collection</returns> - public ExcelTableColumn this[string Name] - { - get - { - if (_colNames.ContainsKey(Name)) - { - return _cols[_colNames[Name]]; - } - else - { - return null; - } - } - } +namespace OfficeOpenXml.Table; - IEnumerator<ExcelTableColumn> IEnumerable<ExcelTableColumn>.GetEnumerator() - { - return _cols.GetEnumerator(); - } +/// <summary> +/// A collection of table columns +/// </summary> +public class ExcelTableColumnCollection : IEnumerable<ExcelTableColumn> { + private List<ExcelTableColumn> _cols = new(); + private Dictionary<string, int> _colNames = new(StringComparer.InvariantCultureIgnoreCase); - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _cols.GetEnumerator(); - } - internal string GetUniqueName(string name) - { - if (_colNames.ContainsKey(name)) - { - var newName = name; - var i = 2; - do - { - newName = name+(i++).ToString(CultureInfo.InvariantCulture); - } - while (_colNames.ContainsKey(newName)); - return newName; - } - return name; - } + public ExcelTableColumnCollection(ExcelTable table) { + Table = table; + foreach (XmlNode node in table.TableXml.SelectNodes( + "//d:table/d:tableColumns/d:tableColumn", + table.NameSpaceManager)) { + _cols.Add(new(table.NameSpaceManager, node, table, _cols.Count)); + _colNames.Add(_cols[_cols.Count - 1].Name, _cols.Count - 1); } + } + + /// <summary> + /// A reference to the table object + /// </summary> + public ExcelTable Table { get; private set; } + + /// <summary> + /// Number of items in the collection + /// </summary> + public int Count => _cols.Count; + + /// <summary> + /// The column Index. Base 0. + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public ExcelTableColumn this[int index] { + get { + if (index < 0 || index >= _cols.Count) { + throw (new ArgumentOutOfRangeException("Column index out of range")); + } + return _cols[index]; + } + } + + /// <summary> + /// Indexer + /// </summary> + /// <param name="name">The name of the table</param> + /// <returns>The table column. Null if the table name is not found in the collection</returns> + public ExcelTableColumn this[string name] { + get { + if (_colNames.ContainsKey(name)) { + return _cols[_colNames[name]]; + } + return null; + } + } + + IEnumerator<ExcelTableColumn> IEnumerable<ExcelTableColumn>.GetEnumerator() { + return _cols.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _cols.GetEnumerator(); + } + + internal string GetUniqueName(string name) { + if (_colNames.ContainsKey(name)) { + var newName = name; + var i = 2; + do { + newName = name + (i++).ToString(CultureInfo.InvariantCulture); + } while (_colNames.ContainsKey(newName)); + return newName; + } + return name; + } }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs b/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs index eb812ea..d25001f 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotCacheDefinition.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,282 +13,259 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Data.SqlClient; +using System.Linq; using System.Text; using System.Xml; -using System.Linq; +using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.Table.PivotTable -{ - public enum eSourceType - { - /// <summary> - /// Indicates that the cache contains data that consolidates ranges. - /// </summary> - Consolidation, - /// <summary> - /// Indicates that the cache contains data from an external data source. - /// </summary> - External, - /// <summary> - /// Indicates that the cache contains a scenario summary report - /// </summary> - Scenario, - /// <summary> - /// Indicates that the cache contains worksheet data - /// </summary> - Worksheet + +namespace OfficeOpenXml.Table.PivotTable; + +public enum eSourceType { + /// <summary> + /// Indicates that the cache contains data that consolidates ranges. + /// </summary> + Consolidation, + + /// <summary> + /// Indicates that the cache contains data from an external data source. + /// </summary> + External, + + /// <summary> + /// Indicates that the cache contains a scenario summary report + /// </summary> + Scenario, + + /// <summary> + /// Indicates that the cache contains worksheet data + /// </summary> + Worksheet, +} + +/// <summary> +/// Cache definition. This class defines the source data. Note that one cache definition can be shared between many pivot tables. +/// </summary> +public class ExcelPivotCacheDefinition : XmlHelper { + internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable) + : base(ns, null) { + foreach (var r in pivotTable.Part.GetRelationshipsByType( + ExcelPackage._schemaRelationships + "/pivotCacheDefinition")) { + Relationship = r; } - /// <summary> - /// Cache definition. This class defines the source data. Note that one cache definition can be shared between many pivot tables. - /// </summary> - public class ExcelPivotCacheDefinition : XmlHelper - { - internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable) : - base(ns, null) - { - foreach (var r in pivotTable.Part.GetRelationshipsByType(ExcelPackage.schemaRelationships + "/pivotCacheDefinition")) - { - Relationship = r; - } - CacheDefinitionUri = UriHelper.ResolvePartUri(Relationship.SourceUri, Relationship.TargetUri); + CacheDefinitionUri = UriHelper.ResolvePartUri(Relationship.SourceUri, Relationship.TargetUri); - var pck = pivotTable.WorkSheet._package.Package; - Part = pck.GetPart(CacheDefinitionUri); - CacheDefinitionXml = new XmlDocument(); - LoadXmlSafe(CacheDefinitionXml, Part.GetStream()); + var pck = pivotTable.WorkSheet._package.Package; + Part = pck.GetPart(CacheDefinitionUri); + CacheDefinitionXml = new(); + LoadXmlSafe(CacheDefinitionXml, Part.GetStream()); - TopNode = CacheDefinitionXml.DocumentElement; - PivotTable = pivotTable; - if (CacheSource == eSourceType.Worksheet) - { - var worksheetName = GetXmlNodeString(_sourceWorksheetPath); - if (pivotTable.WorkSheet.Workbook.Worksheets.Any(t => t.Name == worksheetName)) - { - _sourceRange = pivotTable.WorkSheet.Workbook.Worksheets[worksheetName].Cells[GetXmlNodeString(_sourceAddressPath)]; - } - } - } - internal ExcelPivotCacheDefinition(XmlNamespaceManager ns, ExcelPivotTable pivotTable, ExcelRangeBase sourceAddress, int tblId) : - base(ns, null) - { - PivotTable = pivotTable; + TopNode = CacheDefinitionXml.DocumentElement; + PivotTable = pivotTable; + if (CacheSource == eSourceType.Worksheet) { + var worksheetName = GetXmlNodeString(_sourceWorksheetPath); + if (pivotTable.WorkSheet.Workbook.Worksheets.Any(t => t.Name == worksheetName)) { + _sourceRange = pivotTable + .WorkSheet + .Workbook + .Worksheets[worksheetName].Cells[GetXmlNodeString(_sourceAddressPath)]; + } + } + } - var pck = pivotTable.WorkSheet._package.Package; - - //CacheDefinition - CacheDefinitionXml = new XmlDocument(); - LoadXmlSafe(CacheDefinitionXml, GetStartXml(sourceAddress), Encoding.UTF8); - CacheDefinitionUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheDefinition{0}.xml", tblId); - Part = pck.CreatePart(CacheDefinitionUri, ExcelPackage.schemaPivotCacheDefinition); - TopNode = CacheDefinitionXml.DocumentElement; + internal ExcelPivotCacheDefinition( + XmlNamespaceManager ns, + ExcelPivotTable pivotTable, + ExcelRangeBase sourceAddress, + int tblId) + : base(ns, null) { + PivotTable = pivotTable; - //CacheRecord. Create an empty one. - CacheRecordUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheRecords{0}.xml", tblId); - var cacheRecord = new XmlDocument(); - cacheRecord.LoadXml("<pivotCacheRecords xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" count=\"0\" />"); - var recPart = pck.CreatePart(CacheRecordUri, ExcelPackage.schemaPivotCacheRecords); - cacheRecord.Save(recPart.GetStream()); + var pck = pivotTable.WorkSheet._package.Package; - RecordRelationship = Part.CreateRelationship(UriHelper.ResolvePartUri(CacheDefinitionUri, CacheRecordUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotCacheRecords"); - RecordRelationshipID = RecordRelationship.Id; + //CacheDefinition + CacheDefinitionXml = new(); + LoadXmlSafe(CacheDefinitionXml, GetStartXml(sourceAddress), Encoding.UTF8); + CacheDefinitionUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheDefinition{0}.xml", tblId); + Part = pck.CreatePart(CacheDefinitionUri, ExcelPackage._schemaPivotCacheDefinition); + TopNode = CacheDefinitionXml.DocumentElement; - CacheDefinitionXml.Save(Part.GetStream()); - } - /// <summary> - /// Reference to the internal package part - /// </summary> - internal Packaging.ZipPackagePart Part - { - get; - set; - } - /// <summary> - /// Provides access to the XML data representing the cache definition in the package. - /// </summary> - public XmlDocument CacheDefinitionXml { get; private set; } - /// <summary> - /// The package internal URI to the pivottable cache definition Xml Document. - /// </summary> - public Uri CacheDefinitionUri - { - get; - internal set; - } - internal Uri CacheRecordUri - { - get; - set; - } - internal Packaging.ZipPackageRelationship Relationship - { - get; - set; - } - internal Packaging.ZipPackageRelationship RecordRelationship - { - get; - set; - } - internal string RecordRelationshipID - { - get - { - return GetXmlNodeString("@r:id"); - } - set - { - SetXmlNodeString("@r:id", value); - } - } - /// <summary> - /// Referece to the PivoTable object - /// </summary> - public ExcelPivotTable PivotTable - { - get; - private set; - } - - const string _sourceWorksheetPath="d:cacheSource/d:worksheetSource/@sheet"; - const string _sourceNamePath = "d:cacheSource/d:worksheetSource/@name"; - const string _sourceAddressPath = "d:cacheSource/d:worksheetSource/@ref"; - internal ExcelRangeBase _sourceRange = null; - /// <summary> - /// The source data range when the pivottable has a worksheet datasource. - /// The number of columns in the range must be intact if this property is changed. - /// The range must be in the same workbook as the pivottable. - /// </summary> - public ExcelRangeBase SourceRange - { - get - { - if (_sourceRange == null) - { - if (CacheSource == eSourceType.Worksheet) - { - var ws = PivotTable.WorkSheet.Workbook.Worksheets[GetXmlNodeString(_sourceWorksheetPath)]; - if (ws == null) //Not worksheet, check name or table name - { - var name = GetXmlNodeString(_sourceNamePath); - foreach (var n in PivotTable.WorkSheet.Workbook.Names) - { - if(name.Equals(n.Name,StringComparison.InvariantCultureIgnoreCase)) - { - _sourceRange = n; - return _sourceRange; - } - } - foreach (var w in PivotTable.WorkSheet.Workbook.Worksheets) - { - if (w.Tables._tableNames.ContainsKey(name)) - { - _sourceRange = w.Cells[w.Tables[name].Address.Address]; - break; - } - foreach (var n in w.Names) - { - if (name.Equals(n.Name, StringComparison.InvariantCultureIgnoreCase)) - { - _sourceRange = n; - break; - } - } - } - } - else - { - _sourceRange = ws.Cells[GetXmlNodeString(_sourceAddressPath)]; - } - } - else - { - throw (new ArgumentException("The cachesource is not a worksheet")); - } - } + //CacheRecord. Create an empty one. + CacheRecordUri = GetNewUri(pck, "/xl/pivotCache/pivotCacheRecords{0}.xml", tblId); + var cacheRecord = new XmlDocument(); + cacheRecord.LoadXml( + "<pivotCacheRecords xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" count=\"0\" />"); + var recPart = pck.CreatePart(CacheRecordUri, ExcelPackage._schemaPivotCacheRecords); + cacheRecord.Save(recPart.GetStream()); + + RecordRelationship = Part.CreateRelationship( + UriHelper.ResolvePartUri(CacheDefinitionUri, CacheRecordUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/pivotCacheRecords"); + RecordRelationshipID = RecordRelationship.Id; + + CacheDefinitionXml.Save(Part.GetStream()); + } + + /// <summary> + /// Reference to the internal package part + /// </summary> + internal ZipPackagePart Part { get; set; } + + /// <summary> + /// Provides access to the XML data representing the cache definition in the package. + /// </summary> + public XmlDocument CacheDefinitionXml { get; private set; } + + /// <summary> + /// The package internal URI to the pivottable cache definition Xml Document. + /// </summary> + public Uri CacheDefinitionUri { get; internal set; } + + internal Uri CacheRecordUri { get; set; } + + internal ZipPackageRelationship Relationship { get; set; } + + internal ZipPackageRelationship RecordRelationship { get; set; } + + internal string RecordRelationshipID { + get => GetXmlNodeString("@r:id"); + set => SetXmlNodeString("@r:id", value); + } + + /// <summary> + /// Referece to the PivoTable object + /// </summary> + public ExcelPivotTable PivotTable { get; private set; } + + private const string _sourceWorksheetPath = "d:cacheSource/d:worksheetSource/@sheet"; + private const string _sourceNamePath = "d:cacheSource/d:worksheetSource/@name"; + private const string _sourceAddressPath = "d:cacheSource/d:worksheetSource/@ref"; + internal ExcelRangeBase _sourceRange; + + /// <summary> + /// The source data range when the pivottable has a worksheet datasource. + /// The number of columns in the range must be intact if this property is changed. + /// The range must be in the same workbook as the pivottable. + /// </summary> + public ExcelRangeBase SourceRange { + get { + if (_sourceRange == null) { + if (CacheSource == eSourceType.Worksheet) { + var ws = PivotTable.WorkSheet.Workbook.Worksheets[GetXmlNodeString(_sourceWorksheetPath)]; + if (ws + == null) //Not worksheet, check name or table name + { + var name = GetXmlNodeString(_sourceNamePath); + foreach (var n in PivotTable.WorkSheet.Workbook.Names) { + if (name.Equals(n.Name, StringComparison.InvariantCultureIgnoreCase)) { + _sourceRange = n; return _sourceRange; + } } - set - { - if (PivotTable.WorkSheet.Workbook != value.Worksheet.Workbook) - { - throw (new ArgumentException("Range must be in the same package as the pivottable")); + foreach (var w in PivotTable.WorkSheet.Workbook.Worksheets) { + if (w.Tables._tableNames.ContainsKey(name)) { + _sourceRange = w.Cells[w.Tables[name].Address.Address]; + break; + } + foreach (var n in w.Names) { + if (name.Equals(n.Name, StringComparison.InvariantCultureIgnoreCase)) { + _sourceRange = n; + break; } - - var sr=SourceRange; - if (value.End.Column - value.Start.Column != sr.End.Column - sr.Start.Column) - { - throw (new ArgumentException("Can not change the number of columns(fields) in the SourceRange")); - } - - SetXmlNodeString(_sourceWorksheetPath, value.Worksheet.Name); - SetXmlNodeString(_sourceAddressPath, value.FirstAddress); - _sourceRange = value; + } } + } else { + _sourceRange = ws.Cells[GetXmlNodeString(_sourceAddressPath)]; + } + } else { + throw (new ArgumentException("The cachesource is not a worksheet")); } - /// <summary> - /// Type of source data - /// </summary> - public eSourceType CacheSource - { - get - { - var s=GetXmlNodeString("d:cacheSource/@type"); - if (s == "") - { - return eSourceType.Worksheet; - } - else - { - return (eSourceType)Enum.Parse(typeof(eSourceType), s, true); - } - } - } - private string GetStartXml(ExcelRangeBase sourceAddress) - { - string xml="<pivotCacheDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"\" refreshOnLoad=\"1\" refreshedBy=\"SomeUser\" refreshedDate=\"40504.582403125001\" createdVersion=\"1\" refreshedVersion=\"3\" recordCount=\"5\" upgradeOnRefresh=\"1\">"; - - xml += "<cacheSource type=\"worksheet\">"; - xml += string.Format("<worksheetSource ref=\"{0}\" sheet=\"{1}\" /> ", sourceAddress.Address, sourceAddress.WorkSheet); - xml += "</cacheSource>"; - xml += string.Format("<cacheFields count=\"{0}\">", sourceAddress._toCol - sourceAddress._fromCol + 1); - var sourceWorksheet = PivotTable.WorkSheet.Workbook.Worksheets[sourceAddress.WorkSheet]; - for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) - { - if (sourceWorksheet == null || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col) == null || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col).ToString().Trim() == "") - { - xml += string.Format("<cacheField name=\"Column{0}\" numFmtId=\"0\">", col - sourceAddress._fromCol + 1); - } - else - { - xml += string.Format("<cacheField name=\"{0}\" numFmtId=\"0\">", sourceWorksheet._values.GetValue(sourceAddress._fromRow, col)); - } - //xml += "<sharedItems containsNonDate=\"0\" containsString=\"0\" containsBlank=\"1\" /> "; - xml += "<sharedItems containsBlank=\"1\" /> "; - xml += "</cacheField>"; - } - xml += "</cacheFields>"; - xml += "</pivotCacheDefinition>"; - - return xml; - } + } + return _sourceRange; } + set { + if (PivotTable.WorkSheet.Workbook != value.Worksheet.Workbook) { + throw (new ArgumentException("Range must be in the same package as the pivottable")); + } + + var sr = SourceRange; + if (value.End.Column - value.Start.Column != sr.End.Column - sr.Start.Column) { + throw (new ArgumentException( + "Can not change the number of columns(fields) in the SourceRange")); + } + + SetXmlNodeString(_sourceWorksheetPath, value.Worksheet.Name); + SetXmlNodeString(_sourceAddressPath, value.FirstAddress); + _sourceRange = value; + } + } + + /// <summary> + /// Type of source data + /// </summary> + public eSourceType CacheSource { + get { + var s = GetXmlNodeString("d:cacheSource/@type"); + if (s == "") { + return eSourceType.Worksheet; + } + return (eSourceType)Enum.Parse(typeof(eSourceType), s, true); + } + } + + private string GetStartXml(ExcelRangeBase sourceAddress) { + string xml = + "<pivotCacheDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" xmlns:r=\"http://schemas.openxmlformats.org/officeDocument/2006/relationships\" r:id=\"\" refreshOnLoad=\"1\" refreshedBy=\"SomeUser\" refreshedDate=\"40504.582403125001\" createdVersion=\"1\" refreshedVersion=\"3\" recordCount=\"5\" upgradeOnRefresh=\"1\">"; + + xml += "<cacheSource type=\"worksheet\">"; + xml += string.Format( + "<worksheetSource ref=\"{0}\" sheet=\"{1}\" /> ", + sourceAddress.Address, + sourceAddress.WorkSheet); + xml += "</cacheSource>"; + xml += string.Format( + "<cacheFields count=\"{0}\">", + sourceAddress._toCol - sourceAddress._fromCol + 1); + var sourceWorksheet = PivotTable.WorkSheet.Workbook.Worksheets[sourceAddress.WorkSheet]; + for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) { + if (sourceWorksheet == null + || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col) == null + || sourceWorksheet._values.GetValue(sourceAddress._fromRow, col).ToString().Trim() + == "") { + xml += string.Format( + "<cacheField name=\"Column{0}\" numFmtId=\"0\">", + col - sourceAddress._fromCol + 1); + } else { + xml += string.Format( + "<cacheField name=\"{0}\" numFmtId=\"0\">", + sourceWorksheet._values.GetValue(sourceAddress._fromRow, col)); + } + //xml += "<sharedItems containsNonDate=\"0\" containsString=\"0\" containsBlank=\"1\" /> "; + xml += "<sharedItems containsBlank=\"1\" /> "; + xml += "</cacheField>"; + } + xml += "</cacheFields>"; + xml += "</pivotCacheDefinition>"; + + return xml; + } }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTable.cs b/EPPlus/Table/PivotTable/ExcelPivotTable.cs index ec0990d..75c6360 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTable.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTable.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,937 +13,701 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Text; -using System.Xml; using System.Text.RegularExpressions; -using OfficeOpenXml.Table; +using System.Xml; +using OfficeOpenXml.Packaging; using OfficeOpenXml.Utils; -namespace OfficeOpenXml.Table.PivotTable -{ - /// <summary> - /// An Excel Pivottable - /// </summary> - public class ExcelPivotTable : XmlHelper - { - internal ExcelPivotTable(Packaging.ZipPackageRelationship rel, ExcelWorksheet sheet) : - base(sheet.NameSpaceManager) - { - WorkSheet = sheet; - PivotTableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); - Relationship = rel; - var pck = sheet._package.Package; - Part=pck.GetPart(PivotTableUri); +namespace OfficeOpenXml.Table.PivotTable; - PivotTableXml = new XmlDocument(); - LoadXmlSafe(PivotTableXml, Part.GetStream()); - init(); - TopNode = PivotTableXml.DocumentElement; - Address = new ExcelAddressBase(GetXmlNodeString("d:location/@ref")); +/// <summary> +/// An Excel Pivottable +/// </summary> +public class ExcelPivotTable : XmlHelper { + internal ExcelPivotTable(ZipPackageRelationship rel, ExcelWorksheet sheet) + : base(sheet.NameSpaceManager) { + WorkSheet = sheet; + PivotTableUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri); + Relationship = rel; + var pck = sheet._package.Package; + Part = pck.GetPart(PivotTableUri); - _cacheDefinition = new ExcelPivotCacheDefinition(sheet.NameSpaceManager, this); - LoadFields(); + PivotTableXml = new(); + LoadXmlSafe(PivotTableXml, Part.GetStream()); + Init(); + TopNode = PivotTableXml.DocumentElement; + Address = new(GetXmlNodeString("d:location/@ref")); - //Add row fields. - foreach (XmlElement rowElem in TopNode.SelectNodes("d:rowFields/d:field", NameSpaceManager)) - { - int x; - if (int.TryParse(rowElem.GetAttribute("x"), out x) && x >= 0) - { - RowFields.AddInternal(Fields[x]); - } - else - { - rowElem.ParentNode.RemoveChild(rowElem); - } - } + _cacheDefinition = new(sheet.NameSpaceManager, this); + LoadFields(); - ////Add column fields. - foreach (XmlElement colElem in TopNode.SelectNodes("d:colFields/d:field", NameSpaceManager)) - { - int x; - if(int.TryParse(colElem.GetAttribute("x"),out x) && x >= 0) - { - ColumnFields.AddInternal(Fields[x]); - } - else - { - colElem.ParentNode.RemoveChild(colElem); - } - } - - //Add Page elements - //int index = 0; - foreach (XmlElement pageElem in TopNode.SelectNodes("d:pageFields/d:pageField", NameSpaceManager)) - { - int fld; - if (int.TryParse(pageElem.GetAttribute("fld"), out fld) && fld >= 0) - { - var field = Fields[fld]; - field._pageFieldSettings = new ExcelPivotTablePageFieldSettings(NameSpaceManager, pageElem, field, fld); - PageFields.AddInternal(field); - } - } - - //Add data elements - //index = 0; - foreach (XmlElement dataElem in TopNode.SelectNodes("d:dataFields/d:dataField", NameSpaceManager)) - { - int fld; - if (int.TryParse(dataElem.GetAttribute("fld"), out fld) && fld >= 0) - { - var field = Fields[fld]; - var dataField = new ExcelPivotTableDataField(NameSpaceManager, dataElem, field); - DataFields.AddInternal(dataField); - } - } - } - /// <summary> - /// Add a new pivottable - /// </summary> - /// <param name="sheet">The worksheet</param> - /// <param name="address">the address of the pivottable</param> - /// <param name="sourceAddress">The address of the Source data</param> - /// <param name="name"></param> - /// <param name="tblId"></param> - internal ExcelPivotTable(ExcelWorksheet sheet, ExcelAddressBase address,ExcelRangeBase sourceAddress, string name, int tblId) : - base(sheet.NameSpaceManager) - { - WorkSheet = sheet; - Address = address; - var pck = sheet._package.Package; - - PivotTableXml = new XmlDocument(); - LoadXmlSafe(PivotTableXml, GetStartXml(name, tblId, address, sourceAddress), Encoding.UTF8); - TopNode = PivotTableXml.DocumentElement; - PivotTableUri = GetNewUri(pck, "/xl/pivotTables/pivotTable{0}.xml", tblId); - init(); - - Part = pck.CreatePart(PivotTableUri, ExcelPackage.schemaPivotTable); - PivotTableXml.Save(Part.GetStream()); - - //Worksheet-Pivottable relationship - Relationship = sheet.Part.CreateRelationship(UriHelper.ResolvePartUri(sheet.WorksheetUri, PivotTableUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotTable"); - - _cacheDefinition = new ExcelPivotCacheDefinition(sheet.NameSpaceManager, this, sourceAddress, tblId); - _cacheDefinition.Relationship=Part.CreateRelationship(UriHelper.ResolvePartUri(PivotTableUri, _cacheDefinition.CacheDefinitionUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotCacheDefinition"); - - sheet.Workbook.AddPivotTable(CacheID.ToString(), _cacheDefinition.CacheDefinitionUri); - - LoadFields(); - - using (var r=sheet.Cells[address.Address]) - { - r.Clear(); - } - } - private void init() - { - SchemaNodeOrder = new string[] { "location", "pivotFields", "rowFields", "rowItems", "colFields", "colItems", "pageFields", "pageItems", "dataFields", "dataItems", "formats", "pivotTableStyleInfo" }; - } - private void LoadFields() - { - //Fields.Clear(); - //int ix=0; - //foreach(XmlElement fieldNode in PivotXml.SelectNodes("//d:pivotFields/d:pivotField",NameSpaceManager)) - //{ - // Fields.AddInternal(new ExcelPivotTableField(NameSpaceManager, fieldNode, this, ix++)); - //} - - int index = 0; - //Add fields. - foreach (XmlElement fieldElem in TopNode.SelectNodes("d:pivotFields/d:pivotField", NameSpaceManager)) - { - var fld = new ExcelPivotTableField(NameSpaceManager, fieldElem, this, index, index++); - Fields.AddInternal(fld); - } - - //Add fields. - index = 0; - foreach (XmlElement fieldElem in _cacheDefinition.TopNode.SelectNodes("d:cacheFields/d:cacheField", NameSpaceManager)) - { - var fld = Fields[index++]; - fld.SetCacheFieldNode(fieldElem); - } - - - } - private string GetStartXml(string name, int id, ExcelAddressBase address, ExcelAddressBase sourceAddress) - { - string xml = string.Format("<pivotTableDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" name=\"{0}\" cacheId=\"{1}\" dataOnRows=\"1\" applyNumberFormats=\"0\" applyBorderFormats=\"0\" applyFontFormats=\"0\" applyPatternFormats=\"0\" applyAlignmentFormats=\"0\" applyWidthHeightFormats=\"1\" dataCaption=\"Data\" createdVersion=\"4\" showMemberPropertyTips=\"0\" useAutoFormatting=\"1\" itemPrintTitles=\"1\" indent=\"0\" compact=\"0\" compactData=\"0\" gridDropZones=\"1\">", name, id); - - xml += string.Format("<location ref=\"{0}\" firstHeaderRow=\"1\" firstDataRow=\"1\" firstDataCol=\"1\" /> ", address.FirstAddress); - xml += string.Format("<pivotFields count=\"{0}\">", sourceAddress._toCol-sourceAddress._fromCol+1); - for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) - { - xml += "<pivotField showAll=\"0\" />"; //compact=\"0\" outline=\"0\" subtotalTop=\"0\" includeNewItemsInFilter=\"1\" - } - - xml += "</pivotFields>"; - xml += "<pivotTableStyleInfo name=\"PivotStyleMedium9\" showRowHeaders=\"1\" showColHeaders=\"1\" showRowStripes=\"0\" showColStripes=\"0\" showLastColumn=\"1\" />"; - xml += "</pivotTableDefinition>"; - return xml; - } - internal Packaging.ZipPackagePart Part - { - get; - set; - } - /// <summary> - /// Provides access to the XML data representing the pivottable in the package. - /// </summary> - public XmlDocument PivotTableXml { get; private set; } - /// <summary> - /// The package internal URI to the pivottable Xml Document. - /// </summary> - public Uri PivotTableUri - { - get; - internal set; - } - internal Packaging.ZipPackageRelationship Relationship - { - get; - set; - } - //const string ID_PATH = "@id"; - //internal int Id - //{ - // get - // { - // return GetXmlNodeInt(ID_PATH); - // } - // set - // { - // SetXmlNodeString(ID_PATH, value.ToString()); - // } - //} - const string NAME_PATH = "@name"; - const string DISPLAY_NAME_PATH = "@displayName"; - /// <summary> - /// Name of the pivottable object in Excel - /// </summary> - public string Name - { - get - { - return GetXmlNodeString(NAME_PATH); - } - set - { - if (WorkSheet.Workbook.ExistsTableName(value)) - { - throw (new ArgumentException("PivotTable name is not unique")); - } - string prevName = Name; - if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) - { - int ix = WorkSheet.Tables._tableNames[prevName]; - WorkSheet.Tables._tableNames.Remove(prevName); - WorkSheet.Tables._tableNames.Add(value, ix); - } - SetXmlNodeString(NAME_PATH, value); - SetXmlNodeString(DISPLAY_NAME_PATH, cleanDisplayName(value)); - } - } - ExcelPivotCacheDefinition _cacheDefinition = null; - /// <summary> - /// Reference to the pivot table cache definition object - /// </summary> - public ExcelPivotCacheDefinition CacheDefinition - { - get - { - if (_cacheDefinition == null) - { - _cacheDefinition = new ExcelPivotCacheDefinition(NameSpaceManager, this, null, 1); - } - return _cacheDefinition; - } - } - private string cleanDisplayName(string name) - { - return Regex.Replace(name, @"[^\w\.-_]", "_"); - } - #region "Public Properties" - - /// <summary> - /// The worksheet where the pivottable is located - /// </summary> - public ExcelWorksheet WorkSheet - { - get; - set; - } - /// <summary> - /// The location of the pivot table - /// </summary> - public ExcelAddressBase Address - { - get; - internal set; - } - /// <summary> - /// If multiple datafields are displayed in the row area or the column area - /// </summary> - public bool DataOnRows - { - get - { - return GetXmlNodeBool("@dataOnRows"); - } - set - { - SetXmlNodeBool("@dataOnRows",value); - } - } - /// <summary> - /// if true apply legacy table autoformat number format properties. - /// </summary> - public bool ApplyNumberFormats - { - get - { - return GetXmlNodeBool("@applyNumberFormats"); - } - set - { - SetXmlNodeBool("@applyNumberFormats",value); - } - } - /// <summary> - /// If true apply legacy table autoformat border properties - /// </summary> - public bool ApplyBorderFormats - { - get - { - return GetXmlNodeBool("@applyBorderFormats"); - } - set - { - SetXmlNodeBool("@applyBorderFormats",value); - } - } - /// <summary> - /// If true apply legacy table autoformat font properties - /// </summary> - public bool ApplyFontFormats - { - get - { - return GetXmlNodeBool("@applyFontFormats"); - } - set - { - SetXmlNodeBool("@applyFontFormats",value); - } - } - /// <summary> - /// If true apply legacy table autoformat pattern properties - /// </summary> - public bool ApplyPatternFormats - { - get - { - return GetXmlNodeBool("@applyPatternFormats"); - } - set - { - SetXmlNodeBool("@applyPatternFormats",value); - } - } - /// <summary> - /// If true apply legacy table autoformat width/height properties. - /// </summary> - public bool ApplyWidthHeightFormats - { - get - { - return GetXmlNodeBool("@applyWidthHeightFormats"); - } - set - { - SetXmlNodeBool("@applyWidthHeightFormats",value); - } - } - /// <summary> - /// Show member property information - /// </summary> - public bool ShowMemberPropertyTips - { - get - { - return GetXmlNodeBool("@showMemberPropertyTips"); - } - set - { - SetXmlNodeBool("@showMemberPropertyTips",value); - } - } - /// <summary> - /// Show the drill indicators - /// </summary> - public bool ShowCalcMember - { - get - { - return GetXmlNodeBool("@showCalcMbrs"); - } - set - { - SetXmlNodeBool("@showCalcMbrs", value); - } - } - /// <summary> - /// If the user is prevented from drilling down on a PivotItem or aggregate value - /// </summary> - public bool EnableDrill - { - get - { - return GetXmlNodeBool("@enableDrill", true); - } - set - { - SetXmlNodeBool("@enableDrill", value); - } - } - /// <summary> - /// Show the drill down buttons - /// </summary> - public bool ShowDrill - { - get - { - return GetXmlNodeBool("@showDrill", true); - } - set - { - SetXmlNodeBool("@showDrill", value); - } - } - /// <summary> - /// If the tooltips should be displayed for PivotTable data cells. - /// </summary> - public bool ShowDataTips - { - get - { - return GetXmlNodeBool("@showDataTips", true); - } - set - { - SetXmlNodeBool("@showDataTips", value, true); - } - } - /// <summary> - /// If the row and column titles from the PivotTable should be printed. - /// </summary> - public bool FieldPrintTitles - { - get - { - return GetXmlNodeBool("@fieldPrintTitles"); - } - set - { - SetXmlNodeBool("@fieldPrintTitles", value); - } - } - /// <summary> - /// If the row and column titles from the PivotTable should be printed. - /// </summary> - public bool ItemPrintTitles - { - get - { - return GetXmlNodeBool("@itemPrintTitles"); - } - set - { - SetXmlNodeBool("@itemPrintTitles", value); - } - } - /// <summary> - /// If the grand totals should be displayed for the PivotTable columns - /// </summary> - public bool ColumGrandTotals - { - get - { - return GetXmlNodeBool("@colGrandTotals"); - } - set - { - SetXmlNodeBool("@colGrandTotals", value); - } - } - /// <summary> - /// If the grand totals should be displayed for the PivotTable rows - /// </summary> - public bool RowGrandTotals - { - get - { - return GetXmlNodeBool("@rowGrandTotals"); - } - set - { - SetXmlNodeBool("@rowGrandTotals", value); - } - } - /// <summary> - /// If the drill indicators expand collapse buttons should be printed. - /// </summary> - public bool PrintDrill - { - get - { - return GetXmlNodeBool("@printDrill"); - } - set - { - SetXmlNodeBool("@printDrill", value); - } - } - /// <summary> - /// Indicates whether to show error messages in cells. - /// </summary> - public bool ShowError - { - get - { - return GetXmlNodeBool("@showError"); - } - set - { - SetXmlNodeBool("@showError", value); - } - } - /// <summary> - /// The string to be displayed in cells that contain errors. - /// </summary> - public string ErrorCaption - { - get - { - return GetXmlNodeString("@errorCaption"); - } - set - { - SetXmlNodeString("@errorCaption", value); - } - } - /// <summary> - /// Specifies the name of the value area field header in the PivotTable. - /// This caption is shown when the PivotTable when two or more fields are in the values area. - /// </summary> - public string DataCaption - { - get - { - return GetXmlNodeString("@dataCaption"); - } - set - { - SetXmlNodeString("@dataCaption", value); - } - } - /// <summary> - /// Show field headers - /// </summary> - public bool ShowHeaders - { - get - { - return GetXmlNodeBool("@showHeaders"); - } - set - { - SetXmlNodeBool("@showHeaders", value); - } - } - /// <summary> - /// The number of page fields to display before starting another row or column - /// </summary> - public int PageWrap - { - get - { - return GetXmlNodeInt("@pageWrap"); - } - set - { - if(value<0) - { - throw new Exception("Value can't be negative"); - } - SetXmlNodeString("@pageWrap", value.ToString()); - } - } - /// <summary> - /// A boolean that indicates whether legacy auto formatting has been applied to the PivotTable view - /// </summary> - public bool UseAutoFormatting - { - get - { - return GetXmlNodeBool("@useAutoFormatting"); - } - set - { - SetXmlNodeBool("@useAutoFormatting",value); - } - } - /// <summary> - /// A boolean that indicates whether the in-grid drop zones should be displayed at runtime, and whether classic layout is applied - /// </summary> - public bool GridDropZones - { - get - { - return GetXmlNodeBool("@gridDropZones"); - } - set - { - SetXmlNodeBool("@gridDropZones",value); - } - } - /// <summary> - /// Specifies the indentation increment for compact axis and can be used to set the Report Layout to Compact Form - /// </summary> - public int Indent - { - get - { - return GetXmlNodeInt("@indent"); - } - set - { - SetXmlNodeString("@indent",value.ToString()); - } - } - /// <summary> - /// A boolean that indicates whether data fields in the PivotTable should be displayed in outline form - /// </summary> - public bool OutlineData - { - get - { - return GetXmlNodeBool("@outlineData"); - } - set - { - SetXmlNodeBool("@outlineData", value); - } - } - /// <summary> - /// a boolean that indicates whether new fields should have their outline flag set to true - /// </summary> - public bool Outline - { - get - { - return GetXmlNodeBool("@outline"); - } - set - { - SetXmlNodeBool("@outline", value); - } - } - /// <summary> - /// A boolean that indicates whether the fields of a PivotTable can have multiple filters set on them - /// </summary> - public bool MultipleFieldFilters - { - get - { - return GetXmlNodeBool("@multipleFieldFilters"); - } - set - { - SetXmlNodeBool("@multipleFieldFilters", value); - } - } - /// <summary> - /// A boolean that indicates whether new fields should have their compact flag set to true - /// </summary> - public bool Compact - { - get - { - return GetXmlNodeBool("@compact"); - } - set - { - SetXmlNodeBool("@compact",value); - } - } - /// <summary> - /// A boolean that indicates whether the field next to the data field in the PivotTable should be displayed in the same column of the spreadsheet - /// </summary> - public bool CompactData - { - get - { - return GetXmlNodeBool("@compactData"); - } - set - { - SetXmlNodeBool("@compactData",value); - } - } - /// <summary> - /// Specifies the string to be displayed for grand totals. - /// </summary> - public string GrandTotalCaption - { - get - { - return GetXmlNodeString("@grandTotalCaption"); - } - set - { - SetXmlNodeString("@grandTotalCaption", value); - } - } - /// <summary> - /// Specifies the string to be displayed in row header in compact mode. - /// </summary> - public string RowHeaderCaption - { - get - { - return GetXmlNodeString("@rowHeaderCaption"); - } - set - { - SetXmlNodeString("@rowHeaderCaption", value); - } - } - /// <summary> - /// Specifies the string to be displayed in cells with no value - /// </summary> - public string MissingCaption - { - get - { - return GetXmlNodeString("@missingCaption"); - } - set - { - SetXmlNodeString("@missingCaption", value); - } - } - const string FIRSTHEADERROW_PATH="d:location/@firstHeaderRow"; - /// <summary> - /// Specifies the first row of the PivotTable header, relative to the top left cell in the ref value - /// </summary> - public int FirstHeaderRow - { - get - { - return GetXmlNodeInt(FIRSTHEADERROW_PATH); - } - set - { - SetXmlNodeString(FIRSTHEADERROW_PATH, value.ToString()); - } - } - const string FIRSTDATAROW_PATH = "d:location/@firstDataRow"; - /// <summary> - /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value - /// </summary> - public int FirstDataRow - { - get - { - return GetXmlNodeInt(FIRSTDATAROW_PATH); - } - set - { - SetXmlNodeString(FIRSTDATAROW_PATH, value.ToString()); - } - } - const string FIRSTDATACOL_PATH = "d:location/@firstDataCol"; - /// <summary> - /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value - /// </summary> - public int FirstDataCol - { - get - { - return GetXmlNodeInt(FIRSTDATACOL_PATH); - } - set - { - SetXmlNodeString(FIRSTDATACOL_PATH, value.ToString()); - } - } - ExcelPivotTableFieldCollection _fields = null; - /// <summary> - /// The fields in the table - /// </summary> - public ExcelPivotTableFieldCollection Fields - { - get - { - if (_fields == null) - { - _fields = new ExcelPivotTableFieldCollection(this, ""); - } - return _fields; - } - } - ExcelPivotTableRowColumnFieldCollection _rowFields = null; - /// <summary> - /// Row label fields - /// </summary> - public ExcelPivotTableRowColumnFieldCollection RowFields - { - get - { - if (_rowFields == null) - { - _rowFields = new ExcelPivotTableRowColumnFieldCollection(this, "rowFields"); - } - return _rowFields; - } - } - ExcelPivotTableRowColumnFieldCollection _columnFields = null; - /// <summary> - /// Column label fields - /// </summary> - public ExcelPivotTableRowColumnFieldCollection ColumnFields - { - get - { - if (_columnFields == null) - { - _columnFields = new ExcelPivotTableRowColumnFieldCollection(this, "colFields"); - } - return _columnFields; - } - } - ExcelPivotTableDataFieldCollection _dataFields = null; - /// <summary> - /// Value fields - /// </summary> - public ExcelPivotTableDataFieldCollection DataFields - { - get - { - if (_dataFields == null) - { - _dataFields = new ExcelPivotTableDataFieldCollection(this); - } - return _dataFields; - } - } - ExcelPivotTableRowColumnFieldCollection _pageFields = null; - /// <summary> - /// Report filter fields - /// </summary> - public ExcelPivotTableRowColumnFieldCollection PageFields - { - get - { - if (_pageFields == null) - { - _pageFields = new ExcelPivotTableRowColumnFieldCollection(this, "pageFields"); - } - return _pageFields; - } - } - const string STYLENAME_PATH = "d:pivotTableStyleInfo/@name"; - /// <summary> - /// Pivot style name. Used for custom styles - /// </summary> - public string StyleName - { - get - { - return GetXmlNodeString(STYLENAME_PATH); - } - set - { - if (value.StartsWith("PivotStyle")) - { - try - { - _tableStyle = (TableStyles)Enum.Parse(typeof(TableStyles), value.Substring(10, value.Length - 10), true); - } - catch - { - _tableStyle = TableStyles.Custom; - } - } - else if (value == "None") - { - _tableStyle = TableStyles.None; - value = ""; - } - else - { - _tableStyle = TableStyles.Custom; - } - SetXmlNodeString(STYLENAME_PATH, value, true); - } - } - TableStyles _tableStyle = Table.TableStyles.Medium6; - /// <summary> - /// The table style. If this property is cusom the style from the StyleName propery is used. - /// </summary> - public TableStyles TableStyle - { - get - { - return _tableStyle; - } - set - { - _tableStyle=value; - if (value != TableStyles.Custom) - { - SetXmlNodeString(STYLENAME_PATH, "PivotStyle" + value.ToString()); - } - } - } - - #endregion - #region "Internal Properties" - internal int CacheID - { - get - { - return GetXmlNodeInt("@cacheId"); - } - set - { - SetXmlNodeString("@cacheId",value.ToString()); - } - } - - #endregion - + //Add row fields. + foreach (XmlElement rowElem in TopNode.SelectNodes("d:rowFields/d:field", NameSpaceManager)) { + int x; + if (int.TryParse(rowElem.GetAttribute("x"), out x) && x >= 0) { + RowFields.AddInternal(Fields[x]); + } else { + rowElem.ParentNode.RemoveChild(rowElem); + } } + + ////Add column fields. + foreach (XmlElement colElem in TopNode.SelectNodes("d:colFields/d:field", NameSpaceManager)) { + int x; + if (int.TryParse(colElem.GetAttribute("x"), out x) && x >= 0) { + ColumnFields.AddInternal(Fields[x]); + } else { + colElem.ParentNode.RemoveChild(colElem); + } + } + + //Add Page elements + //int index = 0; + foreach (XmlElement pageElem in TopNode.SelectNodes( + "d:pageFields/d:pageField", + NameSpaceManager)) { + int fld; + if (int.TryParse(pageElem.GetAttribute("fld"), out fld) && fld >= 0) { + var field = Fields[fld]; + field._pageFieldSettings = new(NameSpaceManager, pageElem, field, fld); + PageFields.AddInternal(field); + } + } + + //Add data elements + //index = 0; + foreach (XmlElement dataElem in TopNode.SelectNodes( + "d:dataFields/d:dataField", + NameSpaceManager)) { + int fld; + if (int.TryParse(dataElem.GetAttribute("fld"), out fld) && fld >= 0) { + var field = Fields[fld]; + var dataField = new ExcelPivotTableDataField(NameSpaceManager, dataElem, field); + DataFields.AddInternal(dataField); + } + } + } + + /// <summary> + /// Add a new pivottable + /// </summary> + /// <param name="sheet">The worksheet</param> + /// <param name="address">the address of the pivottable</param> + /// <param name="sourceAddress">The address of the Source data</param> + /// <param name="name"></param> + /// <param name="tblId"></param> + internal ExcelPivotTable( + ExcelWorksheet sheet, + ExcelAddressBase address, + ExcelRangeBase sourceAddress, + string name, + int tblId) + : base(sheet.NameSpaceManager) { + WorkSheet = sheet; + Address = address; + var pck = sheet._package.Package; + + PivotTableXml = new(); + LoadXmlSafe(PivotTableXml, GetStartXml(name, tblId, address, sourceAddress), Encoding.UTF8); + TopNode = PivotTableXml.DocumentElement; + PivotTableUri = GetNewUri(pck, "/xl/pivotTables/pivotTable{0}.xml", tblId); + Init(); + + Part = pck.CreatePart(PivotTableUri, ExcelPackage._schemaPivotTable); + PivotTableXml.Save(Part.GetStream()); + + //Worksheet-Pivottable relationship + Relationship = sheet.Part.CreateRelationship( + UriHelper.ResolvePartUri(sheet.WorksheetUri, PivotTableUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/pivotTable"); + + _cacheDefinition = new(sheet.NameSpaceManager, this, sourceAddress, tblId); + _cacheDefinition.Relationship = Part.CreateRelationship( + UriHelper.ResolvePartUri(PivotTableUri, _cacheDefinition.CacheDefinitionUri), + TargetMode.Internal, + ExcelPackage._schemaRelationships + "/pivotCacheDefinition"); + + sheet.Workbook.AddPivotTable(CacheID.ToString(), _cacheDefinition.CacheDefinitionUri); + + LoadFields(); + + using (var r = sheet.Cells[address.Address]) { + r.Clear(); + } + } + + private void Init() { + SchemaNodeOrder = new[] { + "location", + "pivotFields", + "rowFields", + "rowItems", + "colFields", + "colItems", + "pageFields", + "pageItems", + "dataFields", + "dataItems", + "formats", + "pivotTableStyleInfo", + }; + } + + private void LoadFields() { + //Fields.Clear(); + //int ix=0; + //foreach(XmlElement fieldNode in PivotXml.SelectNodes("//d:pivotFields/d:pivotField",NameSpaceManager)) + //{ + // Fields.AddInternal(new ExcelPivotTableField(NameSpaceManager, fieldNode, this, ix++)); + //} + + int index = 0; + //Add fields. + foreach (XmlElement fieldElem in TopNode.SelectNodes( + "d:pivotFields/d:pivotField", + NameSpaceManager)) { + var fld = new ExcelPivotTableField(NameSpaceManager, fieldElem, this, index, index++); + Fields.AddInternal(fld); + } + + //Add fields. + index = 0; + foreach (XmlElement fieldElem in _cacheDefinition.TopNode.SelectNodes( + "d:cacheFields/d:cacheField", + NameSpaceManager)) { + var fld = Fields[index++]; + fld.SetCacheFieldNode(fieldElem); + } + } + + private string GetStartXml( + string name, + int id, + ExcelAddressBase address, + ExcelAddressBase sourceAddress) { + string xml = string.Format( + "<pivotTableDefinition xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" name=\"{0}\" cacheId=\"{1}\" dataOnRows=\"1\" applyNumberFormats=\"0\" applyBorderFormats=\"0\" applyFontFormats=\"0\" applyPatternFormats=\"0\" applyAlignmentFormats=\"0\" applyWidthHeightFormats=\"1\" dataCaption=\"Data\" createdVersion=\"4\" showMemberPropertyTips=\"0\" useAutoFormatting=\"1\" itemPrintTitles=\"1\" indent=\"0\" compact=\"0\" compactData=\"0\" gridDropZones=\"1\">", + name, + id); + + xml += string.Format( + "<location ref=\"{0}\" firstHeaderRow=\"1\" firstDataRow=\"1\" firstDataCol=\"1\" /> ", + address.FirstAddress); + xml += string.Format( + "<pivotFields count=\"{0}\">", + sourceAddress._toCol - sourceAddress._fromCol + 1); + for (int col = sourceAddress._fromCol; col <= sourceAddress._toCol; col++) { + xml += "<pivotField showAll=\"0\" />"; //compact=\"0\" outline=\"0\" subtotalTop=\"0\" includeNewItemsInFilter=\"1\" + } + + xml += "</pivotFields>"; + xml += + "<pivotTableStyleInfo name=\"PivotStyleMedium9\" showRowHeaders=\"1\" showColHeaders=\"1\" showRowStripes=\"0\" showColStripes=\"0\" showLastColumn=\"1\" />"; + xml += "</pivotTableDefinition>"; + return xml; + } + + internal ZipPackagePart Part { get; set; } + + /// <summary> + /// Provides access to the XML data representing the pivottable in the package. + /// </summary> + public XmlDocument PivotTableXml { get; private set; } + + /// <summary> + /// The package internal URI to the pivottable Xml Document. + /// </summary> + public Uri PivotTableUri { get; internal set; } + + internal ZipPackageRelationship Relationship { get; set; } + + //const string ID_PATH = "@id"; + //internal int Id + //{ + // get + // { + // return GetXmlNodeInt(ID_PATH); + // } + // set + // { + // SetXmlNodeString(ID_PATH, value.ToString()); + // } + //} + private const string _namePath = "@name"; + private const string _displayNamePath = "@displayName"; + + /// <summary> + /// Name of the pivottable object in Excel + /// </summary> + public string Name { + get => GetXmlNodeString(_namePath); + set { + if (WorkSheet.Workbook.ExistsTableName(value)) { + throw (new ArgumentException("PivotTable name is not unique")); + } + string prevName = Name; + if (WorkSheet.Tables._tableNames.ContainsKey(prevName)) { + int ix = WorkSheet.Tables._tableNames[prevName]; + WorkSheet.Tables._tableNames.Remove(prevName); + WorkSheet.Tables._tableNames.Add(value, ix); + } + SetXmlNodeString(_namePath, value); + SetXmlNodeString(_displayNamePath, CleanDisplayName(value)); + } + } + + private ExcelPivotCacheDefinition _cacheDefinition; + + /// <summary> + /// Reference to the pivot table cache definition object + /// </summary> + public ExcelPivotCacheDefinition CacheDefinition { + get { + if (_cacheDefinition == null) { + _cacheDefinition = new(NameSpaceManager, this, null, 1); + } + return _cacheDefinition; + } + } + + private string CleanDisplayName(string name) { + return Regex.Replace(name, @"[^\w\.-_]", "_"); + } + + /// <summary> + /// The worksheet where the pivottable is located + /// </summary> + public ExcelWorksheet WorkSheet { get; set; } + + /// <summary> + /// The location of the pivot table + /// </summary> + public ExcelAddressBase Address { get; internal set; } + + /// <summary> + /// If multiple datafields are displayed in the row area or the column area + /// </summary> + public bool DataOnRows { + get => GetXmlNodeBool("@dataOnRows"); + set => SetXmlNodeBool("@dataOnRows", value); + } + + /// <summary> + /// if true apply legacy table autoformat number format properties. + /// </summary> + public bool ApplyNumberFormats { + get => GetXmlNodeBool("@applyNumberFormats"); + set => SetXmlNodeBool("@applyNumberFormats", value); + } + + /// <summary> + /// If true apply legacy table autoformat border properties + /// </summary> + public bool ApplyBorderFormats { + get => GetXmlNodeBool("@applyBorderFormats"); + set => SetXmlNodeBool("@applyBorderFormats", value); + } + + /// <summary> + /// If true apply legacy table autoformat font properties + /// </summary> + public bool ApplyFontFormats { + get => GetXmlNodeBool("@applyFontFormats"); + set => SetXmlNodeBool("@applyFontFormats", value); + } + + /// <summary> + /// If true apply legacy table autoformat pattern properties + /// </summary> + public bool ApplyPatternFormats { + get => GetXmlNodeBool("@applyPatternFormats"); + set => SetXmlNodeBool("@applyPatternFormats", value); + } + + /// <summary> + /// If true apply legacy table autoformat width/height properties. + /// </summary> + public bool ApplyWidthHeightFormats { + get => GetXmlNodeBool("@applyWidthHeightFormats"); + set => SetXmlNodeBool("@applyWidthHeightFormats", value); + } + + /// <summary> + /// Show member property information + /// </summary> + public bool ShowMemberPropertyTips { + get => GetXmlNodeBool("@showMemberPropertyTips"); + set => SetXmlNodeBool("@showMemberPropertyTips", value); + } + + /// <summary> + /// Show the drill indicators + /// </summary> + public bool ShowCalcMember { + get => GetXmlNodeBool("@showCalcMbrs"); + set => SetXmlNodeBool("@showCalcMbrs", value); + } + + /// <summary> + /// If the user is prevented from drilling down on a PivotItem or aggregate value + /// </summary> + public bool EnableDrill { + get => GetXmlNodeBool("@enableDrill", true); + set => SetXmlNodeBool("@enableDrill", value); + } + + /// <summary> + /// Show the drill down buttons + /// </summary> + public bool ShowDrill { + get => GetXmlNodeBool("@showDrill", true); + set => SetXmlNodeBool("@showDrill", value); + } + + /// <summary> + /// If the tooltips should be displayed for PivotTable data cells. + /// </summary> + public bool ShowDataTips { + get => GetXmlNodeBool("@showDataTips", true); + set => SetXmlNodeBool("@showDataTips", value, true); + } + + /// <summary> + /// If the row and column titles from the PivotTable should be printed. + /// </summary> + public bool FieldPrintTitles { + get => GetXmlNodeBool("@fieldPrintTitles"); + set => SetXmlNodeBool("@fieldPrintTitles", value); + } + + /// <summary> + /// If the row and column titles from the PivotTable should be printed. + /// </summary> + public bool ItemPrintTitles { + get => GetXmlNodeBool("@itemPrintTitles"); + set => SetXmlNodeBool("@itemPrintTitles", value); + } + + /// <summary> + /// If the grand totals should be displayed for the PivotTable columns + /// </summary> + public bool ColumGrandTotals { + get => GetXmlNodeBool("@colGrandTotals"); + set => SetXmlNodeBool("@colGrandTotals", value); + } + + /// <summary> + /// If the grand totals should be displayed for the PivotTable rows + /// </summary> + public bool RowGrandTotals { + get => GetXmlNodeBool("@rowGrandTotals"); + set => SetXmlNodeBool("@rowGrandTotals", value); + } + + /// <summary> + /// If the drill indicators expand collapse buttons should be printed. + /// </summary> + public bool PrintDrill { + get => GetXmlNodeBool("@printDrill"); + set => SetXmlNodeBool("@printDrill", value); + } + + /// <summary> + /// Indicates whether to show error messages in cells. + /// </summary> + public bool ShowError { + get => GetXmlNodeBool("@showError"); + set => SetXmlNodeBool("@showError", value); + } + + /// <summary> + /// The string to be displayed in cells that contain errors. + /// </summary> + public string ErrorCaption { + get => GetXmlNodeString("@errorCaption"); + set => SetXmlNodeString("@errorCaption", value); + } + + /// <summary> + /// Specifies the name of the value area field header in the PivotTable. + /// This caption is shown when the PivotTable when two or more fields are in the values area. + /// </summary> + public string DataCaption { + get => GetXmlNodeString("@dataCaption"); + set => SetXmlNodeString("@dataCaption", value); + } + + /// <summary> + /// Show field headers + /// </summary> + public bool ShowHeaders { + get => GetXmlNodeBool("@showHeaders"); + set => SetXmlNodeBool("@showHeaders", value); + } + + /// <summary> + /// The number of page fields to display before starting another row or column + /// </summary> + public int PageWrap { + get => GetXmlNodeInt("@pageWrap"); + set { + if (value < 0) { + throw new("Value can't be negative"); + } + SetXmlNodeString("@pageWrap", value.ToString()); + } + } + + /// <summary> + /// A boolean that indicates whether legacy auto formatting has been applied to the PivotTable view + /// </summary> + public bool UseAutoFormatting { + get => GetXmlNodeBool("@useAutoFormatting"); + set => SetXmlNodeBool("@useAutoFormatting", value); + } + + /// <summary> + /// A boolean that indicates whether the in-grid drop zones should be displayed at runtime, and whether classic layout is applied + /// </summary> + public bool GridDropZones { + get => GetXmlNodeBool("@gridDropZones"); + set => SetXmlNodeBool("@gridDropZones", value); + } + + /// <summary> + /// Specifies the indentation increment for compact axis and can be used to set the Report Layout to Compact Form + /// </summary> + public int Indent { + get => GetXmlNodeInt("@indent"); + set => SetXmlNodeString("@indent", value.ToString()); + } + + /// <summary> + /// A boolean that indicates whether data fields in the PivotTable should be displayed in outline form + /// </summary> + public bool OutlineData { + get => GetXmlNodeBool("@outlineData"); + set => SetXmlNodeBool("@outlineData", value); + } + + /// <summary> + /// a boolean that indicates whether new fields should have their outline flag set to true + /// </summary> + public bool Outline { + get => GetXmlNodeBool("@outline"); + set => SetXmlNodeBool("@outline", value); + } + + /// <summary> + /// A boolean that indicates whether the fields of a PivotTable can have multiple filters set on them + /// </summary> + public bool MultipleFieldFilters { + get => GetXmlNodeBool("@multipleFieldFilters"); + set => SetXmlNodeBool("@multipleFieldFilters", value); + } + + /// <summary> + /// A boolean that indicates whether new fields should have their compact flag set to true + /// </summary> + public bool Compact { + get => GetXmlNodeBool("@compact"); + set => SetXmlNodeBool("@compact", value); + } + + /// <summary> + /// A boolean that indicates whether the field next to the data field in the PivotTable should be displayed in the same column of the spreadsheet + /// </summary> + public bool CompactData { + get => GetXmlNodeBool("@compactData"); + set => SetXmlNodeBool("@compactData", value); + } + + /// <summary> + /// Specifies the string to be displayed for grand totals. + /// </summary> + public string GrandTotalCaption { + get => GetXmlNodeString("@grandTotalCaption"); + set => SetXmlNodeString("@grandTotalCaption", value); + } + + /// <summary> + /// Specifies the string to be displayed in row header in compact mode. + /// </summary> + public string RowHeaderCaption { + get => GetXmlNodeString("@rowHeaderCaption"); + set => SetXmlNodeString("@rowHeaderCaption", value); + } + + /// <summary> + /// Specifies the string to be displayed in cells with no value + /// </summary> + public string MissingCaption { + get => GetXmlNodeString("@missingCaption"); + set => SetXmlNodeString("@missingCaption", value); + } + + private const string _firstheaderrowPath = "d:location/@firstHeaderRow"; + + /// <summary> + /// Specifies the first row of the PivotTable header, relative to the top left cell in the ref value + /// </summary> + public int FirstHeaderRow { + get => GetXmlNodeInt(_firstheaderrowPath); + set => SetXmlNodeString(_firstheaderrowPath, value.ToString()); + } + + private const string _firstdatarowPath = "d:location/@firstDataRow"; + + /// <summary> + /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value + /// </summary> + public int FirstDataRow { + get => GetXmlNodeInt(_firstdatarowPath); + set => SetXmlNodeString(_firstdatarowPath, value.ToString()); + } + + private const string _firstdatacolPath = "d:location/@firstDataCol"; + + /// <summary> + /// Specifies the first column of the PivotTable data, relative to the top left cell in the ref value + /// </summary> + public int FirstDataCol { + get => GetXmlNodeInt(_firstdatacolPath); + set => SetXmlNodeString(_firstdatacolPath, value.ToString()); + } + + private ExcelPivotTableFieldCollection _fields; + + /// <summary> + /// The fields in the table + /// </summary> + public ExcelPivotTableFieldCollection Fields { + get { + if (_fields == null) { + _fields = new(this, ""); + } + return _fields; + } + } + + private ExcelPivotTableRowColumnFieldCollection _rowFields; + + /// <summary> + /// Row label fields + /// </summary> + public ExcelPivotTableRowColumnFieldCollection RowFields { + get { + if (_rowFields == null) { + _rowFields = new(this, "rowFields"); + } + return _rowFields; + } + } + + private ExcelPivotTableRowColumnFieldCollection _columnFields; + + /// <summary> + /// Column label fields + /// </summary> + public ExcelPivotTableRowColumnFieldCollection ColumnFields { + get { + if (_columnFields == null) { + _columnFields = new(this, "colFields"); + } + return _columnFields; + } + } + + private ExcelPivotTableDataFieldCollection _dataFields; + + /// <summary> + /// Value fields + /// </summary> + public ExcelPivotTableDataFieldCollection DataFields { + get { + if (_dataFields == null) { + _dataFields = new(this); + } + return _dataFields; + } + } + + private ExcelPivotTableRowColumnFieldCollection _pageFields; + + /// <summary> + /// Report filter fields + /// </summary> + public ExcelPivotTableRowColumnFieldCollection PageFields { + get { + if (_pageFields == null) { + _pageFields = new(this, "pageFields"); + } + return _pageFields; + } + } + + private const string _stylenamePath = "d:pivotTableStyleInfo/@name"; + + /// <summary> + /// Pivot style name. Used for custom styles + /// </summary> + public string StyleName { + get => GetXmlNodeString(_stylenamePath); + set { + if (value.StartsWith("PivotStyle")) { + try { + _tableStyle = (TableStyles) + Enum.Parse(typeof(TableStyles), value.Substring(10, value.Length - 10), true); + } catch { + _tableStyle = TableStyles.Custom; + } + } else if (value == "None") { + _tableStyle = TableStyles.None; + value = ""; + } else { + _tableStyle = TableStyles.Custom; + } + SetXmlNodeString(_stylenamePath, value, true); + } + } + + private TableStyles _tableStyle = TableStyles.Medium6; + + /// <summary> + /// The table style. If this property is cusom the style from the StyleName propery is used. + /// </summary> + public TableStyles TableStyle { + get => _tableStyle; + set { + _tableStyle = value; + if (value != TableStyles.Custom) { + SetXmlNodeString(_stylenamePath, "PivotStyle" + value); + } + } + } + + internal int CacheID { + get => GetXmlNodeInt("@cacheId"); + set => SetXmlNodeString("@cacheId", value.ToString()); + } }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs b/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs index 7bf4750..bde8c36 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTableCollection.cs
@@ -13,153 +13,127 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; -using System.Text; -using System.Xml; -namespace OfficeOpenXml.Table.PivotTable -{ - /// <summary> - /// A collection of pivottable objects - /// </summary> - public class ExcelPivotTableCollection : IEnumerable<ExcelPivotTable> - { - List<ExcelPivotTable> _pivotTables = new List<ExcelPivotTable>(); - internal Dictionary<string, int> _pivotTableNames = new Dictionary<string, int>(); - ExcelWorksheet _ws; - internal ExcelPivotTableCollection(ExcelWorksheet ws) - { - var pck = ws._package.Package; - _ws = ws; - foreach(var rel in ws.Part.GetRelationships()) - { - if (rel.RelationshipType == ExcelPackage.schemaRelationships + "/pivotTable") - { - var tbl = new ExcelPivotTable(rel, ws); - _pivotTableNames.Add(tbl.Name, _pivotTables.Count); - _pivotTables.Add(tbl); - } - } - } - private ExcelPivotTable Add(ExcelPivotTable tbl) - { - _pivotTables.Add(tbl); - _pivotTableNames.Add(tbl.Name, _pivotTables.Count - 1); - if (tbl.CacheID >= _ws.Workbook._nextPivotTableID) - { - _ws.Workbook._nextPivotTableID = tbl.CacheID + 1; - } - return tbl; - } +namespace OfficeOpenXml.Table.PivotTable; - /// <summary> - /// Create a pivottable on the supplied range - /// </summary> - /// <param name="Range">The range address including header and total row</param> - /// <param name="Source">The Source data range address</param> - /// <param name="Name">The name of the table. Must be unique </param> - /// <returns>The pivottable object</returns> - public ExcelPivotTable Add(ExcelAddressBase Range, ExcelRangeBase Source, string Name) - { - if (string.IsNullOrEmpty(Name)) - { - Name = GetNewTableName(); - } - if (Range.WorkSheet != _ws.Name) - { - throw(new Exception("The Range must be in the current worksheet")); - } - else if (_ws.Workbook.ExistsTableName(Name)) - { - throw (new ArgumentException("Tablename is not unique")); - } - foreach (var t in _pivotTables) - { - if (t.Address.Collide(Range) != ExcelAddressBase.eAddressCollition.No) - { - throw (new ArgumentException(string.Format("Table range collides with table {0}", t.Name))); - } - } - return Add(new ExcelPivotTable(_ws, Range, Source, Name, _ws.Workbook._nextPivotTableID++)); - } +/// <summary> +/// A collection of pivottable objects +/// </summary> +public class ExcelPivotTableCollection : IEnumerable<ExcelPivotTable> { + private List<ExcelPivotTable> _pivotTables = new(); + internal Dictionary<string, int> _pivotTableNames = new(); + private ExcelWorksheet _ws; - internal string GetNewTableName() - { - string name = "Pivottable1"; - int i = 2; - while (_ws.Workbook.ExistsPivotTableName(name)) - { - name = string.Format("Pivottable{0}", i++); - } - return name; - } - public int Count - { - get - { - return _pivotTables.Count; - } - } - /// <summary> - /// The pivottable Index. Base 0. - /// </summary> - /// <param name="Index"></param> - /// <returns></returns> - public ExcelPivotTable this[int Index] - { - get - { - if (Index < 0 || Index >= _pivotTables.Count) - { - throw (new ArgumentOutOfRangeException("PivotTable index out of range")); - } - return _pivotTables[Index]; - } - } - /// <summary> - /// Pivottabes accesed by name - /// </summary> - /// <param name="Name">The name of the pivottable</param> - /// <returns>The Pivotable. Null if the no match is found</returns> - public ExcelPivotTable this[string Name] - { - get - { - if (_pivotTableNames.ContainsKey(Name)) - { - return _pivotTables[_pivotTableNames[Name]]; - } - else - { - return null; - } - } - } - public IEnumerator<ExcelPivotTable> GetEnumerator() - { - return _pivotTables.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _pivotTables.GetEnumerator(); - } + internal ExcelPivotTableCollection(ExcelWorksheet ws) { + var pck = ws._package.Package; + _ws = ws; + foreach (var rel in ws.Part.GetRelationships()) { + if (rel.RelationshipType == ExcelPackage._schemaRelationships + "/pivotTable") { + var tbl = new ExcelPivotTable(rel, ws); + _pivotTableNames.Add(tbl.Name, _pivotTables.Count); + _pivotTables.Add(tbl); + } } + } + + private ExcelPivotTable Add(ExcelPivotTable tbl) { + _pivotTables.Add(tbl); + _pivotTableNames.Add(tbl.Name, _pivotTables.Count - 1); + if (tbl.CacheID >= _ws.Workbook._nextPivotTableID) { + _ws.Workbook._nextPivotTableID = tbl.CacheID + 1; + } + return tbl; + } + + /// <summary> + /// Create a pivottable on the supplied range + /// </summary> + /// <param name="range">The range address including header and total row</param> + /// <param name="source">The Source data range address</param> + /// <param name="name">The name of the table. Must be unique </param> + /// <returns>The pivottable object</returns> + public ExcelPivotTable Add(ExcelAddressBase range, ExcelRangeBase source, string name) { + if (string.IsNullOrEmpty(name)) { + name = GetNewTableName(); + } + if (range.WorkSheet != _ws.Name) { + throw (new("The Range must be in the current worksheet")); + } + if (_ws.Workbook.ExistsTableName(name)) { + throw (new ArgumentException("Tablename is not unique")); + } + foreach (var t in _pivotTables) { + if (t.Address.Collide(range) != ExcelAddressBase.eAddressCollition.No) { + throw (new ArgumentException(string.Format("Table range collides with table {0}", t.Name))); + } + } + return Add(new(_ws, range, source, name, _ws.Workbook._nextPivotTableID++)); + } + + internal string GetNewTableName() { + string name = "Pivottable1"; + int i = 2; + while (_ws.Workbook.ExistsPivotTableName(name)) { + name = string.Format("Pivottable{0}", i++); + } + return name; + } + + public int Count => _pivotTables.Count; + + /// <summary> + /// The pivottable Index. Base 0. + /// </summary> + /// <param name="index"></param> + /// <returns></returns> + public ExcelPivotTable this[int index] { + get { + if (index < 0 || index >= _pivotTables.Count) { + throw (new ArgumentOutOfRangeException("PivotTable index out of range")); + } + return _pivotTables[index]; + } + } + + /// <summary> + /// Pivottabes accesed by name + /// </summary> + /// <param name="name">The name of the pivottable</param> + /// <returns>The Pivotable. Null if the no match is found</returns> + public ExcelPivotTable this[string name] { + get { + if (_pivotTableNames.ContainsKey(name)) { + return _pivotTables[_pivotTableNames[name]]; + } + return null; + } + } + + public IEnumerator<ExcelPivotTable> GetEnumerator() { + return _pivotTables.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _pivotTables.GetEnumerator(); + } }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs b/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs index 97a7dc4..bfe8c52 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTableDataField.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,221 +13,178 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; using System.Globalization; -using System.Text; using System.Xml; using OfficeOpenXml.Style.XmlAccess; -namespace OfficeOpenXml.Table.PivotTable -{ - /// <summary> - /// A pivo table data field - /// </summary> - public class ExcelPivotTableDataField : XmlHelper - { - internal ExcelPivotTableDataField(XmlNamespaceManager ns, XmlNode topNode,ExcelPivotTableField field) : - base(ns, topNode) - { - if (topNode.Attributes.Count == 0) - { - Index = field.Index; - BaseField = 0; - BaseItem = 0; - } - - Field = field; - } - /// <summary> - /// The field - /// </summary> - public ExcelPivotTableField Field - { - get; - private set; - } - /// <summary> - /// The index of the datafield - /// </summary> - public int Index - { - get - { - return GetXmlNodeInt("@fld"); - } - internal set - { - SetXmlNodeString("@fld",value.ToString()); - } - } - /// <summary> - /// The name of the datafield - /// </summary> - public string Name - { - get - { - return GetXmlNodeString("@name"); - } - set - { - if (Field._table.DataFields.ExistsDfName(value, this)) - { - throw (new InvalidOperationException("Duplicate datafield name")); - } - SetXmlNodeString("@name", value); - } - } - /// <summary> - /// Field index. Reference to the field collection - /// </summary> - public int BaseField - { - get - { - return GetXmlNodeInt("@baseField"); - } - set - { - SetXmlNodeString("@baseField", value.ToString()); - } - } - /// <summary> - /// Specifies the index to the base item when the ShowDataAs calculation is in use - /// </summary> - public int BaseItem - { - get - { - return GetXmlNodeInt("@baseItem"); - } - set - { - SetXmlNodeString("@baseItem", value.ToString()); - } - } - /// <summary> - /// Number format id. - /// </summary> - internal int NumFmtId - { - get - { - return GetXmlNodeInt("@numFmtId"); - } - set - { - SetXmlNodeString("@numFmtId", value.ToString()); - } - } - /// <summary> - /// Number format for the data column - /// </summary> - public string Format - { - get - { - foreach (var nf in Field._table.WorkSheet.Workbook.Styles.NumberFormats) - { - if (nf.NumFmtId == NumFmtId) - { - return nf.Format; - } - } - return Field._table.WorkSheet.Workbook.Styles.NumberFormats[0].Format; - } - set - { - var styles = Field._table.WorkSheet.Workbook.Styles; +namespace OfficeOpenXml.Table.PivotTable; - ExcelNumberFormatXml nf = null; - if (!styles.NumberFormats.FindByID(value, ref nf)) - { - nf = new ExcelNumberFormatXml(NameSpaceManager) { Format = value, NumFmtId = styles.NumberFormats.NextId++ }; - styles.NumberFormats.Add(value, nf); - } - NumFmtId = nf.NumFmtId; - } - } - /// <summary> - /// Type of aggregate function - /// </summary> - public DataFieldFunctions Function - { - get - { - string s=GetXmlNodeString("@subtotal"); - if(s=="") - { - return DataFieldFunctions.None; - } - else - { - return (DataFieldFunctions)Enum.Parse(typeof(DataFieldFunctions), s, true); - } - } - set - { - string v; - switch(value) - { - case DataFieldFunctions.None: - DeleteNode("@subtotal"); - return; - case DataFieldFunctions.CountNums: - v="CountNums"; - break; - case DataFieldFunctions.StdDev: - v="stdDev"; - break; - case DataFieldFunctions.StdDevP: - v="stdDevP"; - break; - default: - v=value.ToString().ToLower(CultureInfo.InvariantCulture); - break; - } - SetXmlNodeString("@subtotal", v); - } - } - /////Since we have no items, Excel will crash when we use showDataAs options that require baseItem's - //public eShowDataAs ShowDataAs - //{ - // get - // { - // string s = GetXmlNodeString("@showDataAs"); - // if (s == "") - // { - // return eShowDataAs.Normal; - // } - // else - // { - // return (eShowDataAs)Enum.Parse(typeof(eShowDataAs), s, true); - // } - // } - // set - // { - // string v = value.ToString(); - // v = v.Substring(0, 1).ToLower() + v.Substring(1); - // SetXmlNodeString("@showDataAs", v); - // } - //} +/// <summary> +/// A pivo table data field +/// </summary> +public class ExcelPivotTableDataField : XmlHelper { + internal ExcelPivotTableDataField( + XmlNamespaceManager ns, + XmlNode topNode, + ExcelPivotTableField field) + : base(ns, topNode) { + if (topNode.Attributes.Count == 0) { + Index = field.Index; + BaseField = 0; + BaseItem = 0; } + + Field = field; + } + + /// <summary> + /// The field + /// </summary> + public ExcelPivotTableField Field { get; private set; } + + /// <summary> + /// The index of the datafield + /// </summary> + public int Index { + get => GetXmlNodeInt("@fld"); + internal set => SetXmlNodeString("@fld", value.ToString()); + } + + /// <summary> + /// The name of the datafield + /// </summary> + public string Name { + get => GetXmlNodeString("@name"); + set { + if (Field._table.DataFields.ExistsDfName(value, this)) { + throw (new InvalidOperationException("Duplicate datafield name")); + } + SetXmlNodeString("@name", value); + } + } + + /// <summary> + /// Field index. Reference to the field collection + /// </summary> + public int BaseField { + get => GetXmlNodeInt("@baseField"); + set => SetXmlNodeString("@baseField", value.ToString()); + } + + /// <summary> + /// Specifies the index to the base item when the ShowDataAs calculation is in use + /// </summary> + public int BaseItem { + get => GetXmlNodeInt("@baseItem"); + set => SetXmlNodeString("@baseItem", value.ToString()); + } + + /// <summary> + /// Number format id. + /// </summary> + internal int NumFmtId { + get => GetXmlNodeInt("@numFmtId"); + set => SetXmlNodeString("@numFmtId", value.ToString()); + } + + /// <summary> + /// Number format for the data column + /// </summary> + public string Format { + get { + foreach (var nf in Field._table.WorkSheet.Workbook.Styles.NumberFormats) { + if (nf.NumFmtId == NumFmtId) { + return nf.Format; + } + } + return Field._table.WorkSheet.Workbook.Styles.NumberFormats[0].Format; + } + set { + var styles = Field._table.WorkSheet.Workbook.Styles; + + ExcelNumberFormatXml nf = null; + if (!styles.NumberFormats.FindById(value, ref nf)) { + nf = new(NameSpaceManager) { + Format = value, + NumFmtId = styles.NumberFormats.NextId++, + }; + styles.NumberFormats.Add(value, nf); + } + NumFmtId = nf.NumFmtId; + } + } + + /// <summary> + /// Type of aggregate function + /// </summary> + public DataFieldFunctions Function { + get { + string s = GetXmlNodeString("@subtotal"); + if (s == "") { + return DataFieldFunctions.None; + } + return (DataFieldFunctions)Enum.Parse(typeof(DataFieldFunctions), s, true); + } + set { + string v; + switch (value) { + case DataFieldFunctions.None: + DeleteNode("@subtotal"); + return; + case DataFieldFunctions.CountNums: + v = "CountNums"; + break; + case DataFieldFunctions.StdDev: + v = "stdDev"; + break; + case DataFieldFunctions.StdDevP: + v = "stdDevP"; + break; + default: + v = value.ToString().ToLower(CultureInfo.InvariantCulture); + break; + } + SetXmlNodeString("@subtotal", v); + } + } + /////Since we have no items, Excel will crash when we use showDataAs options that require baseItem's + //public eShowDataAs ShowDataAs + //{ + // get + // { + // string s = GetXmlNodeString("@showDataAs"); + // if (s == "") + // { + // return eShowDataAs.Normal; + // } + // else + // { + // return (eShowDataAs)Enum.Parse(typeof(eShowDataAs), s, true); + // } + // } + // set + // { + // string v = value.ToString(); + // v = v.Substring(0, 1).ToLower() + v.Substring(1); + // SetXmlNodeString("@showDataAs", v); + // } + //} }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableField.cs b/EPPlus/Table/PivotTable/ExcelPivotTableField.cs index 2e897ab..654ab71 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTableField.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTableField.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,1064 +13,1000 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; using System.Collections.Generic; -using System.Text; -using System.Xml; using System.Globalization; +using System.Xml; -namespace OfficeOpenXml.Table.PivotTable -{ - - /// <summary> - /// Defines the axis for a PivotTable - /// </summary> - public enum ePivotFieldAxis - { - /// <summary> - /// None - /// </summary> - None=-1, - /// <summary> - /// Column axis - /// </summary> - Column, - /// <summary> - /// Page axis (Include Count Filter) - /// - /// </summary> - Page, - /// <summary> - /// Row axis - /// </summary> - Row, - /// <summary> - /// Values axis - /// </summary> - Values +namespace OfficeOpenXml.Table.PivotTable; + +/// <summary> +/// Defines the axis for a PivotTable +/// </summary> +public enum ePivotFieldAxis { + /// <summary> + /// None + /// </summary> + None = -1, + + /// <summary> + /// Column axis + /// </summary> + Column, + + /// <summary> + /// Page axis (Include Count Filter) + /// + /// </summary> + Page, + + /// <summary> + /// Row axis + /// </summary> + Row, + + /// <summary> + /// Values axis + /// </summary> + Values, +} + +/// <summary> +/// Build-in table row functions +/// </summary> +public enum DataFieldFunctions { + Average, + Count, + CountNums, + Max, + Min, + Product, + None, + StdDev, + StdDevP, + Sum, + Var, + VarP, +} + +/// <summary> +/// Defines the data formats for a field in the PivotTable +/// </summary> +public enum eShowDataAs { + /// <summary> + /// Indicates the field is shown as the "difference from" a value. + /// </summary> + Difference, + + /// <summary> + /// Indicates the field is shown as the "index. + /// </summary> + Index, + + /// <summary> + /// Indicates that the field is shown as its normal datatype. + /// </summary> + Normal, + + /// <summary> + /// /Indicates the field is show as the "percentage of" a value + /// </summary> + Percent, + + /// <summary> + /// Indicates the field is shown as the "percentage difference from" a value. + /// </summary> + PercentDiff, + + /// <summary> + /// Indicates the field is shown as the percentage of column. + /// </summary> + PercentOfCol, + + /// <summary> + /// Indicates the field is shown as the percentage of row + /// </summary> + PercentOfRow, + + /// <summary> + /// Indicates the field is shown as percentage of total. + /// </summary> + PercentOfTotal, + + /// <summary> + /// Indicates the field is shown as running total in the table. + /// </summary> + RunTotal, +} + +/// <summary> +/// Built-in subtotal functions +/// </summary> +[Flags] +public enum eSubTotalFunctions { + None = 1, + Count = 2, + CountA = 4, + Avg = 8, + Default = 16, + Min = 32, + Max = 64, + Product = 128, + StdDev = 256, + StdDevP = 512, + Sum = 1024, + Var = 2048, + VarP = 4096, +} + +/// <summary> +/// Data grouping +/// </summary> +[Flags] +public enum eDateGroupBy { + Years = 1, + Quarters = 2, + Months = 4, + Days = 8, + Hours = 16, + Minutes = 32, + Seconds = 64, +} + +/// <summary> +/// Sorting +/// </summary> +public enum eSortType { + None, + Ascending, + Descending, +} + +/// <summary> +/// A pivot table field. +/// </summary> +public class ExcelPivotTableField : XmlHelper { + internal ExcelPivotTable _table; + + internal ExcelPivotTableField( + XmlNamespaceManager ns, + XmlNode topNode, + ExcelPivotTable table, + int index, + int baseIndex) + : base(ns, topNode) { + Index = index; + BaseIndex = baseIndex; + _table = table; + } + + public int Index { get; set; } + + internal int BaseIndex { get; set; } + + /// <summary> + /// Name of the field + /// </summary> + public string Name { + get { + string v = GetXmlNodeString("@name"); + if (v == "") { + return _cacheFieldHelper.GetXmlNodeString("@name"); + } + return v; } - /// <summary> - /// Build-in table row functions - /// </summary> - public enum DataFieldFunctions - { - Average, - Count, - CountNums, - Max, - Min, - Product, - None, - StdDev, - StdDevP, - Sum, - Var, - VarP + set => SetXmlNodeString("@name", value); + } + + /// <summary> + /// Compact mode + /// </summary> + public bool Compact { + get => GetXmlNodeBool("@compact"); + set => SetXmlNodeBool("@compact", value); + } + + /// <summary> + /// A boolean that indicates whether the items in this field should be shown in Outline form + /// </summary> + public bool Outline { + get => GetXmlNodeBool("@outline"); + set => SetXmlNodeBool("@outline", value); + } + + /// <summary> + /// The custom text that is displayed for the subtotals label + /// </summary> + public bool SubtotalTop { + get => GetXmlNodeBool("@subtotalTop"); + set => SetXmlNodeBool("@subtotalTop", value); + } + + /// <summary> + /// A boolean that indicates whether to show all items for this field + /// </summary> + public bool ShowAll { + get => GetXmlNodeBool("@showAll"); + set => SetXmlNodeBool("@showAll", value); + } + + /// <summary> + /// The type of sort that is applied to this field + /// </summary> + public eSortType Sort { + get { + string v = GetXmlNodeString("@sortType"); + return v == "" ? eSortType.None : (eSortType)Enum.Parse(typeof(eSortType), v, true); } - /// <summary> - /// Defines the data formats for a field in the PivotTable - /// </summary> - public enum eShowDataAs - { - /// <summary> - /// Indicates the field is shown as the "difference from" a value. - /// </summary> - Difference, - /// <summary> - /// Indicates the field is shown as the "index. - /// </summary> - Index, - /// <summary> - /// Indicates that the field is shown as its normal datatype. - /// </summary> - Normal, - /// <summary> - /// /Indicates the field is show as the "percentage of" a value - /// </summary> - Percent, - /// <summary> - /// Indicates the field is shown as the "percentage difference from" a value. - /// </summary> - PercentDiff, - /// <summary> - /// Indicates the field is shown as the percentage of column. - /// </summary> - PercentOfCol, - /// <summary> - /// Indicates the field is shown as the percentage of row - /// </summary> - PercentOfRow, - /// <summary> - /// Indicates the field is shown as percentage of total. - /// </summary> - PercentOfTotal, - /// <summary> - /// Indicates the field is shown as running total in the table. - /// </summary> - RunTotal, + set { + if (value == eSortType.None) { + DeleteNode("@sortType"); + } else { + SetXmlNodeString("@sortType", value.ToString().ToLower(CultureInfo.InvariantCulture)); + } } - /// <summary> - /// Built-in subtotal functions - /// </summary> - [Flags] - public enum eSubTotalFunctions - { - None=1, - Count=2, - CountA=4, - Avg=8, - Default=16, - Min=32, - Max=64, - Product=128, - StdDev=256, - StdDevP=512, - Sum=1024, - Var=2048, - VarP=4096 - } - /// <summary> - /// Data grouping - /// </summary> - [Flags] - public enum eDateGroupBy - { - Years = 1, - Quarters = 2, - Months = 4, - Days = 8, - Hours = 16, - Minutes = 32, - Seconds = 64 + } + + /// <summary> + /// A boolean that indicates whether manual filter is in inclusive mode + /// </summary> + public bool IncludeNewItemsInFilter { + get => GetXmlNodeBool("@includeNewItemsInFilter"); + set => SetXmlNodeBool("@includeNewItemsInFilter", value); + } + + /// <summary> + /// Enumeration of the different subtotal operations that can be applied to page, row or column fields + /// </summary> + public eSubTotalFunctions SubTotalFunctions { + get { + eSubTotalFunctions ret = 0; + XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager); + if (nl.Count == 0) { + return eSubTotalFunctions.None; + } + foreach (XmlAttribute item in nl) { + try { + ret |= (eSubTotalFunctions)Enum.Parse(typeof(eSubTotalFunctions), item.Value, true); + } catch (ArgumentException ex) { + throw new ArgumentException( + "Unable to parse value of " + + item.Value + + " to a valid pivot table subtotal function", + ex); + } + } + return ret; } - /// <summary> - /// Sorting - /// </summary> - public enum eSortType - { - None, - Ascending, - Descending + set { + if ((value & eSubTotalFunctions.None) == eSubTotalFunctions.None + && (value != eSubTotalFunctions.None)) { + throw (new ArgumentException("Value None can not be combined with other values.")); + } + if ((value & eSubTotalFunctions.Default) == eSubTotalFunctions.Default + && (value != eSubTotalFunctions.Default)) { + throw (new ArgumentException("Value Default can not be combined with other values.")); + } + + // remove old attribute + XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager); + if (nl.Count > 0) { + foreach (XmlAttribute item in nl) { + DeleteNode("@" + item.Value + "Subtotal"); + item.OwnerElement.ParentNode.RemoveChild(item.OwnerElement); + } + } + + if (value == eSubTotalFunctions.None) { + // for no subtotals, set defaultSubtotal to off + SetXmlNodeBool("@defaultSubtotal", false); + TopNode.InnerXml = ""; + } else { + string innerXml = ""; + int count = 0; + foreach (eSubTotalFunctions e in Enum.GetValues(typeof(eSubTotalFunctions))) { + if ((value & e) == e) { + var newTotalType = e.ToString(); + var totalType = + char.ToLower(newTotalType[0], CultureInfo.InvariantCulture) + + newTotalType.Substring(1); + // add new attribute + SetXmlNodeBool("@" + totalType + "Subtotal", true); + innerXml += "<item t=\"" + totalType + "\" />"; + count++; + } + } + TopNode.InnerXml = string.Format("<items count=\"{0}\">{1}</items>", count, innerXml); + } } - /// <summary> - /// A pivot table field. - /// </summary> - public class ExcelPivotTableField : XmlHelper - { - internal ExcelPivotTable _table; - internal ExcelPivotTableField(XmlNamespaceManager ns, XmlNode topNode,ExcelPivotTable table, int index, int baseIndex) : - base(ns, topNode) - { - Index = index; - BaseIndex = baseIndex; - _table = table; - } - public int Index - { - get; - set; - } - internal int BaseIndex - { - get; - set; - } - /// <summary> - /// Name of the field - /// </summary> - public string Name - { - get - { - string v = GetXmlNodeString("@name"); - if (v == "") - { - return _cacheFieldHelper.GetXmlNodeString("@name"); - } - else - { - return v; - } - } - set - { - SetXmlNodeString("@name", value); - } - } - /// <summary> - /// Compact mode - /// </summary> - public bool Compact - { - get - { - return GetXmlNodeBool("@compact"); - } - set - { - SetXmlNodeBool("@compact",value); - } - } - /// <summary> - /// A boolean that indicates whether the items in this field should be shown in Outline form - /// </summary> - public bool Outline - { - get - { - return GetXmlNodeBool("@outline"); - } - set - { - SetXmlNodeBool("@outline",value); - } - } - /// <summary> - /// The custom text that is displayed for the subtotals label - /// </summary> - public bool SubtotalTop - { - get - { - return GetXmlNodeBool("@subtotalTop"); - } - set - { - SetXmlNodeBool("@subtotalTop",value); - } - } - /// <summary> - /// A boolean that indicates whether to show all items for this field - /// </summary> - public bool ShowAll - { - get - { - return GetXmlNodeBool("@showAll"); - } - set - { - SetXmlNodeBool("@showAll",value); - } - } - /// <summary> - /// The type of sort that is applied to this field - /// </summary> - public eSortType Sort - { - get - { - string v = GetXmlNodeString("@sortType"); - return v == "" ? eSortType.None : (eSortType)Enum.Parse(typeof(eSortType), v, true); - } - set - { - if (value == eSortType.None) - { - DeleteNode("@sortType"); - } - else - { - SetXmlNodeString("@sortType", value.ToString().ToLower(CultureInfo.InvariantCulture)); - } - } - } - /// <summary> - /// A boolean that indicates whether manual filter is in inclusive mode - /// </summary> - public bool IncludeNewItemsInFilter - { - get - { - return GetXmlNodeBool("@includeNewItemsInFilter"); - } - set - { - SetXmlNodeBool("@includeNewItemsInFilter",value); - } - } - /// <summary> - /// Enumeration of the different subtotal operations that can be applied to page, row or column fields - /// </summary> - public eSubTotalFunctions SubTotalFunctions - { - get - { - eSubTotalFunctions ret = 0; - XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager); - if (nl.Count == 0) return eSubTotalFunctions.None; - foreach (XmlAttribute item in nl) - { - try - { - ret |= (eSubTotalFunctions)Enum.Parse(typeof(eSubTotalFunctions), item.Value, true); - } - catch (ArgumentException ex) - { - throw new ArgumentException("Unable to parse value of " + item.Value + " to a valid pivot table subtotal function", ex); - } - } - return ret; - } - set - { - if ((value & eSubTotalFunctions.None) == eSubTotalFunctions.None && (value != eSubTotalFunctions.None)) - { - throw (new ArgumentException("Value None can not be combined with other values.")); - } - if ((value & eSubTotalFunctions.Default) == eSubTotalFunctions.Default && (value != eSubTotalFunctions.Default)) - { - throw (new ArgumentException("Value Default can not be combined with other values.")); - } + } + /// <summary> + /// Type of axis + /// </summary> + public ePivotFieldAxis Axis { + get { + switch (GetXmlNodeString("@axis")) { + case "axisRow": + return ePivotFieldAxis.Row; + case "axisCol": + return ePivotFieldAxis.Column; + case "axisPage": + return ePivotFieldAxis.Page; + case "axisValues": + return ePivotFieldAxis.Values; + default: + return ePivotFieldAxis.None; + } + } + internal set { + switch (value) { + case ePivotFieldAxis.Row: + SetXmlNodeString("@axis", "axisRow"); + break; + case ePivotFieldAxis.Column: + SetXmlNodeString("@axis", "axisCol"); + break; + case ePivotFieldAxis.Values: + SetXmlNodeString("@axis", "axisValues"); + break; + case ePivotFieldAxis.Page: + SetXmlNodeString("@axis", "axisPage"); + break; + default: + DeleteNode("@axis"); + break; + } + } + } - // remove old attribute - XmlNodeList nl = TopNode.SelectNodes("d:items/d:item/@t", NameSpaceManager); - if (nl.Count > 0) - { - foreach (XmlAttribute item in nl) - { - DeleteNode("@" + item.Value + "Subtotal"); - item.OwnerElement.ParentNode.RemoveChild(item.OwnerElement); - } - } - - - if (value==eSubTotalFunctions.None) - { - // for no subtotals, set defaultSubtotal to off - SetXmlNodeBool("@defaultSubtotal", false); - TopNode.InnerXml = ""; - } - else - { - string innerXml = ""; - int count = 0; - foreach (eSubTotalFunctions e in Enum.GetValues(typeof(eSubTotalFunctions))) - { - if ((value & e) == e) - { - var newTotalType = e.ToString(); - var totalType = char.ToLower(newTotalType[0], CultureInfo.InvariantCulture) + newTotalType.Substring(1); - // add new attribute - SetXmlNodeBool("@" + totalType + "Subtotal", true); - innerXml += "<item t=\"" + totalType + "\" />"; - count++; - } - } - TopNode.InnerXml = string.Format("<items count=\"{0}\">{1}</items>", count, innerXml); - } - } - } - /// <summary> - /// Type of axis - /// </summary> - public ePivotFieldAxis Axis - { - get - { - switch(GetXmlNodeString("@axis")) - { - case "axisRow": - return ePivotFieldAxis.Row; - case "axisCol": - return ePivotFieldAxis.Column; - case "axisPage": - return ePivotFieldAxis.Page; - case "axisValues": - return ePivotFieldAxis.Values; - default: - return ePivotFieldAxis.None; - } - } - internal set - { - switch (value) - { - case ePivotFieldAxis.Row: - SetXmlNodeString("@axis","axisRow"); - break; - case ePivotFieldAxis.Column: - SetXmlNodeString("@axis","axisCol"); - break; - case ePivotFieldAxis.Values: - SetXmlNodeString("@axis", "axisValues"); - break; - case ePivotFieldAxis.Page: - SetXmlNodeString("@axis", "axisPage"); - break; - default: - DeleteNode("@axis"); - break; - } - } - } - /// <summary> - /// If the field is a row field - /// </summary> - public bool IsRowField - { - get - { - return (TopNode.SelectSingleNode(string.Format("../../d:rowFields/d:field[@x={0}]", Index), NameSpaceManager) != null); - } - internal set - { - if (value) - { - var rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager); - if (rowsNode == null) - { - _table.CreateNode("d:rowFields"); - } - rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager); - - AppendField(rowsNode, Index, "field", "x"); - if (BaseIndex == Index) - { - TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>"; - } - else - { - TopNode.InnerXml = "<items count=\"0\"></items>"; - } - } - else - { - XmlElement node = TopNode.SelectSingleNode(string.Format("../../d:rowFields/d:field[@x={0}]", Index), NameSpaceManager) as XmlElement; - if (node != null) - { - node.ParentNode.RemoveChild(node); - } - } - } + /// <summary> + /// If the field is a row field + /// </summary> + public bool IsRowField { + get => + (TopNode.SelectSingleNode( + string.Format("../../d:rowFields/d:field[@x={0}]", Index), + NameSpaceManager) != null); + internal set { + if (value) { + var rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager); + if (rowsNode == null) { + _table.CreateNode("d:rowFields"); } - /// <summary> - /// If the field is a column field - /// </summary> - public bool IsColumnField - { - get - { - return (TopNode.SelectSingleNode(string.Format("../../d:colFields/d:field[@x={0}]", Index), NameSpaceManager) != null); - } - internal set - { - if (value) - { - var columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager); - if (columnsNode == null) - { - _table.CreateNode("d:colFields"); - } - columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager); + rowsNode = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager); - AppendField(columnsNode, Index, "field", "x"); - if (BaseIndex == Index) - { - TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>"; - } - else - { - TopNode.InnerXml = "<items count=\"0\"></items>"; - } - } - else - { - XmlElement node = TopNode.SelectSingleNode(string.Format("../../d:colFields/d:field[@x={0}]", Index), NameSpaceManager) as XmlElement; - if (node != null) - { - node.ParentNode.RemoveChild(node); - } - } - } + AppendField(rowsNode, Index, "field", "x"); + if (BaseIndex == Index) { + TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>"; + } else { + TopNode.InnerXml = "<items count=\"0\"></items>"; } - /// <summary> - /// If the field is a datafield - /// </summary> - public bool IsDataField - { - get - { - return GetXmlNodeBool("@dataField", false); - } + } else { + XmlElement node = + TopNode.SelectSingleNode( + string.Format("../../d:rowFields/d:field[@x={0}]", Index), + NameSpaceManager) as XmlElement; + if (node != null) { + node.ParentNode.RemoveChild(node); } - /// <summary> - /// If the field is a page field. - /// </summary> - public bool IsPageField - { - get - { - return (Axis==ePivotFieldAxis.Page); - } - internal set - { - if (value) - { - var dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager); - if (dataFieldsNode == null) - { - _table.CreateNode("d:pageFields"); - dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager); - } + } + } + } - TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>"; - - XmlElement node = AppendField(dataFieldsNode, Index, "pageField", "fld"); - _pageFieldSettings = new ExcelPivotTablePageFieldSettings(NameSpaceManager, node, this, Index); - } - else - { - _pageFieldSettings = null; - XmlElement node = TopNode.SelectSingleNode(string.Format("../../d:pageFields/d:pageField[@fld={0}]", Index), NameSpaceManager) as XmlElement; - if (node != null) - { - node.ParentNode.RemoveChild(node); - } - } - } + /// <summary> + /// If the field is a column field + /// </summary> + public bool IsColumnField { + get => + (TopNode.SelectSingleNode( + string.Format("../../d:colFields/d:field[@x={0}]", Index), + NameSpaceManager) != null); + internal set { + if (value) { + var columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager); + if (columnsNode == null) { + _table.CreateNode("d:colFields"); } - //public ExcelPivotGrouping DateGrouping + columnsNode = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager); + + AppendField(columnsNode, Index, "field", "x"); + if (BaseIndex == Index) { + TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>"; + } else { + TopNode.InnerXml = "<items count=\"0\"></items>"; + } + } else { + XmlElement node = + TopNode.SelectSingleNode( + string.Format("../../d:colFields/d:field[@x={0}]", Index), + NameSpaceManager) as XmlElement; + if (node != null) { + node.ParentNode.RemoveChild(node); + } + } + } + } + + /// <summary> + /// If the field is a datafield + /// </summary> + public bool IsDataField => GetXmlNodeBool("@dataField", false); + + /// <summary> + /// If the field is a page field. + /// </summary> + public bool IsPageField { + get => (Axis == ePivotFieldAxis.Page); + internal set { + if (value) { + var dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager); + if (dataFieldsNode == null) { + _table.CreateNode("d:pageFields"); + dataFieldsNode = TopNode.SelectSingleNode("../../d:pageFields", NameSpaceManager); + } + + TopNode.InnerXml = "<items count=\"1\"><item t=\"default\" /></items>"; + + XmlElement node = AppendField(dataFieldsNode, Index, "pageField", "fld"); + _pageFieldSettings = new(NameSpaceManager, node, this, Index); + } else { + _pageFieldSettings = null; + XmlElement node = + TopNode.SelectSingleNode( + string.Format("../../d:pageFields/d:pageField[@fld={0}]", Index), + NameSpaceManager) as XmlElement; + if (node != null) { + node.ParentNode.RemoveChild(node); + } + } + } + } + + //public ExcelPivotGrouping DateGrouping + //{ + + //} + internal ExcelPivotTablePageFieldSettings _pageFieldSettings; + + public ExcelPivotTablePageFieldSettings PageFieldSettings => _pageFieldSettings; + + internal eDateGroupBy DateGrouping { get; set; } + + private ExcelPivotTableFieldGroup _grouping; + + /// <summary> + /// Grouping settings. + /// Null if the field has no grouping otherwise ExcelPivotTableFieldNumericGroup or ExcelPivotTableFieldNumericGroup. + /// </summary> + public ExcelPivotTableFieldGroup Grouping => _grouping; + + internal XmlElement AppendField( + XmlNode rowsNode, + int index, + string fieldNodeText, + string indexAttrText) { + XmlElement prevField = null, + newElement; + foreach (XmlElement field in rowsNode.ChildNodes) { + string x = field.GetAttribute(indexAttrText); + int fieldIndex; + if (int.TryParse(x, out fieldIndex)) { + if (fieldIndex + == index) //Row already exists + { + return field; + } + //else if (fieldIndex > index) //{ + // newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage.schemaMain); + // newElement.SetAttribute(indexAttrText, index.ToString()); + // rowsNode.InsertAfter(newElement, field); + //} + } + prevField = field; + } + newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage._schemaMain); + newElement.SetAttribute(indexAttrText, index.ToString()); + rowsNode.InsertAfter(newElement, prevField); + + return newElement; + } + + internal XmlHelperInstance _cacheFieldHelper; + + internal void SetCacheFieldNode(XmlNode cacheField) { + _cacheFieldHelper = new(NameSpaceManager, cacheField); + var groupNode = cacheField.SelectSingleNode("d:fieldGroup", NameSpaceManager); + if (groupNode != null) { + var groupBy = groupNode.SelectSingleNode("d:rangePr/@groupBy", NameSpaceManager); + if (groupBy == null) { + _grouping = new ExcelPivotTableFieldNumericGroup(NameSpaceManager, cacheField); + } else { + DateGrouping = (eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), groupBy.Value, true); + _grouping = new ExcelPivotTableFieldDateGroup(NameSpaceManager, groupNode); + } + } + } + + internal ExcelPivotTableFieldDateGroup SetDateGroup( + eDateGroupBy groupBy, + DateTime startDate, + DateTime endDate, + int interval) { + ExcelPivotTableFieldDateGroup group; + group = new(NameSpaceManager, _cacheFieldHelper.TopNode); + _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsDate", true); + _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNonDate", false); + _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false); + + group.TopNode.InnerXml += string.Format( + "<fieldGroup base=\"{0}\"><rangePr groupBy=\"{1}\" /><groupItems /></fieldGroup>", + BaseIndex, + groupBy.ToString().ToLower(CultureInfo.InvariantCulture)); + + if (startDate.Year < 1900) { + _cacheFieldHelper.SetXmlNodeString( + "d:fieldGroup/d:rangePr/@startDate", + "1900-01-01T00:00:00"); + } else { + _cacheFieldHelper.SetXmlNodeString( + "d:fieldGroup/d:rangePr/@startDate", + startDate.ToString("s", CultureInfo.InvariantCulture)); + _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoStart", "0"); + } + + if (endDate == DateTime.MaxValue) { + _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@endDate", "9999-12-31T00:00:00"); + } else { + _cacheFieldHelper.SetXmlNodeString( + "d:fieldGroup/d:rangePr/@endDate", + endDate.ToString("s", CultureInfo.InvariantCulture)); + _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoEnd", "0"); + } + + int items = AddDateGroupItems(group, groupBy, startDate, endDate, interval); + AddFieldItems(items); + + _grouping = group; + return group; + } + + internal ExcelPivotTableFieldNumericGroup SetNumericGroup( + double start, + double end, + double interval) { + ExcelPivotTableFieldNumericGroup group; + group = new(NameSpaceManager, _cacheFieldHelper.TopNode); + _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNumber", true); + _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsInteger", true); + _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false); + _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsString", false); + + group.TopNode.InnerXml += string.Format( + "<fieldGroup base=\"{0}\"><rangePr autoStart=\"0\" autoEnd=\"0\" startNum=\"{1}\" endNum=\"{2}\" groupInterval=\"{3}\"/><groupItems /></fieldGroup>", + BaseIndex, + start.ToString(CultureInfo.InvariantCulture), + end.ToString(CultureInfo.InvariantCulture), + interval.ToString(CultureInfo.InvariantCulture)); + int items = AddNumericGroupItems(group, start, end, interval); + AddFieldItems(items); + + _grouping = group; + return group; + } + + private int AddNumericGroupItems( + ExcelPivotTableFieldNumericGroup group, + double start, + double end, + double interval) { + if (interval < 0) { + throw (new("The interval must be a positiv")); + } + if (start > end) { + throw (new("Then End number must be larger than the Start number")); + } + + XmlElement groupItems = + group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager) + as XmlElement; + int items = 2; + //First date + double index = start; + double nextIndex = start + interval; + AddGroupItem(groupItems, "<" + start.ToString(CultureInfo.InvariantCulture)); + + while (index < end) { + AddGroupItem( + groupItems, + string.Format( + "{0}-{1}", + index.ToString(CultureInfo.InvariantCulture), + nextIndex.ToString(CultureInfo.InvariantCulture))); + index = nextIndex; + nextIndex += interval; + items++; + } + AddGroupItem(groupItems, ">" + nextIndex.ToString(CultureInfo.InvariantCulture)); + return items; + } + + private void AddFieldItems(int items) { + XmlElement prevNode = null; + XmlElement itemsNode = TopNode.SelectSingleNode("d:items", NameSpaceManager) as XmlElement; + for (int x = 0; x < items; x++) { + var itemNode = itemsNode.OwnerDocument.CreateElement("item", ExcelPackage._schemaMain); + itemNode.SetAttribute("x", x.ToString()); + if (prevNode == null) { + itemsNode.PrependChild(itemNode); + } else { + itemsNode.InsertAfter(itemNode, prevNode); + } + prevNode = itemNode; + } + itemsNode.SetAttribute("count", (items + 1).ToString()); + } + + private int AddDateGroupItems( + ExcelPivotTableFieldGroup group, + eDateGroupBy groupBy, + DateTime startDate, + DateTime endDate, + int interval) { + XmlElement groupItems = + group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager) + as XmlElement; + int items = 2; + //First date + AddGroupItem( + groupItems, + "<" + startDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10)); + + switch (groupBy) { + case eDateGroupBy.Seconds: + case eDateGroupBy.Minutes: + AddTimeSerie(60, groupItems); + items += 60; + break; + case eDateGroupBy.Hours: + AddTimeSerie(24, groupItems); + items += 24; + break; + case eDateGroupBy.Days: + if (interval == 1) { + DateTime dt = new DateTime(2008, 1, 1); //pick a year with 366 days + while (dt.Year == 2008) { + AddGroupItem(groupItems, dt.ToString("dd-MMM")); + dt = dt.AddDays(1); + } + items += 366; + } else { + DateTime dt = startDate; + items = 0; + while (dt < endDate) { + AddGroupItem(groupItems, dt.ToString("dd-MMM")); + dt = dt.AddDays(interval); + items++; + } + } + break; + case eDateGroupBy.Months: + AddGroupItem(groupItems, "jan"); + AddGroupItem(groupItems, "feb"); + AddGroupItem(groupItems, "mar"); + AddGroupItem(groupItems, "apr"); + AddGroupItem(groupItems, "may"); + AddGroupItem(groupItems, "jun"); + AddGroupItem(groupItems, "jul"); + AddGroupItem(groupItems, "aug"); + AddGroupItem(groupItems, "sep"); + AddGroupItem(groupItems, "oct"); + AddGroupItem(groupItems, "nov"); + AddGroupItem(groupItems, "dec"); + items += 12; + break; + case eDateGroupBy.Quarters: + AddGroupItem(groupItems, "Qtr1"); + AddGroupItem(groupItems, "Qtr2"); + AddGroupItem(groupItems, "Qtr3"); + AddGroupItem(groupItems, "Qtr4"); + items += 4; + break; + case eDateGroupBy.Years: + if (startDate.Year >= 1900 && endDate != DateTime.MaxValue) { + for (int year = startDate.Year; year <= endDate.Year; year++) { + AddGroupItem(groupItems, year.ToString()); + } + items += endDate.Year - startDate.Year + 1; + } + break; + default: + throw (new("unsupported grouping")); + } + + //Lastdate + AddGroupItem( + groupItems, + ">" + endDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10)); + return items; + } + + private void AddTimeSerie(int count, XmlElement groupItems) { + for (int i = 0; i < count; i++) { + AddGroupItem(groupItems, string.Format("{0:00}", i)); + } + } + + private void AddGroupItem(XmlElement groupItems, string value) { + var s = groupItems.OwnerDocument.CreateElement("s", ExcelPackage._schemaMain); + s.SetAttribute("v", value); + groupItems.AppendChild(s); + } + + internal ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> _items; + + /// <summary> + /// Pivottable field Items. Used for grouping. + /// </summary> + public ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> Items { + get { + if (_items == null) { + _items = new(_table); + foreach (XmlNode node in TopNode.SelectNodes("d:items//d:item", NameSpaceManager)) { + var item = new ExcelPivotTableFieldItem(NameSpaceManager, node, this); + if (item.T == "") { + _items.AddInternal(item); + } + } + //if (_grouping is ExcelPivotTableFieldDateGroup) + //{ + // ExcelPivotTableFieldDateGroup dtgrp = ((ExcelPivotTableFieldDateGroup)_grouping); + + // ExcelPivotTableFieldItem minItem=null, maxItem=null; + // foreach (var item in _items) + // { + // if (item.X == 0) + // { + // minItem = item; + // } + // else if (maxItem == null || maxItem.X < item.X) + // { + // maxItem = item; + // } + // } + // if (dtgrp.AutoStart) + // { + // _items._list.Remove(minItem); + // } + // if (dtgrp.AutoEnd) + // { + // _items._list.Remove(maxItem); + // } //} - internal ExcelPivotTablePageFieldSettings _pageFieldSettings = null; - public ExcelPivotTablePageFieldSettings PageFieldSettings - { - get - { - return _pageFieldSettings; - } - } - internal eDateGroupBy DateGrouping - { - get; - set; - } - ExcelPivotTableFieldGroup _grouping=null; - /// <summary> - /// Grouping settings. - /// Null if the field has no grouping otherwise ExcelPivotTableFieldNumericGroup or ExcelPivotTableFieldNumericGroup. - /// </summary> - public ExcelPivotTableFieldGroup Grouping - { - get - { - return _grouping; - } - } - #region Private & internal Methods - internal XmlElement AppendField(XmlNode rowsNode, int index, string fieldNodeText, string indexAttrText) - { - XmlElement prevField = null, newElement; - foreach (XmlElement field in rowsNode.ChildNodes) - { - string x = field.GetAttribute(indexAttrText); - int fieldIndex; - if(int.TryParse(x, out fieldIndex)) - { - if (fieldIndex == index) //Row already exists - { - return field; - } - //else if (fieldIndex > index) - //{ - // newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage.schemaMain); - // newElement.SetAttribute(indexAttrText, index.ToString()); - // rowsNode.InsertAfter(newElement, field); - //} - } - prevField=field; - } - newElement = rowsNode.OwnerDocument.CreateElement(fieldNodeText, ExcelPackage.schemaMain); - newElement.SetAttribute(indexAttrText, index.ToString()); - rowsNode.InsertAfter(newElement, prevField); - - return newElement; - } - internal XmlHelperInstance _cacheFieldHelper = null; - internal void SetCacheFieldNode(XmlNode cacheField) - { - _cacheFieldHelper = new XmlHelperInstance(NameSpaceManager, cacheField); - var groupNode = cacheField.SelectSingleNode("d:fieldGroup", NameSpaceManager); - if (groupNode!=null) - { - var groupBy = groupNode.SelectSingleNode("d:rangePr/@groupBy", NameSpaceManager); - if (groupBy==null) - { - _grouping = new ExcelPivotTableFieldNumericGroup(NameSpaceManager, cacheField); - } - else - { - DateGrouping=(eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), groupBy.Value, true); - _grouping = new ExcelPivotTableFieldDateGroup(NameSpaceManager, groupNode); - } - } - } - #endregion - #region Grouping - internal ExcelPivotTableFieldDateGroup SetDateGroup(eDateGroupBy GroupBy, DateTime StartDate, DateTime EndDate, int interval) - { - ExcelPivotTableFieldDateGroup group; - group = new ExcelPivotTableFieldDateGroup(NameSpaceManager, _cacheFieldHelper.TopNode); - _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsDate", true); - _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNonDate", false); - _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false); - - group.TopNode.InnerXml += string.Format("<fieldGroup base=\"{0}\"><rangePr groupBy=\"{1}\" /><groupItems /></fieldGroup>", BaseIndex, GroupBy.ToString().ToLower(CultureInfo.InvariantCulture)); - - if (StartDate.Year < 1900) - { - _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@startDate", "1900-01-01T00:00:00"); - } - else - { - _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@startDate", StartDate.ToString("s", CultureInfo.InvariantCulture)); - _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoStart", "0"); - } - - if (EndDate==DateTime.MaxValue) - { - _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@endDate", "9999-12-31T00:00:00"); - } - else - { - _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@endDate", EndDate.ToString("s", CultureInfo.InvariantCulture)); - _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@autoEnd", "0"); - } - - int items = AddDateGroupItems(group, GroupBy, StartDate, EndDate, interval); - AddFieldItems(items); - - _grouping = group; - return group; - } - internal ExcelPivotTableFieldNumericGroup SetNumericGroup(double start, double end, double interval) - { - ExcelPivotTableFieldNumericGroup group; - group = new ExcelPivotTableFieldNumericGroup(NameSpaceManager, _cacheFieldHelper.TopNode); - _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsNumber", true); - _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsInteger", true); - _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsSemiMixedTypes", false); - _cacheFieldHelper.SetXmlNodeBool("d:sharedItems/@containsString", false); - - group.TopNode.InnerXml += string.Format("<fieldGroup base=\"{0}\"><rangePr autoStart=\"0\" autoEnd=\"0\" startNum=\"{1}\" endNum=\"{2}\" groupInterval=\"{3}\"/><groupItems /></fieldGroup>", BaseIndex, start.ToString(CultureInfo.InvariantCulture), end.ToString(CultureInfo.InvariantCulture), interval.ToString(CultureInfo.InvariantCulture)); - int items = AddNumericGroupItems(group, start, end, interval); - AddFieldItems(items); - - _grouping = group; - return group; - } - - private int AddNumericGroupItems(ExcelPivotTableFieldNumericGroup group, double start, double end, double interval) - { - if (interval < 0) - { - throw (new Exception("The interval must be a positiv")); - } - if (start > end) - { - throw(new Exception("Then End number must be larger than the Start number")); - } - - XmlElement groupItems = group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager) as XmlElement; - int items = 2; - //First date - double index=start; - double nextIndex=start+interval; - AddGroupItem(groupItems, "<" + start.ToString(CultureInfo.InvariantCulture)); - - while (index < end) - { - AddGroupItem(groupItems, string.Format("{0}-{1}", index.ToString(CultureInfo.InvariantCulture), nextIndex.ToString(CultureInfo.InvariantCulture))); - index=nextIndex; - nextIndex+=interval; - items++; - } - AddGroupItem(groupItems, ">" + nextIndex.ToString(CultureInfo.InvariantCulture)); - return items; - } - - private void AddFieldItems(int items) - { - XmlElement prevNode = null; - XmlElement itemsNode = TopNode.SelectSingleNode("d:items", NameSpaceManager) as XmlElement; - for (int x = 0; x < items; x++) - { - var itemNode = itemsNode.OwnerDocument.CreateElement("item", ExcelPackage.schemaMain); - itemNode.SetAttribute("x", x.ToString()); - if (prevNode == null) - { - itemsNode.PrependChild(itemNode); - } - else - { - itemsNode.InsertAfter(itemNode, prevNode); - } - prevNode = itemNode; - } - itemsNode.SetAttribute("count", (items + 1).ToString()); - } - - private int AddDateGroupItems(ExcelPivotTableFieldGroup group, eDateGroupBy GroupBy, DateTime StartDate, DateTime EndDate, int interval) - { - XmlElement groupItems = group.TopNode.SelectSingleNode("d:fieldGroup/d:groupItems", group.NameSpaceManager) as XmlElement; - int items = 2; - //First date - AddGroupItem(groupItems, "<" + StartDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10)); - - switch (GroupBy) - { - case eDateGroupBy.Seconds: - case eDateGroupBy.Minutes: - AddTimeSerie(60, groupItems); - items += 60; - break; - case eDateGroupBy.Hours: - AddTimeSerie(24, groupItems); - items += 24; - break; - case eDateGroupBy.Days: - if (interval == 1) - { - DateTime dt = new DateTime(2008, 1, 1); //pick a year with 366 days - while (dt.Year == 2008) - { - AddGroupItem(groupItems, dt.ToString("dd-MMM")); - dt = dt.AddDays(1); - } - items += 366; - } - else - { - DateTime dt = StartDate; - items = 0; - while (dt < EndDate) - { - AddGroupItem(groupItems, dt.ToString("dd-MMM")); - dt = dt.AddDays(interval); - items++; - } - } - break; - case eDateGroupBy.Months: - AddGroupItem(groupItems, "jan"); - AddGroupItem(groupItems, "feb"); - AddGroupItem(groupItems, "mar"); - AddGroupItem(groupItems, "apr"); - AddGroupItem(groupItems, "may"); - AddGroupItem(groupItems, "jun"); - AddGroupItem(groupItems, "jul"); - AddGroupItem(groupItems, "aug"); - AddGroupItem(groupItems, "sep"); - AddGroupItem(groupItems, "oct"); - AddGroupItem(groupItems, "nov"); - AddGroupItem(groupItems, "dec"); - items += 12; - break; - case eDateGroupBy.Quarters: - AddGroupItem(groupItems, "Qtr1"); - AddGroupItem(groupItems, "Qtr2"); - AddGroupItem(groupItems, "Qtr3"); - AddGroupItem(groupItems, "Qtr4"); - items += 4; - break; - case eDateGroupBy.Years: - if(StartDate.Year>=1900 && EndDate!=DateTime.MaxValue) - { - for (int year = StartDate.Year; year <= EndDate.Year; year++) - { - AddGroupItem(groupItems, year.ToString()); - } - items += EndDate.Year - StartDate.Year+1; - } - break; - default: - throw (new Exception("unsupported grouping")); - } - - //Lastdate - AddGroupItem(groupItems, ">" + EndDate.ToString("s", CultureInfo.InvariantCulture).Substring(0, 10)); - return items; - } - - private void AddTimeSerie(int count, XmlElement groupItems) - { - for (int i = 0; i < count; i++) - { - AddGroupItem(groupItems, string.Format("{0:00}", i)); - } - } - - private void AddGroupItem(XmlElement groupItems, string value) - { - var s = groupItems.OwnerDocument.CreateElement("s", ExcelPackage.schemaMain); - s.SetAttribute("v", value); - groupItems.AppendChild(s); - } - #endregion - internal ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> _items=null; - /// <summary> - /// Pivottable field Items. Used for grouping. - /// </summary> - public ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem> Items - { - get - { - if (_items == null) - { - _items = new ExcelPivotTableFieldCollectionBase<ExcelPivotTableFieldItem>(_table); - foreach (XmlNode node in TopNode.SelectNodes("d:items//d:item", NameSpaceManager)) - { - var item = new ExcelPivotTableFieldItem(NameSpaceManager, node,this); - if (item.T == "") - { - _items.AddInternal(item); - } - } - //if (_grouping is ExcelPivotTableFieldDateGroup) - //{ - // ExcelPivotTableFieldDateGroup dtgrp = ((ExcelPivotTableFieldDateGroup)_grouping); - - // ExcelPivotTableFieldItem minItem=null, maxItem=null; - // foreach (var item in _items) - // { - // if (item.X == 0) - // { - // minItem = item; - // } - // else if (maxItem == null || maxItem.X < item.X) - // { - // maxItem = item; - // } - // } - // if (dtgrp.AutoStart) - // { - // _items._list.Remove(minItem); - // } - // if (dtgrp.AutoEnd) - // { - // _items._list.Remove(maxItem); - // } - - //} - } - return _items; - } - } - /// <summary> - /// Add numberic grouping to the field - /// </summary> - /// <param name="Start">Start value</param> - /// <param name="End">End value</param> - /// <param name="Interval">Interval</param> - public void AddNumericGrouping(double Start, double End, double Interval) - { - ValidateGrouping(); - SetNumericGroup(Start, End, Interval); - } - /// <summary> - /// Add a date grouping on this field. - /// </summary> - /// <param name="groupBy">Group by</param> - public void AddDateGrouping(eDateGroupBy groupBy) - { - AddDateGrouping(groupBy, DateTime.MinValue, DateTime.MaxValue,1); - } - /// <summary> - /// Add a date grouping on this field. - /// </summary> - /// <param name="groupBy">Group by</param> - /// <param name="startDate">Fixed start date. Use DateTime.MinValue for auto</param> - /// <param name="endDate">Fixed end date. Use DateTime.MaxValue for auto</param> - public void AddDateGrouping(eDateGroupBy groupBy, DateTime startDate, DateTime endDate) - { - AddDateGrouping(groupBy, startDate, endDate, 1); - } - /// <summary> - /// Add a date grouping on this field. - /// </summary> - /// <param name="days">Number of days when grouping on days</param> - /// <param name="startDate">Fixed start date. Use DateTime.MinValue for auto</param> - /// <param name="endDate">Fixed end date. Use DateTime.MaxValue for auto</param> - public void AddDateGrouping(int days, DateTime startDate, DateTime endDate) - { - AddDateGrouping(eDateGroupBy.Days, startDate, endDate, days); - } - private void AddDateGrouping(eDateGroupBy groupBy, DateTime startDate, DateTime endDate, int groupInterval) - { - if (groupInterval < 1 || groupInterval >= Int16.MaxValue) - { - throw (new ArgumentOutOfRangeException("Group interval is out of range")); - } - if (groupInterval > 1 && groupBy != eDateGroupBy.Days) - { - throw (new ArgumentException("Group interval is can only be used when groupBy is Days")); - } - ValidateGrouping(); - - bool firstField = true; - List<ExcelPivotTableField> fields=new List<ExcelPivotTableField>(); - //Seconds - if ((groupBy & eDateGroupBy.Seconds) == eDateGroupBy.Seconds) - { - fields.Add(AddField(eDateGroupBy.Seconds, startDate, endDate, ref firstField)); - } - //Minutes - if ((groupBy & eDateGroupBy.Minutes) == eDateGroupBy.Minutes) - { - fields.Add(AddField(eDateGroupBy.Minutes, startDate, endDate, ref firstField)); - } - //Hours - if ((groupBy & eDateGroupBy.Hours) == eDateGroupBy.Hours) - { - fields.Add(AddField(eDateGroupBy.Hours, startDate, endDate, ref firstField)); - } - //Days - if ((groupBy & eDateGroupBy.Days) == eDateGroupBy.Days) - { - fields.Add(AddField(eDateGroupBy.Days, startDate, endDate, ref firstField, groupInterval)); - } - //Month - if ((groupBy & eDateGroupBy.Months) == eDateGroupBy.Months) - { - fields.Add(AddField(eDateGroupBy.Months, startDate, endDate, ref firstField)); - } - //Quarters - if ((groupBy & eDateGroupBy.Quarters) == eDateGroupBy.Quarters) - { - fields.Add(AddField(eDateGroupBy.Quarters, startDate, endDate, ref firstField)); - } - //Years - if ((groupBy & eDateGroupBy.Years) == eDateGroupBy.Years) - { - fields.Add(AddField(eDateGroupBy.Years, startDate, endDate, ref firstField)); - } - - if (fields.Count > 1) _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/@par", (_table.Fields.Count - 1).ToString()); - if (groupInterval != 1) - { - _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/d:rangePr/@groupInterval", groupInterval.ToString()); - } - else - { - _cacheFieldHelper.DeleteNode("d:fieldGroup/d:rangePr/@groupInterval"); - } - _items = null; - } - - private void ValidateGrouping() - { - if (!(IsColumnField || IsRowField)) - { - throw (new Exception("Field must be a row or column field")); - } - foreach (var field in _table.Fields) - { - if (field.Grouping != null) - { - throw (new Exception("Grouping already exists")); - } - } - } - private ExcelPivotTableField AddField(eDateGroupBy groupBy, DateTime startDate, DateTime endDate, ref bool firstField) - { - return AddField(groupBy, startDate, endDate, ref firstField,1); - } - private ExcelPivotTableField AddField(eDateGroupBy groupBy, DateTime startDate, DateTime endDate, ref bool firstField, int interval) - { - if (firstField == false) - { - //Pivot field - var topNode = _table.PivotTableXml.SelectSingleNode("//d:pivotFields", _table.NameSpaceManager); - var fieldNode = _table.PivotTableXml.CreateElement("pivotField", ExcelPackage.schemaMain); - fieldNode.SetAttribute("compact", "0"); - fieldNode.SetAttribute("outline", "0"); - fieldNode.SetAttribute("showAll", "0"); - fieldNode.SetAttribute("defaultSubtotal", "0"); - topNode.AppendChild(fieldNode); - - var field = new ExcelPivotTableField(_table.NameSpaceManager, fieldNode, _table, _table.Fields.Count, Index); - field.DateGrouping = groupBy; - - XmlNode rowColFields; - if (IsRowField) - { - rowColFields=TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager); - } - else - { - rowColFields = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager); - } - - int fieldIndex, index = 0; - foreach (XmlElement rowfield in rowColFields.ChildNodes) - { - if (int.TryParse(rowfield.GetAttribute("x"), out fieldIndex)) - { - if (_table.Fields[fieldIndex].BaseIndex == BaseIndex) - { - var newElement = rowColFields.OwnerDocument.CreateElement("field", ExcelPackage.schemaMain); - newElement.SetAttribute("x", field.Index.ToString()); - rowColFields.InsertBefore(newElement, rowfield); - break; - } - } - index++; - } - - if (IsRowField) - { - _table.RowFields.Insert(field, index); - } - else - { - _table.ColumnFields.Insert(field, index); - } - - _table.Fields.AddInternal(field); - - AddCacheField(field, startDate, endDate, interval); - return field; - } - else - { - firstField = false; - DateGrouping = groupBy; - Compact = false; - SetDateGroup(groupBy, startDate, endDate, interval); - return this; - } - } - private void AddCacheField(ExcelPivotTableField field, DateTime startDate, DateTime endDate, int interval) - { - //Add Cache definition field. - var cacheTopNode = _table.CacheDefinition.CacheDefinitionXml.SelectSingleNode("//d:cacheFields", _table.NameSpaceManager); - var cacheFieldNode = _table.CacheDefinition.CacheDefinitionXml.CreateElement("cacheField", ExcelPackage.schemaMain); - - cacheFieldNode.SetAttribute("name", field.DateGrouping.ToString()); - cacheFieldNode.SetAttribute("databaseField", "0"); - cacheTopNode.AppendChild(cacheFieldNode); - field.SetCacheFieldNode(cacheFieldNode); - - field.SetDateGroup(field.DateGrouping, startDate, endDate, interval); - } + } + return _items; } + } + + /// <summary> + /// Add numberic grouping to the field + /// </summary> + /// <param name="start">Start value</param> + /// <param name="end">End value</param> + /// <param name="interval">Interval</param> + public void AddNumericGrouping(double start, double end, double interval) { + ValidateGrouping(); + SetNumericGroup(start, end, interval); + } + + /// <summary> + /// Add a date grouping on this field. + /// </summary> + /// <param name="groupBy">Group by</param> + public void AddDateGrouping(eDateGroupBy groupBy) { + AddDateGrouping(groupBy, DateTime.MinValue, DateTime.MaxValue, 1); + } + + /// <summary> + /// Add a date grouping on this field. + /// </summary> + /// <param name="groupBy">Group by</param> + /// <param name="startDate">Fixed start date. Use DateTime.MinValue for auto</param> + /// <param name="endDate">Fixed end date. Use DateTime.MaxValue for auto</param> + public void AddDateGrouping(eDateGroupBy groupBy, DateTime startDate, DateTime endDate) { + AddDateGrouping(groupBy, startDate, endDate, 1); + } + + /// <summary> + /// Add a date grouping on this field. + /// </summary> + /// <param name="days">Number of days when grouping on days</param> + /// <param name="startDate">Fixed start date. Use DateTime.MinValue for auto</param> + /// <param name="endDate">Fixed end date. Use DateTime.MaxValue for auto</param> + public void AddDateGrouping(int days, DateTime startDate, DateTime endDate) { + AddDateGrouping(eDateGroupBy.Days, startDate, endDate, days); + } + + private void AddDateGrouping( + eDateGroupBy groupBy, + DateTime startDate, + DateTime endDate, + int groupInterval) { + if (groupInterval < 1 || groupInterval >= Int16.MaxValue) { + throw (new ArgumentOutOfRangeException("Group interval is out of range")); + } + if (groupInterval > 1 && groupBy != eDateGroupBy.Days) { + throw (new ArgumentException("Group interval is can only be used when groupBy is Days")); + } + ValidateGrouping(); + + bool firstField = true; + List<ExcelPivotTableField> fields = new List<ExcelPivotTableField>(); + //Seconds + if ((groupBy & eDateGroupBy.Seconds) == eDateGroupBy.Seconds) { + fields.Add(AddField(eDateGroupBy.Seconds, startDate, endDate, ref firstField)); + } + //Minutes + if ((groupBy & eDateGroupBy.Minutes) == eDateGroupBy.Minutes) { + fields.Add(AddField(eDateGroupBy.Minutes, startDate, endDate, ref firstField)); + } + //Hours + if ((groupBy & eDateGroupBy.Hours) == eDateGroupBy.Hours) { + fields.Add(AddField(eDateGroupBy.Hours, startDate, endDate, ref firstField)); + } + //Days + if ((groupBy & eDateGroupBy.Days) == eDateGroupBy.Days) { + fields.Add(AddField(eDateGroupBy.Days, startDate, endDate, ref firstField, groupInterval)); + } + //Month + if ((groupBy & eDateGroupBy.Months) == eDateGroupBy.Months) { + fields.Add(AddField(eDateGroupBy.Months, startDate, endDate, ref firstField)); + } + //Quarters + if ((groupBy & eDateGroupBy.Quarters) == eDateGroupBy.Quarters) { + fields.Add(AddField(eDateGroupBy.Quarters, startDate, endDate, ref firstField)); + } + //Years + if ((groupBy & eDateGroupBy.Years) == eDateGroupBy.Years) { + fields.Add(AddField(eDateGroupBy.Years, startDate, endDate, ref firstField)); + } + + if (fields.Count > 1) { + _cacheFieldHelper.SetXmlNodeString("d:fieldGroup/@par", (_table.Fields.Count - 1).ToString()); + } + if (groupInterval != 1) { + _cacheFieldHelper.SetXmlNodeString( + "d:fieldGroup/d:rangePr/@groupInterval", + groupInterval.ToString()); + } else { + _cacheFieldHelper.DeleteNode("d:fieldGroup/d:rangePr/@groupInterval"); + } + _items = null; + } + + private void ValidateGrouping() { + if (!(IsColumnField || IsRowField)) { + throw (new("Field must be a row or column field")); + } + foreach (var field in _table.Fields) { + if (field.Grouping != null) { + throw (new("Grouping already exists")); + } + } + } + + private ExcelPivotTableField AddField( + eDateGroupBy groupBy, + DateTime startDate, + DateTime endDate, + ref bool firstField) { + return AddField(groupBy, startDate, endDate, ref firstField, 1); + } + + private ExcelPivotTableField AddField( + eDateGroupBy groupBy, + DateTime startDate, + DateTime endDate, + ref bool firstField, + int interval) { + if (firstField == false) { + //Pivot field + var topNode = _table.PivotTableXml.SelectSingleNode( + "//d:pivotFields", + _table.NameSpaceManager); + var fieldNode = _table.PivotTableXml.CreateElement("pivotField", ExcelPackage._schemaMain); + fieldNode.SetAttribute("compact", "0"); + fieldNode.SetAttribute("outline", "0"); + fieldNode.SetAttribute("showAll", "0"); + fieldNode.SetAttribute("defaultSubtotal", "0"); + topNode.AppendChild(fieldNode); + + var field = new ExcelPivotTableField( + _table.NameSpaceManager, + fieldNode, + _table, + _table.Fields.Count, + Index); + field.DateGrouping = groupBy; + + XmlNode rowColFields; + if (IsRowField) { + rowColFields = TopNode.SelectSingleNode("../../d:rowFields", NameSpaceManager); + } else { + rowColFields = TopNode.SelectSingleNode("../../d:colFields", NameSpaceManager); + } + + int fieldIndex, + index = 0; + foreach (XmlElement rowfield in rowColFields.ChildNodes) { + if (int.TryParse(rowfield.GetAttribute("x"), out fieldIndex)) { + if (_table.Fields[fieldIndex].BaseIndex == BaseIndex) { + var newElement = rowColFields.OwnerDocument.CreateElement( + "field", + ExcelPackage._schemaMain); + newElement.SetAttribute("x", field.Index.ToString()); + rowColFields.InsertBefore(newElement, rowfield); + break; + } + } + index++; + } + + if (IsRowField) { + _table.RowFields.Insert(field, index); + } else { + _table.ColumnFields.Insert(field, index); + } + + _table.Fields.AddInternal(field); + + AddCacheField(field, startDate, endDate, interval); + return field; + } + firstField = false; + DateGrouping = groupBy; + Compact = false; + SetDateGroup(groupBy, startDate, endDate, interval); + return this; + } + + private void AddCacheField( + ExcelPivotTableField field, + DateTime startDate, + DateTime endDate, + int interval) { + //Add Cache definition field. + var cacheTopNode = _table.CacheDefinition.CacheDefinitionXml.SelectSingleNode( + "//d:cacheFields", + _table.NameSpaceManager); + var cacheFieldNode = _table.CacheDefinition.CacheDefinitionXml.CreateElement( + "cacheField", + ExcelPackage._schemaMain); + + cacheFieldNode.SetAttribute("name", field.DateGrouping.ToString()); + cacheFieldNode.SetAttribute("databaseField", "0"); + cacheTopNode.AppendChild(cacheFieldNode); + field.SetCacheFieldNode(cacheFieldNode); + + field.SetDateGroup(field.DateGrouping, startDate, endDate, interval); + } }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableFieldCollection.cs b/EPPlus/Table/PivotTable/ExcelPivotTableFieldCollection.cs index 9b736ce..e60e735 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTableFieldCollection.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTableFieldCollection.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,310 +13,291 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; +using System.Collections; using System.Collections.Generic; -using System.Text; using System.Xml; -namespace OfficeOpenXml.Table.PivotTable -{ - /// <summary> - /// Base collection class for pivottable fields - /// </summary> - /// <typeparam name="T"></typeparam> - public class ExcelPivotTableFieldCollectionBase<T> : IEnumerable<T> - { - protected ExcelPivotTable _table; - internal List<T> _list = new List<T>(); - internal ExcelPivotTableFieldCollectionBase(ExcelPivotTable table) - { - _table = table; - } - public IEnumerator<T> GetEnumerator() - { - return _list.GetEnumerator(); - } +namespace OfficeOpenXml.Table.PivotTable; - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return _list.GetEnumerator(); - } - public int Count - { - get - { - return _list.Count; - } - } - internal void AddInternal(T field) - { - _list.Add(field); - } - internal void Clear() - { - _list.Clear(); - } - public T this[int Index] - { - get - { - if (Index < 0 || Index >= _list.Count) - { - throw (new ArgumentOutOfRangeException("Index out of range")); - } - return _list[Index]; - } - } +/// <summary> +/// Base collection class for pivottable fields +/// </summary> +/// <typeparam name="T"></typeparam> +public class ExcelPivotTableFieldCollectionBase<T> : IEnumerable<T> { + protected ExcelPivotTable _table; + internal List<T> _list = new(); + + internal ExcelPivotTableFieldCollectionBase(ExcelPivotTable table) { + _table = table; + } + + public IEnumerator<T> GetEnumerator() { + return _list.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() { + return _list.GetEnumerator(); + } + + public int Count => _list.Count; + + internal void AddInternal(T field) { + _list.Add(field); + } + + internal void Clear() { + _list.Clear(); + } + + public T this[int index] { + get { + if (index < 0 || index >= _list.Count) { + throw (new ArgumentOutOfRangeException("Index out of range")); + } + return _list[index]; } - public class ExcelPivotTableFieldCollection : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> - { - internal ExcelPivotTableFieldCollection(ExcelPivotTable table, string topNode) : - base(table) - { + } +} +public class ExcelPivotTableFieldCollection + : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> { + internal ExcelPivotTableFieldCollection(ExcelPivotTable table, string topNode) + : base(table) {} + + /// <summary> + /// Indexer by name + /// </summary> + /// <param name="name"></param> + /// <returns></returns> + public ExcelPivotTableField this[string name] { + get { + foreach (var field in _list) { + if (field.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)) { + return field; } - /// <summary> - /// Indexer by name - /// </summary> - /// <param name="name"></param> - /// <returns></returns> - public ExcelPivotTableField this[string name] - { - get - { - foreach (var field in _list) - { - if (field.Name.Equals(name,StringComparison.InvariantCultureIgnoreCase)) - { - return field; - } - } - return null; - } - } - /// <summary> - /// Returns the date group field. - /// </summary> - /// <param name="GroupBy">The type of grouping</param> - /// <returns>The matching field. If none is found null is returned</returns> - public ExcelPivotTableField GetDateGroupField(eDateGroupBy GroupBy) - { - foreach (var fld in _list) - { - if (fld.Grouping is ExcelPivotTableFieldDateGroup && (((ExcelPivotTableFieldDateGroup)fld.Grouping).GroupBy) == GroupBy) - { - return fld; - } - } - return null; - } - /// <summary> - /// Returns the numeric group field. - /// </summary> - /// <returns>The matching field. If none is found null is returned</returns> - public ExcelPivotTableField GetNumericGroupField() - { - foreach (var fld in _list) - { - if (fld.Grouping is ExcelPivotTableFieldNumericGroup) - { - return fld; - } - } - return null; - } + } + return null; } - /// <summary> - /// Collection class for Row and column fields in a Pivottable - /// </summary> - public class ExcelPivotTableRowColumnFieldCollection : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> - { - internal string _topNode; - internal ExcelPivotTableRowColumnFieldCollection(ExcelPivotTable table, string topNode) : - base(table) - { - _topNode=topNode; - } + } - /// <summary> - /// Add a new row/column field - /// </summary> - /// <param name="Field">The field</param> - /// <returns>The new field</returns> - public ExcelPivotTableField Add(ExcelPivotTableField Field) - { - SetFlag(Field, true); - _list.Add(Field); - return Field; - } - /// <summary> - /// Insert a new row/column field - /// </summary> - /// <param name="Field">The field</param> - /// <param name="Index">The position to insert the field</param> - /// <returns>The new field</returns> - internal ExcelPivotTableField Insert(ExcelPivotTableField Field, int Index) - { - SetFlag(Field, true); - _list.Insert(Index, Field); - return Field; - } - private void SetFlag(ExcelPivotTableField field, bool value) - { - switch (_topNode) - { - case "rowFields": - if (field.IsColumnField || field.IsPageField) - { - throw(new Exception("This field is a column or page field. Can't add it to the RowFields collection")); - } - field.IsRowField = value; - field.Axis = ePivotFieldAxis.Row; - break; - case "colFields": - if (field.IsRowField || field.IsPageField) - { - throw (new Exception("This field is a row or page field. Can't add it to the ColumnFields collection")); - } - field.IsColumnField = value; - field.Axis = ePivotFieldAxis.Column; - break; - case "pageFields": - if (field.IsColumnField || field.IsRowField) - { - throw (new Exception("Field is a column or row field. Can't add it to the PageFields collection")); - } - if (_table.Address._fromRow < 3) - { - throw(new Exception(string.Format("A pivot table with page fields must be located above row 3. Currenct location is {0}", _table.Address.Address))); - } - field.IsPageField = value; - field.Axis = ePivotFieldAxis.Page; - break; - case "dataFields": - - break; - } - } - /// <summary> - /// Remove a field - /// </summary> - /// <param name="Field"></param> - public void Remove(ExcelPivotTableField Field) - { - if(!_list.Contains(Field)) - { - throw new ArgumentException("Field not in collection"); - } - SetFlag(Field, false); - _list.Remove(Field); - } - /// <summary> - /// Remove a field at a specific position - /// </summary> - /// <param name="Index"></param> - public void RemoveAt(int Index) - { - if (Index > -1 && Index < _list.Count) - { - throw(new IndexOutOfRangeException()); - } - SetFlag(_list[Index], false); - _list.RemoveAt(Index); - } + /// <summary> + /// Returns the date group field. + /// </summary> + /// <param name="groupBy">The type of grouping</param> + /// <returns>The matching field. If none is found null is returned</returns> + public ExcelPivotTableField GetDateGroupField(eDateGroupBy groupBy) { + foreach (var fld in _list) { + if (fld.Grouping is ExcelPivotTableFieldDateGroup + && (((ExcelPivotTableFieldDateGroup)fld.Grouping).GroupBy) == groupBy) { + return fld; + } } - /// <summary> - /// Collection class for data fields in a Pivottable - /// </summary> - public class ExcelPivotTableDataFieldCollection : ExcelPivotTableFieldCollectionBase<ExcelPivotTableDataField> - { - internal ExcelPivotTableDataFieldCollection(ExcelPivotTable table) : - base(table) - { + return null; + } - } - /// <summary> - /// Add a new datafield - /// </summary> - /// <param name="field">The field</param> - /// <returns>The new datafield</returns> - public ExcelPivotTableDataField Add(ExcelPivotTableField field) - { - var dataFieldsNode = field.TopNode.SelectSingleNode("../../d:dataFields", field.NameSpaceManager); - if (dataFieldsNode == null) - { - _table.CreateNode("d:dataFields"); - dataFieldsNode = field.TopNode.SelectSingleNode("../../d:dataFields", field.NameSpaceManager); - } - - XmlElement node = _table.PivotTableXml.CreateElement("dataField", ExcelPackage.schemaMain); - node.SetAttribute("fld", field.Index.ToString()); - dataFieldsNode.AppendChild(node); - - //XmlElement node = field.AppendField(dataFieldsNode, field.Index, "dataField", "fld"); - field.SetXmlNodeBool("@dataField", true,false); - - var dataField = new ExcelPivotTableDataField(field.NameSpaceManager, node, field); - ValidateDupName(dataField); - - _list.Add(dataField); - return dataField; - } - private void ValidateDupName(ExcelPivotTableDataField dataField) - { - if(ExistsDfName(dataField.Field.Name, null)) - { - var index = 2; - string name; - do - { - name = dataField.Field.Name + "_" + index++.ToString(); - } - while (ExistsDfName(name,null)); - dataField.Name = name; - } - } - - internal bool ExistsDfName(string name, ExcelPivotTableDataField datafield) - { - foreach (var df in _list) - { - if (((!string.IsNullOrEmpty(df.Name) && df.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) || - (string.IsNullOrEmpty(df.Name) && df.Field.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)))) && datafield != df) - { - return true; - } - } - return false; - } - /// <summary> - /// Remove a datafield - /// </summary> - /// <param name="dataField"></param> - public void Remove(ExcelPivotTableDataField dataField) - { - XmlElement node = dataField.Field.TopNode.SelectSingleNode(string.Format("../../d:dataFields/d:dataField[@fld={0}]", dataField.Index), dataField.NameSpaceManager) as XmlElement; - if (node != null) - { - node.ParentNode.RemoveChild(node); - } - _list.Remove(dataField); - } + /// <summary> + /// Returns the numeric group field. + /// </summary> + /// <returns>The matching field. If none is found null is returned</returns> + public ExcelPivotTableField GetNumericGroupField() { + foreach (var fld in _list) { + if (fld.Grouping is ExcelPivotTableFieldNumericGroup) { + return fld; + } } -} \ No newline at end of file + return null; + } +} + +/// <summary> +/// Collection class for Row and column fields in a Pivottable +/// </summary> +public class ExcelPivotTableRowColumnFieldCollection + : ExcelPivotTableFieldCollectionBase<ExcelPivotTableField> { + internal string _topNode; + + internal ExcelPivotTableRowColumnFieldCollection(ExcelPivotTable table, string topNode) + : base(table) { + _topNode = topNode; + } + + /// <summary> + /// Add a new row/column field + /// </summary> + /// <param name="field">The field</param> + /// <returns>The new field</returns> + public ExcelPivotTableField Add(ExcelPivotTableField field) { + SetFlag(field, true); + _list.Add(field); + return field; + } + + /// <summary> + /// Insert a new row/column field + /// </summary> + /// <param name="field">The field</param> + /// <param name="index">The position to insert the field</param> + /// <returns>The new field</returns> + internal ExcelPivotTableField Insert(ExcelPivotTableField field, int index) { + SetFlag(field, true); + _list.Insert(index, field); + return field; + } + + private void SetFlag(ExcelPivotTableField field, bool value) { + switch (_topNode) { + case "rowFields": + if (field.IsColumnField || field.IsPageField) { + throw (new( + "This field is a column or page field. Can't add it to the RowFields collection")); + } + field.IsRowField = value; + field.Axis = ePivotFieldAxis.Row; + break; + case "colFields": + if (field.IsRowField || field.IsPageField) { + throw (new( + "This field is a row or page field. Can't add it to the ColumnFields collection")); + } + field.IsColumnField = value; + field.Axis = ePivotFieldAxis.Column; + break; + case "pageFields": + if (field.IsColumnField || field.IsRowField) { + throw (new("Field is a column or row field. Can't add it to the PageFields collection")); + } + if (_table.Address._fromRow < 3) { + throw (new( + string.Format( + "A pivot table with page fields must be located above row 3. Currenct location is {0}", + _table.Address.Address))); + } + field.IsPageField = value; + field.Axis = ePivotFieldAxis.Page; + break; + case "dataFields": + + break; + } + } + + /// <summary> + /// Remove a field + /// </summary> + /// <param name="field"></param> + public void Remove(ExcelPivotTableField field) { + if (!_list.Contains(field)) { + throw new ArgumentException("Field not in collection"); + } + SetFlag(field, false); + _list.Remove(field); + } + + /// <summary> + /// Remove a field at a specific position + /// </summary> + /// <param name="index"></param> + public void RemoveAt(int index) { + if (index > -1 && index < _list.Count) { + throw (new IndexOutOfRangeException()); + } + SetFlag(_list[index], false); + _list.RemoveAt(index); + } +} + +/// <summary> +/// Collection class for data fields in a Pivottable +/// </summary> +public class ExcelPivotTableDataFieldCollection + : ExcelPivotTableFieldCollectionBase<ExcelPivotTableDataField> { + internal ExcelPivotTableDataFieldCollection(ExcelPivotTable table) + : base(table) {} + + /// <summary> + /// Add a new datafield + /// </summary> + /// <param name="field">The field</param> + /// <returns>The new datafield</returns> + public ExcelPivotTableDataField Add(ExcelPivotTableField field) { + var dataFieldsNode = field.TopNode.SelectSingleNode( + "../../d:dataFields", + field.NameSpaceManager); + if (dataFieldsNode == null) { + _table.CreateNode("d:dataFields"); + dataFieldsNode = field.TopNode.SelectSingleNode("../../d:dataFields", field.NameSpaceManager); + } + + XmlElement node = _table.PivotTableXml.CreateElement("dataField", ExcelPackage._schemaMain); + node.SetAttribute("fld", field.Index.ToString()); + dataFieldsNode.AppendChild(node); + + //XmlElement node = field.AppendField(dataFieldsNode, field.Index, "dataField", "fld"); + field.SetXmlNodeBool("@dataField", true, false); + + var dataField = new ExcelPivotTableDataField(field.NameSpaceManager, node, field); + ValidateDupName(dataField); + + _list.Add(dataField); + return dataField; + } + + private void ValidateDupName(ExcelPivotTableDataField dataField) { + if (ExistsDfName(dataField.Field.Name, null)) { + var index = 2; + string name; + do { + name = dataField.Field.Name + "_" + index++; + } while (ExistsDfName(name, null)); + dataField.Name = name; + } + } + + internal bool ExistsDfName(string name, ExcelPivotTableDataField datafield) { + foreach (var df in _list) { + if (((!string.IsNullOrEmpty(df.Name) + && df.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) + || (string.IsNullOrEmpty(df.Name) + && df.Field.Name.Equals( + name, + StringComparison.InvariantCultureIgnoreCase)))) + && datafield != df) { + return true; + } + } + return false; + } + + /// <summary> + /// Remove a datafield + /// </summary> + /// <param name="dataField"></param> + public void Remove(ExcelPivotTableDataField dataField) { + XmlElement node = + dataField.Field.TopNode.SelectSingleNode( + string.Format("../../d:dataFields/d:dataField[@fld={0}]", dataField.Index), + dataField.NameSpaceManager) as XmlElement; + if (node != null) { + node.ParentNode.RemoveChild(node); + } + _list.Remove(dataField); + } +}
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableFieldGroup.cs b/EPPlus/Table/PivotTable/ExcelPivotTableFieldGroup.cs index cac0918..ea1f9d4 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTableFieldGroup.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTableFieldGroup.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,148 +13,107 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Xml; -using System.Globalization; -namespace OfficeOpenXml.Table.PivotTable -{ - /// <summary> - /// Base class for pivot table field groups - /// </summary> - public class ExcelPivotTableFieldGroup : XmlHelper - { - internal ExcelPivotTableFieldGroup(XmlNamespaceManager ns, XmlNode topNode) : - base(ns, topNode) - { - - } +using System; +using System.Globalization; +using System.Xml; + +namespace OfficeOpenXml.Table.PivotTable; + +/// <summary> +/// Base class for pivot table field groups +/// </summary> +public class ExcelPivotTableFieldGroup : XmlHelper { + internal ExcelPivotTableFieldGroup(XmlNamespaceManager ns, XmlNode topNode) + : base(ns, topNode) {} +} + +/// <summary> +/// A date group +/// </summary> +public class ExcelPivotTableFieldDateGroup : ExcelPivotTableFieldGroup { + internal ExcelPivotTableFieldDateGroup(XmlNamespaceManager ns, XmlNode topNode) + : base(ns, topNode) {} + + private const string _groupByPath = "d:fieldGroup/d:rangePr/@groupBy"; + + /// <summary> + /// How to group the date field + /// </summary> + public eDateGroupBy GroupBy { + get { + string v = GetXmlNodeString(_groupByPath); + if (v != "") { + return (eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), v, true); + } + throw (new("Invalid date Groupby")); } - /// <summary> - /// A date group - /// </summary> - public class ExcelPivotTableFieldDateGroup : ExcelPivotTableFieldGroup - { - internal ExcelPivotTableFieldDateGroup(XmlNamespaceManager ns, XmlNode topNode) : - base(ns, topNode) - { - } - const string groupByPath = "d:fieldGroup/d:rangePr/@groupBy"; - /// <summary> - /// How to group the date field - /// </summary> - public eDateGroupBy GroupBy - { - get - { - string v = GetXmlNodeString(groupByPath); - if (v != "") - { - return (eDateGroupBy)Enum.Parse(typeof(eDateGroupBy), v, true); - } - else - { - throw (new Exception("Invalid date Groupby")); - } - } - private set - { - SetXmlNodeString(groupByPath, value.ToString().ToLower(CultureInfo.InvariantCulture)); - } - } - /// <summary> - /// Auto detect start date - /// </summary> - public bool AutoStart - { - get - { - return GetXmlNodeBool("@autoStart", false); - } - } - /// <summary> - /// Auto detect end date - /// </summary> - public bool AutoEnd - { - get - { - return GetXmlNodeBool("@autoStart", false); - } - } - } - /// <summary> - /// A pivot table field numeric grouping - /// </summary> - public class ExcelPivotTableFieldNumericGroup : ExcelPivotTableFieldGroup - { - internal ExcelPivotTableFieldNumericGroup(XmlNamespaceManager ns, XmlNode topNode) : - base(ns, topNode) - { - } - const string startPath = "d:fieldGroup/d:rangePr/@startNum"; - /// <summary> - /// Start value - /// </summary> - public double Start - { - get - { - return (double)GetXmlNodeDoubleNull(startPath); - } - private set - { - SetXmlNodeString(startPath,value.ToString(CultureInfo.InvariantCulture)); - } - } - const string endPath = "d:fieldGroup/d:rangePr/@endNum"; - /// <summary> - /// End value - /// </summary> - public double End - { - get - { - return (double)GetXmlNodeDoubleNull(endPath); - } - private set - { - SetXmlNodeString(endPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - const string groupIntervalPath = "d:fieldGroup/d:rangePr/@groupInterval"; - /// <summary> - /// Interval - /// </summary> - public double Interval - { - get - { - return (double)GetXmlNodeDoubleNull(groupIntervalPath); - } - private set - { - SetXmlNodeString(groupIntervalPath, value.ToString(CultureInfo.InvariantCulture)); - } - } - } + private set => + SetXmlNodeString(_groupByPath, value.ToString().ToLower(CultureInfo.InvariantCulture)); + } + + /// <summary> + /// Auto detect start date + /// </summary> + public bool AutoStart => GetXmlNodeBool("@autoStart", false); + + /// <summary> + /// Auto detect end date + /// </summary> + public bool AutoEnd => GetXmlNodeBool("@autoStart", false); +} + +/// <summary> +/// A pivot table field numeric grouping +/// </summary> +public class ExcelPivotTableFieldNumericGroup : ExcelPivotTableFieldGroup { + internal ExcelPivotTableFieldNumericGroup(XmlNamespaceManager ns, XmlNode topNode) + : base(ns, topNode) {} + + private const string _startPath = "d:fieldGroup/d:rangePr/@startNum"; + + /// <summary> + /// Start value + /// </summary> + public double Start { + get => (double)GetXmlNodeDoubleNull(_startPath); + private set => SetXmlNodeString(_startPath, value.ToString(CultureInfo.InvariantCulture)); + } + + private const string _endPath = "d:fieldGroup/d:rangePr/@endNum"; + + /// <summary> + /// End value + /// </summary> + public double End { + get => (double)GetXmlNodeDoubleNull(_endPath); + private set => SetXmlNodeString(_endPath, value.ToString(CultureInfo.InvariantCulture)); + } + + private const string _groupIntervalPath = "d:fieldGroup/d:rangePr/@groupInterval"; + + /// <summary> + /// Interval + /// </summary> + public double Interval { + get => (double)GetXmlNodeDoubleNull(_groupIntervalPath); + private set => + SetXmlNodeString(_groupIntervalPath, value.ToString(CultureInfo.InvariantCulture)); + } }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTableFieldItem.cs b/EPPlus/Table/PivotTable/ExcelPivotTableFieldItem.cs index 711507e..d4dce2d 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTableFieldItem.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTableFieldItem.cs
@@ -13,80 +13,62 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ + using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Xml; -namespace OfficeOpenXml.Table.PivotTable -{ - /// <summary> - /// A field Item. Used for grouping - /// </summary> - public class ExcelPivotTableFieldItem : XmlHelper - { - ExcelPivotTableField _field; - internal ExcelPivotTableFieldItem(XmlNamespaceManager ns, XmlNode topNode, ExcelPivotTableField field) : - base(ns, topNode) - { - _field = field; +namespace OfficeOpenXml.Table.PivotTable; + +/// <summary> +/// A field Item. Used for grouping +/// </summary> +public class ExcelPivotTableFieldItem : XmlHelper { + private ExcelPivotTableField _field; + + internal ExcelPivotTableFieldItem( + XmlNamespaceManager ns, + XmlNode topNode, + ExcelPivotTableField field) + : base(ns, topNode) { + _field = field; + } + + /// <summary> + /// The text. Unique values only + /// </summary> + public string Text { + get => GetXmlNodeString("@n"); + set { + if (string.IsNullOrEmpty(value)) { + DeleteNode("@n"); + return; + } + foreach (var item in _field.Items) { + if (item.Text == value) { + throw (new ArgumentException("Duplicate Text")); } - /// <summary> - /// The text. Unique values only - /// </summary> - public string Text - { - get - { - return GetXmlNodeString("@n"); - } - set - { - if(string.IsNullOrEmpty(value)) - { - DeleteNode("@n"); - return; - } - foreach (var item in _field.Items) - { - if (item.Text == value) - { - throw(new ArgumentException("Duplicate Text")); - } - } - SetXmlNodeString("@n", value); - } - } - internal int X - { - get - { - return GetXmlNodeInt("@x"); - } - } - internal string T - { - get - { - return GetXmlNodeString("@t"); - } - } + } + SetXmlNodeString("@n", value); } + } + + internal int X => GetXmlNodeInt("@x"); + + internal string T => GetXmlNodeString("@t"); }
diff --git a/EPPlus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs b/EPPlus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs index 7e5ba85..fe6f762 100644 --- a/EPPlus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs +++ b/EPPlus/Table/PivotTable/ExcelPivotTablePageFieldSettings.cs
@@ -13,106 +13,81 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Added 21-MAR-2011 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; + using System.Xml; -namespace OfficeOpenXml.Table.PivotTable -{ - /// <summary> - /// A page / report filter field - /// </summary> - public class ExcelPivotTablePageFieldSettings : XmlHelper - { - ExcelPivotTableField _field; - internal ExcelPivotTablePageFieldSettings(XmlNamespaceManager ns, XmlNode topNode, ExcelPivotTableField field, int index) : - base(ns, topNode) - { - if (GetXmlNodeString("@hier")=="") - { - Hier = -1; - } - _field = field; - } - internal int Index - { - get - { - return GetXmlNodeInt("@fld"); - } - set - { - SetXmlNodeString("@fld",value.ToString()); - } - } - /// <summary> - /// The Name of the field - /// </summary> - public string Name - { - get - { - return GetXmlNodeString("@name"); - } - set - { - SetXmlNodeString("@name", value); - } - } - /***** Dont work. Need items to be populated. ****/ - ///// <summary> - ///// The selected item - ///// </summary> - //public int SelectedItem - //{ - // get - // { - // return GetXmlNodeInt("@item"); - // } - // set - // { - // if (value < 0) throw new InvalidOperationException("Can't be negative"); - // SetXmlNodeString("@item", value.ToString()); - // } - //} - internal int NumFmtId - { - get - { - return GetXmlNodeInt("@numFmtId"); - } - set - { - SetXmlNodeString("@numFmtId", value.ToString()); - } - } - internal int Hier - { - get - { - return GetXmlNodeInt("@hier"); - } - set - { - SetXmlNodeString("@hier", value.ToString()); - } - } +namespace OfficeOpenXml.Table.PivotTable; + +/// <summary> +/// A page / report filter field +/// </summary> +public class ExcelPivotTablePageFieldSettings : XmlHelper { + private ExcelPivotTableField _field; + + internal ExcelPivotTablePageFieldSettings( + XmlNamespaceManager ns, + XmlNode topNode, + ExcelPivotTableField field, + int index) + : base(ns, topNode) { + if (GetXmlNodeString("@hier") == "") { + Hier = -1; } + _field = field; + } + + internal int Index { + get => GetXmlNodeInt("@fld"); + set => SetXmlNodeString("@fld", value.ToString()); + } + + /// <summary> + /// The Name of the field + /// </summary> + public string Name { + get => GetXmlNodeString("@name"); + set => SetXmlNodeString("@name", value); + } + + /***** Dont work. Need items to be populated. ****/ + ///// <summary> + ///// The selected item + ///// </summary> + //public int SelectedItem + //{ + // get + // { + // return GetXmlNodeInt("@item"); + // } + // set + // { + // if (value < 0) throw new InvalidOperationException("Can't be negative"); + // SetXmlNodeString("@item", value.ToString()); + // } + //} + internal int NumFmtId { + get => GetXmlNodeInt("@numFmtId"); + set => SetXmlNodeString("@numFmtId", value.ToString()); + } + + internal int Hier { + get => GetXmlNodeInt("@hier"); + set => SetXmlNodeString("@hier", value.ToString()); + } }
diff --git a/EPPlus/Utils/AddressUtility.cs b/EPPlus/Utils/AddressUtility.cs index bc1c8fc..05fadd1 100644 --- a/EPPlus/Utils/AddressUtility.cs +++ b/EPPlus/Utils/AddressUtility.cs
@@ -1,29 +1,20 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; -namespace OfficeOpenXml.Utils -{ - public static class AddressUtility - { - public static string ParseEntireColumnSelections(string address) - { - string parsedAddress = address; - var matches = Regex.Matches(address, "[A-Z]+:[A-Z]+"); - foreach (Match match in matches) - { - AddRowNumbersToEntireColumnRange(ref parsedAddress, match.Value); - } - return parsedAddress; - } +namespace OfficeOpenXml.Utils; - private static void AddRowNumbersToEntireColumnRange(ref string address, string range) - { - var parsedRange = string.Format("{0}{1}", range, ExcelPackage.MaxRows); - var splitArr = parsedRange.Split(new char[] { ':' }); - address = address.Replace(range, string.Format("{0}1:{1}", splitArr[0], splitArr[1])); - } +public static class AddressUtility { + public static string ParseEntireColumnSelections(string address) { + string parsedAddress = address; + var matches = Regex.Matches(address, "[A-Z]+:[A-Z]+"); + foreach (Match match in matches) { + AddRowNumbersToEntireColumnRange(ref parsedAddress, match.Value); } + return parsedAddress; + } + + private static void AddRowNumbersToEntireColumnRange(ref string address, string range) { + var parsedRange = string.Format("{0}{1}", range, ExcelPackage.MaxRows); + var splitArr = parsedRange.Split(new[] { ':' }); + address = address.Replace(range, string.Format("{0}1:{1}", splitArr[0], splitArr[1])); + } }
diff --git a/EPPlus/Utils/Argument.cs b/EPPlus/Utils/Argument.cs index 90b0abe..e95c92b 100644 --- a/EPPlus/Utils/Argument.cs +++ b/EPPlus/Utils/Argument.cs
@@ -13,41 +13,31 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.Utils -{ - internal class Argument<T> : IArgument<T> - { - public Argument(T @value) - { - _value = @value; - } +namespace OfficeOpenXml.Utils; - private T _value; +internal class Argument<T> : IArgument<T> { + public Argument(T value) { + _value = value; + } - T IArgument<T>.Value - { - get { return _value; } - } - } + private T _value; + + T IArgument<T>.Value => _value; }
diff --git a/EPPlus/Utils/ArgumentExtensions.cs b/EPPlus/Utils/ArgumentExtensions.cs index 9fdd6c4..6bba854 100644 --- a/EPPlus/Utils/ArgumentExtensions.cs +++ b/EPPlus/Utils/ArgumentExtensions.cs
@@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 @@ -31,65 +31,53 @@ *******************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.Utils -{ - /// <summary> - /// Extension methods for guarding - /// </summary> - public static class ArgumentExtensions - { +namespace OfficeOpenXml.Utils; - /// <summary> - /// Throws an ArgumentNullException if argument is null - /// </summary> - /// <typeparam name="T">Argument type</typeparam> - /// <param name="argument">Argument to check</param> - /// <param name="argumentName">parameter/argument name</param> - /// <exception cref="ArgumentNullException"></exception> - public static void IsNotNull<T>(this IArgument<T> argument, string argumentName) - where T : class - { - argumentName = string.IsNullOrEmpty(argumentName) ? "value" : argumentName; - if (argument.Value == null) - { - throw new ArgumentNullException(argumentName); - } - } - - /// <summary> - /// Throws an <see cref="ArgumentNullException"/> if the string argument is null or empty - /// </summary> - /// <param name="argument">Argument to check</param> - /// <param name="argumentName">parameter/argument name</param> - /// <exception cref="ArgumentNullException"></exception> - public static void IsNotNullOrEmpty(this IArgument<string> argument, string argumentName) - { - if (string.IsNullOrEmpty(argument.Value)) - { - throw new ArgumentNullException(argumentName); - } - } - - /// <summary> - /// Throws an ArgumentOutOfRangeException if the value of the argument is out of the supplied range - /// </summary> - /// <typeparam name="T">Type implementing <see cref="IComparable"/></typeparam> - /// <param name="argument">The argument to check</param> - /// <param name="min">Min value of the supplied range</param> - /// <param name="max">Max value of the supplied range</param> - /// <param name="argumentName">parameter/argument name</param> - /// <exception cref="ArgumentOutOfRangeException"></exception> - public static void IsInRange<T>(this IArgument<T> argument, T min, T max, string argumentName) - where T : IComparable - { - if (!(argument.Value.CompareTo(min) >= 0 && argument.Value.CompareTo(max) <= 0)) - { - throw new ArgumentOutOfRangeException(argumentName); - } - } +/// <summary> +/// Extension methods for guarding +/// </summary> +public static class ArgumentExtensions { + /// <summary> + /// Throws an ArgumentNullException if argument is null + /// </summary> + /// <typeparam name="T">Argument type</typeparam> + /// <param name="argument">Argument to check</param> + /// <param name="argumentName">parameter/argument name</param> + /// <exception cref="ArgumentNullException"></exception> + public static void IsNotNull<T>(this IArgument<T> argument, string argumentName) + where T : class { + argumentName = string.IsNullOrEmpty(argumentName) ? "value" : argumentName; + if (argument.Value == null) { + throw new ArgumentNullException(argumentName); } + } + + /// <summary> + /// Throws an <see cref="ArgumentNullException"/> if the string argument is null or empty + /// </summary> + /// <param name="argument">Argument to check</param> + /// <param name="argumentName">parameter/argument name</param> + /// <exception cref="ArgumentNullException"></exception> + public static void IsNotNullOrEmpty(this IArgument<string> argument, string argumentName) { + if (string.IsNullOrEmpty(argument.Value)) { + throw new ArgumentNullException(argumentName); + } + } + + /// <summary> + /// Throws an ArgumentOutOfRangeException if the value of the argument is out of the supplied range + /// </summary> + /// <typeparam name="T">Type implementing <see cref="IComparable"/></typeparam> + /// <param name="argument">The argument to check</param> + /// <param name="min">Min value of the supplied range</param> + /// <param name="max">Max value of the supplied range</param> + /// <param name="argumentName">parameter/argument name</param> + /// <exception cref="ArgumentOutOfRangeException"></exception> + public static void IsInRange<T>(this IArgument<T> argument, T min, T max, string argumentName) + where T : IComparable { + if (!(argument.Value.CompareTo(min) >= 0 && argument.Value.CompareTo(max) <= 0)) { + throw new ArgumentOutOfRangeException(argumentName); + } + } }
diff --git a/EPPlus/Utils/ConvertUtil.cs b/EPPlus/Utils/ConvertUtil.cs index d528426..fddf785 100644 --- a/EPPlus/Utils/ConvertUtil.cs +++ b/EPPlus/Utils/ConvertUtil.cs
@@ -1,196 +1,171 @@ -using System; -using System.Collections.Generic; +using System; using System.Globalization; -using System.Linq; +using System.IO; using System.Text; using System.Text.RegularExpressions; -using OfficeOpenXml.FormulaParsing.ExpressionGraph; -using System.IO; -namespace OfficeOpenXml.Utils -{ - internal static class ConvertUtil - { - internal static bool IsNumeric(object candidate) - { - if (candidate == null) return false; - return (candidate.GetType().IsPrimitive || candidate is double || candidate is decimal || candidate is DateTime || candidate is TimeSpan || candidate is long); - } +namespace OfficeOpenXml.Utils; - internal static bool IsNumericString(object candidate) - { - if (candidate != null) - { - return Regex.IsMatch(candidate.ToString(), @"^[\d]+(\,[\d])?"); - } - return false; - } - - /// <summary> - /// Convert an object value to a double - /// </summary> - /// <param name="v"></param> - /// <param name="ignoreBool"></param> - /// <returns></returns> - internal static double GetValueDouble(object v, bool ignoreBool = false) - { - double d; - try - { - if (ignoreBool && v is bool) - { - return 0; - } - if (IsNumeric(v)) - { - if (v is DateTime) - { - d = ((DateTime)v).ToOADate(); - } - else if (v is TimeSpan) - { - d = DateTime.FromOADate(0).Add((TimeSpan)v).ToOADate(); - } - else - { - d = Convert.ToDouble(v, CultureInfo.InvariantCulture); - } - } - else - { - d = 0; - } - } - - catch - { - d = 0; - } - return d; - } - /// <summary> - /// OOXML requires that "," , and & be escaped, but ' and " should *not* be escaped, nor should - /// any extended Unicode characters. This function only encodes the required characters. - /// System.Security.SecurityElement.Escape() escapes ' and " as ' and ", so it cannot - /// be used reliably. System.Web.HttpUtility.HtmlEncode overreaches as well and uses the numeric - /// escape equivalent. - /// </summary> - /// <param name="s"></param> - /// <returns></returns> - internal static string ExcelEscapeString(string s) - { - return s.Replace("&", "&").Replace("<", "<").Replace(">", ">"); - } - - /// <summary> - /// Return true if preserve space attribute is set. - /// </summary> - /// <param name="sw"></param> - /// <param name="t"></param> - /// <returns></returns> - internal static void ExcelEncodeString(StreamWriter sw, string t) - { - if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) - { - var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)"); - int indexAdd = 0; - while (match.Success) - { - t = t.Insert(match.Index + indexAdd, "_x005F"); - indexAdd += 6; - match = match.NextMatch(); - } - } - for (int i = 0; i < t.Length; i++) - { - if (t[i] <= 0x1f && t[i] != '\t' && t[i] != '\n' && t[i] != '\r') //Not Tab, CR or LF - { - sw.Write("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X")); - } - else - { - sw.Write(t[i]); - } - } - - } - /// <summary> - /// Return true if preserve space attribute is set. - /// </summary> - /// <param name="sb"></param> - /// <param name="t"></param> - /// <returns></returns> - internal static void ExcelEncodeString(StringBuilder sb, string t, bool encodeTabCRLF=false) - { - if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) - { - var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)"); - int indexAdd = 0; - while (match.Success) - { - t = t.Insert(match.Index + indexAdd, "_x005F"); - indexAdd += 6; - match = match.NextMatch(); - } - } - for (int i = 0; i < t.Length; i++) - { - if (t[i] <= 0x1f && ((t[i] != '\t' && t[i] != '\n' && t[i] != '\r' && encodeTabCRLF == false) || encodeTabCRLF)) //Not Tab, CR or LF - { - sb.AppendFormat("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X")); - } - else - { - sb.Append(t[i]); - } - } - - } - /// <summary> - /// Return true if preserve space attribute is set. - /// </summary> - /// <param name="sb"></param> - /// <param name="t"></param> - /// <returns></returns> - internal static string ExcelEncodeString(string t) - { - StringBuilder sb=new StringBuilder(); - t=t.Replace("\r\n", "\n"); //For some reason can't table name have cr in them. Replace with nl - ExcelEncodeString(sb, t, true); - return sb.ToString(); - } - internal static string ExcelDecodeString(string t) - { - var match = Regex.Match(t, "(_x005F|_x[0-9A-F]{4,4}_)"); - if (!match.Success) return t; - - var useNextValue = false; - var ret = new StringBuilder(); - var prevIndex = 0; - while (match.Success) - { - if (prevIndex < match.Index) ret.Append(t.Substring(prevIndex, match.Index - prevIndex)); - if (!useNextValue && match.Value == "_x005F") - { - useNextValue = true; - } - else - { - if (useNextValue) - { - ret.Append(match.Value); - useNextValue = false; - } - else - { - ret.Append((char)int.Parse(match.Value.Substring(2, 4), NumberStyles.AllowHexSpecifier)); - } - } - prevIndex = match.Index + match.Length; - match = match.NextMatch(); - } - ret.Append(t.Substring(prevIndex, t.Length - prevIndex)); - return ret.ToString(); - } +internal static class ConvertUtil { + internal static bool IsNumeric(object candidate) { + if (candidate == null) { + return false; } + return (candidate.GetType().IsPrimitive + || candidate is double + || candidate is decimal + || candidate is DateTime + || candidate is TimeSpan + || candidate is long); + } + + internal static bool IsNumericString(object candidate) { + if (candidate != null) { + return Regex.IsMatch(candidate.ToString(), @"^[\d]+(\,[\d])?"); + } + return false; + } + + /// <summary> + /// Convert an object value to a double + /// </summary> + /// <param name="v"></param> + /// <param name="ignoreBool"></param> + /// <returns></returns> + internal static double GetValueDouble(object v, bool ignoreBool = false) { + double d; + try { + if (ignoreBool && v is bool) { + return 0; + } + if (IsNumeric(v)) { + if (v is DateTime) { + d = ((DateTime)v).ToOADate(); + } else if (v is TimeSpan) { + d = DateTime.FromOADate(0).Add((TimeSpan)v).ToOADate(); + } else { + d = Convert.ToDouble(v, CultureInfo.InvariantCulture); + } + } else { + d = 0; + } + } catch { + d = 0; + } + return d; + } + + /// <summary> + /// OOXML requires that "," , and & be escaped, but ' and " should *not* be escaped, nor should + /// any extended Unicode characters. This function only encodes the required characters. + /// System.Security.SecurityElement.Escape() escapes ' and " as ' and ", so it cannot + /// be used reliably. System.Web.HttpUtility.HtmlEncode overreaches as well and uses the numeric + /// escape equivalent. + /// </summary> + /// <param name="s"></param> + /// <returns></returns> + internal static string ExcelEscapeString(string s) { + return s.Replace("&", "&").Replace("<", "<").Replace(">", ">"); + } + + /// <summary> + /// Return true if preserve space attribute is set. + /// </summary> + /// <param name="sw"></param> + /// <param name="t"></param> + /// <returns></returns> + internal static void ExcelEncodeString(StreamWriter sw, string t) { + if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) { + var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)"); + int indexAdd = 0; + while (match.Success) { + t = t.Insert(match.Index + indexAdd, "_x005F"); + indexAdd += 6; + match = match.NextMatch(); + } + } + for (int i = 0; i < t.Length; i++) { + if (t[i] <= 0x1f + && t[i] != '\t' + && t[i] != '\n' + && t[i] + != '\r') //Not Tab, CR or LF + { + sw.Write("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X")); + } else { + sw.Write(t[i]); + } + } + } + + /// <summary> + /// Return true if preserve space attribute is set. + /// </summary> + /// <param name="sb"></param> + /// <param name="t"></param> + /// <returns></returns> + internal static void ExcelEncodeString(StringBuilder sb, string t, bool encodeTabCrlf = false) { + if (Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)")) { + var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)"); + int indexAdd = 0; + while (match.Success) { + t = t.Insert(match.Index + indexAdd, "_x005F"); + indexAdd += 6; + match = match.NextMatch(); + } + } + for (int i = 0; i < t.Length; i++) { + if (t[i] <= 0x1f + && ((t[i] != '\t' && t[i] != '\n' && t[i] != '\r' && encodeTabCrlf == false) + || encodeTabCrlf)) //Not Tab, CR or LF + { + sb.AppendFormat("_x00{0}_", (t[i] < 0xf ? "0" : "") + ((int)t[i]).ToString("X")); + } else { + sb.Append(t[i]); + } + } + } + + /// <summary> + /// Return true if preserve space attribute is set. + /// </summary> + /// <param name="sb"></param> + /// <param name="t"></param> + /// <returns></returns> + internal static string ExcelEncodeString(string t) { + StringBuilder sb = new StringBuilder(); + t = t.Replace("\r\n", "\n"); //For some reason can't table name have cr in them. Replace with nl + ExcelEncodeString(sb, t, true); + return sb.ToString(); + } + + internal static string ExcelDecodeString(string t) { + var match = Regex.Match(t, "(_x005F|_x[0-9A-F]{4,4}_)"); + if (!match.Success) { + return t; + } + + var useNextValue = false; + var ret = new StringBuilder(); + var prevIndex = 0; + while (match.Success) { + if (prevIndex < match.Index) { + ret.Append(t.Substring(prevIndex, match.Index - prevIndex)); + } + if (!useNextValue && match.Value == "_x005F") { + useNextValue = true; + } else { + if (useNextValue) { + ret.Append(match.Value); + useNextValue = false; + } else { + ret.Append((char)int.Parse(match.Value.Substring(2, 4), NumberStyles.AllowHexSpecifier)); + } + } + prevIndex = match.Index + match.Length; + match = match.NextMatch(); + } + ret.Append(t.Substring(prevIndex, t.Length - prevIndex)); + return ret.ToString(); + } }
diff --git a/EPPlus/Utils/IArgument.cs b/EPPlus/Utils/IArgument.cs index ac4a5aa..8c4f614 100644 --- a/EPPlus/Utils/IArgument.cs +++ b/EPPlus/Utils/IArgument.cs
@@ -13,36 +13,29 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.Utils; -namespace OfficeOpenXml.Utils -{ - /// <summary> - /// An argument - /// </summary> - /// <typeparam name="T">Argument Type</typeparam> - public interface IArgument<T> - { - T Value { get; } - } +/// <summary> +/// An argument +/// </summary> +/// <typeparam name="T">Argument Type</typeparam> +public interface IArgument<T> { + T Value { get; } }
diff --git a/EPPlus/Utils/IExcelCell.cs b/EPPlus/Utils/IExcelCell.cs index 6447951..b1087c3 100644 --- a/EPPlus/Utils/IExcelCell.cs +++ b/EPPlus/Utils/IExcelCell.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,38 +13,39 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 * Jan Källman License changed GPL-->LGPL 2011-12-16 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Text; -namespace OfficeOpenXml.Style -{ - internal interface IExcelCell - { - #region "public properties" - object Value {get;set;} - string StyleName { get; } - int StyleID { get; set; } - ExcelStyle Style { get; } - Uri Hyperlink { get; set; } - string Formula { get; set; } - string FormulaR1C1 { get; set; } - #endregion - } +using System; + +namespace OfficeOpenXml.Style; + +internal interface IExcelCell { + object Value { get; set; } + + string StyleName { get; } + + int StyleID { get; set; } + + ExcelStyle Style { get; } + + Uri Hyperlink { get; set; } + + string Formula { get; set; } + + string FormulaR1C1 { get; set; } }
diff --git a/EPPlus/Utils/IValidationResult.cs b/EPPlus/Utils/IValidationResult.cs index 19b4986..61ef1c1 100644 --- a/EPPlus/Utils/IValidationResult.cs +++ b/EPPlus/Utils/IValidationResult.cs
@@ -1,13 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.Utils; -namespace OfficeOpenXml.Utils -{ - public interface IValidationResult - { - void IsTrue(); - void IsFalse(); - } +public interface IValidationResult { + void IsTrue(); + + void IsFalse(); }
diff --git a/EPPlus/Utils/Require.cs b/EPPlus/Utils/Require.cs index 6f9943f..17b98d8 100644 --- a/EPPlus/Utils/Require.cs +++ b/EPPlus/Utils/Require.cs
@@ -13,40 +13,30 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Added 2011-01-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +namespace OfficeOpenXml.Utils; -namespace OfficeOpenXml.Utils -{ - /// <summary> - /// Utility for validation - /// </summary> - public static class Require - { - public static IArgument<T> Argument<T>(T argument) - { - return new Argument<T>(argument); - } - - - } +/// <summary> +/// Utility for validation +/// </summary> +public static class Require { + public static IArgument<T> Argument<T>(T argument) { + return new Argument<T>(argument); + } }
diff --git a/EPPlus/Utils/SqRefUtility.cs b/EPPlus/Utils/SqRefUtility.cs index a170486..5115bd3 100644 --- a/EPPlus/Utils/SqRefUtility.cs +++ b/EPPlus/Utils/SqRefUtility.cs
@@ -1,39 +1,31 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; +using System.Text.RegularExpressions; -namespace OfficeOpenXml.Utils -{ - /// <summary> - /// Class for handling translation between ExcelAddresses and sqref addresses. - /// </summary> - public static class SqRefUtility - { - /// <summary> - /// Transforms an address to a valid sqRef address. - /// </summary> - /// <param name="address">The address to transform</param> - /// <returns>A valid SqRef address</returns> - public static string ToSqRefAddress(string address) - { - Require.Argument(address).IsNotNullOrEmpty(address); - address = address.Replace(",", " "); - address = new Regex("[ ]+").Replace(address, " "); - return address; - } +namespace OfficeOpenXml.Utils; - /// <summary> - /// Transforms an sqRef address into a excel address - /// </summary> - /// <param name="address">The address to transform</param> - /// <returns>A valid excel address</returns> - public static string FromSqRefAddress(string address) - { - Require.Argument(address).IsNotNullOrEmpty(address); - address = address.Replace(" ", ","); - return address; - } - } +/// <summary> +/// Class for handling translation between ExcelAddresses and sqref addresses. +/// </summary> +public static class SqRefUtility { + /// <summary> + /// Transforms an address to a valid sqRef address. + /// </summary> + /// <param name="address">The address to transform</param> + /// <returns>A valid SqRef address</returns> + public static string ToSqRefAddress(string address) { + Require.Argument(address).IsNotNullOrEmpty(address); + address = address.Replace(",", " "); + address = new Regex("[ ]+").Replace(address, " "); + return address; + } + + /// <summary> + /// Transforms an sqRef address into a excel address + /// </summary> + /// <param name="address">The address to transform</param> + /// <returns>A valid excel address</returns> + public static string FromSqRefAddress(string address) { + Require.Argument(address).IsNotNullOrEmpty(address); + address = address.Replace(" ", ","); + return address; + } }
diff --git a/EPPlus/Utils/UriHelper.cs b/EPPlus/Utils/UriHelper.cs index 84ff943..8f9c04b 100644 --- a/EPPlus/Utils/UriHelper.cs +++ b/EPPlus/Utils/UriHelper.cs
@@ -1,91 +1,69 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System; -namespace OfficeOpenXml.Utils -{ - internal class UriHelper - { - internal static Uri ResolvePartUri(Uri sourceUri, Uri targetUri) - { - if(targetUri.OriginalString.StartsWith("/")) - { - return targetUri; - } - string[] source = sourceUri.OriginalString.Split('/'); - string[] target = targetUri.OriginalString.Split('/'); +namespace OfficeOpenXml.Utils; - int t = target.Length - 1; - int s; - if(sourceUri.OriginalString.EndsWith("/")) //is the source a directory? - { - s = source.Length-1; - } - else - { - s=source.Length-2; - } - - string file = target[t--]; - - while (t >= 0) - { - if (target[t] == ".") - { - break; - } - else if (target[t] == "..") - { - s--; - t--; - } - else - { - file = target[t--] + "/" + file; - } - } - if (s >= 0) - { - for(int i=s;i>=0;i--) - { - file = source[i] + "/" + file; - } - } - return new Uri(file,UriKind.RelativeOrAbsolute); - } - - internal static Uri GetRelativeUri(Uri WorksheetUri, Uri uri) - { - string[] source = WorksheetUri.OriginalString.Split('/'); - string[] target = uri.OriginalString.Split('/'); - - int slen; - if (WorksheetUri.OriginalString.EndsWith("/")) - { - slen = source.Length; - } - else - { - slen = source.Length-1; - } - int i = 0; - while (i < slen && i < target.Length && source[i] == target[i]) - { - i++; - } - - string dirUp=""; - for (int s = i; s < slen; s++) - { - dirUp += "../"; - } - string file = ""; - for (int t = i; t < target.Length; t++) - { - file += (file==""?"":"/") + target[t]; - } - return new Uri(dirUp+file,UriKind.Relative); - } +internal class UriHelper { + internal static Uri ResolvePartUri(Uri sourceUri, Uri targetUri) { + if (targetUri.OriginalString.StartsWith("/")) { + return targetUri; } + string[] source = sourceUri.OriginalString.Split('/'); + string[] target = targetUri.OriginalString.Split('/'); + + int t = target.Length - 1; + int s; + if (sourceUri.OriginalString.EndsWith( + "/")) //is the source a directory? + { + s = source.Length - 1; + } else { + s = source.Length - 2; + } + + string file = target[t--]; + + while (t >= 0) { + if (target[t] == ".") { + break; + } + if (target[t] == "..") { + s--; + t--; + } else { + file = target[t--] + "/" + file; + } + } + if (s >= 0) { + for (int i = s; i >= 0; i--) { + file = source[i] + "/" + file; + } + } + return new(file, UriKind.RelativeOrAbsolute); + } + + internal static Uri GetRelativeUri(Uri worksheetUri, Uri uri) { + string[] source = worksheetUri.OriginalString.Split('/'); + string[] target = uri.OriginalString.Split('/'); + + int slen; + if (worksheetUri.OriginalString.EndsWith("/")) { + slen = source.Length; + } else { + slen = source.Length - 1; + } + int i = 0; + while (i < slen && i < target.Length && source[i] == target[i]) { + i++; + } + + string dirUp = ""; + for (int s = i; s < slen; s++) { + dirUp += "../"; + } + string file = ""; + for (int t = i; t < target.Length; t++) { + file += (file == "" ? "" : "/") + target[t]; + } + return new(dirUp + file, UriKind.Relative); + } }
diff --git a/EPPlus/Utils/ValidationResult.cs b/EPPlus/Utils/ValidationResult.cs index cb04dab..2985491 100644 --- a/EPPlus/Utils/ValidationResult.cs +++ b/EPPlus/Utils/ValidationResult.cs
@@ -1,50 +1,35 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -namespace OfficeOpenXml.Utils -{ - public class ValidationResult : IValidationResult - { - public ValidationResult(bool result) - : this(result, null) - { - - } +namespace OfficeOpenXml.Utils; - public ValidationResult(bool result, string errorMessage) - { - _result = result; - _errorMessage = errorMessage; - } +public class ValidationResult : IValidationResult { + public ValidationResult(bool result) + : this(result, null) {} - private bool _result; - private string _errorMessage; + public ValidationResult(bool result, string errorMessage) { + _result = result; + _errorMessage = errorMessage; + } - private void Throw() - { - if(string.IsNullOrEmpty(_errorMessage)) - { - throw new InvalidOperationException(); - } - throw new InvalidOperationException(_errorMessage); - } + private bool _result; + private string _errorMessage; - void IValidationResult.IsTrue() - { - if (!_result) - { - Throw(); - } - } - - void IValidationResult.IsFalse() - { - if (_result) - { - Throw(); - } - } + private void Throw() { + if (string.IsNullOrEmpty(_errorMessage)) { + throw new InvalidOperationException(); } + throw new InvalidOperationException(_errorMessage); + } + + void IValidationResult.IsTrue() { + if (!_result) { + Throw(); + } + } + + void IValidationResult.IsFalse() { + if (_result) { + Throw(); + } + } }
diff --git a/EPPlus/XmlHelper.cs b/EPPlus/XmlHelper.cs index 6915a4a..9455242 100644 --- a/EPPlus/XmlHelper.cs +++ b/EPPlus/XmlHelper.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,17 +13,17 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Jan Källman Initial Release 2009-10-01 @@ -33,798 +33,658 @@ *******************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; -using System.Xml; -using OfficeOpenXml.Style; using System.Globalization; using System.IO; -namespace OfficeOpenXml -{ - /// <summary> - /// Help class containing XML functions. - /// Can be Inherited - /// </summary> - public abstract class XmlHelper - { - internal delegate int ChangedEventHandler(StyleBase sender, Style.StyleChangeEventArgs e); +using System.Text; +using System.Xml; +using OfficeOpenXml.Packaging; +using OfficeOpenXml.Style; - internal XmlHelper(XmlNamespaceManager nameSpaceManager) - { - TopNode = null; - NameSpaceManager = nameSpaceManager; - } +namespace OfficeOpenXml; - internal XmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode) - { - TopNode = topNode; - NameSpaceManager = nameSpaceManager; - } - //internal bool ChangedFlag; - internal XmlNamespaceManager NameSpaceManager { get; set; } - internal XmlNode TopNode { get; set; } - string[] _schemaNodeOrder = null; - /// <summary> - /// Schema order list - /// </summary> - internal string[] SchemaNodeOrder - { - get - { - return _schemaNodeOrder; - } - set - { - _schemaNodeOrder = value; - } - } - internal XmlNode CreateNode(string path) - { - if (path == "") - return TopNode; - else - return CreateNode(path, false); - } - internal XmlNode CreateNode(string path, bool insertFirst) - { - XmlNode node = TopNode; - XmlNode prependNode = null; - foreach (string subPath in path.Split('/')) - { - XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager); - if (subNode == null) - { - string nodeName; - string nodePrefix; +/// <summary> +/// Help class containing XML functions. +/// Can be Inherited +/// </summary> +public abstract class XmlHelper { + internal delegate int ChangedEventHandler(StyleBase sender, StyleChangeEventArgs e); - string nameSpaceURI = ""; - string[] nameSplit = subPath.Split(':'); + internal XmlHelper(XmlNamespaceManager nameSpaceManager) { + TopNode = null; + NameSpaceManager = nameSpaceManager; + } - if (SchemaNodeOrder != null && subPath[0] != '@') - { - insertFirst = false; - prependNode = GetPrependNode(subPath, node); - } + internal XmlHelper(XmlNamespaceManager nameSpaceManager, XmlNode topNode) { + TopNode = topNode; + NameSpaceManager = nameSpaceManager; + } - if (nameSplit.Length > 1) - { - nodePrefix = nameSplit[0]; - if (nodePrefix[0] == '@') nodePrefix = nodePrefix.Substring(1, nodePrefix.Length - 1); - nameSpaceURI = NameSpaceManager.LookupNamespace(nodePrefix); - nodeName = nameSplit[1]; - } - else - { - nodePrefix = ""; - nameSpaceURI = ""; - nodeName = nameSplit[0]; - } - if (subPath.StartsWith("@")) - { - XmlAttribute addedAtt = node.OwnerDocument.CreateAttribute(subPath.Substring(1, subPath.Length - 1), nameSpaceURI); //nameSpaceURI - node.Attributes.Append(addedAtt); - } - else - { - if (nodePrefix == "") - { - subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceURI); - } - else - { - if (nodePrefix == "" || (node.OwnerDocument != null && node.OwnerDocument.DocumentElement != null && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceURI && - node.OwnerDocument.DocumentElement.Prefix == "")) - { - subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceURI); - } - else - { - subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceURI); - } - } - if (prependNode != null) - { - node.InsertBefore(subNode, prependNode); - prependNode = null; - } - else if (insertFirst) - { - node.PrependChild(subNode); - } - else - { - node.AppendChild(subNode); - } - } - } - node = subNode; - } - return node; - } + //internal bool ChangedFlag; + internal XmlNamespaceManager NameSpaceManager { get; set; } - /// <summary> - /// Options to insert a node in the XmlDocument - /// </summary> - internal enum eNodeInsertOrder - { - /// <summary> - /// Insert as first node of "topNode" - /// </summary> - First, + internal XmlNode TopNode { get; set; } - /// <summary> - /// Insert as the last child of "topNode" - /// </summary> - Last, + private string[] _schemaNodeOrder; - /// <summary> - /// Insert after the "referenceNode" - /// </summary> - After, + /// <summary> + /// Schema order list + /// </summary> + internal string[] SchemaNodeOrder { + get => _schemaNodeOrder; + set => _schemaNodeOrder = value; + } - /// <summary> - /// Insert before the "referenceNode" - /// </summary> - Before, + internal XmlNode CreateNode(string path) { + if (path == "") { + return TopNode; + } + return CreateNode(path, false); + } - /// <summary> - /// Use the Schema List to insert in the right order. If the Schema list - /// is null or empty, consider "Last" as the selected option - /// </summary> - SchemaOrder - } + internal XmlNode CreateNode(string path, bool insertFirst) { + XmlNode node = TopNode; + XmlNode prependNode = null; + foreach (string subPath in path.Split('/')) { + XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager); + if (subNode == null) { + string nodeName; + string nodePrefix; - /// <summary> - /// Create a complex node. Insert the node according to SchemaOrder - /// using the TopNode as the parent - /// </summary> - /// <param name="path"></param> - /// <returns></returns> - internal XmlNode CreateComplexNode( - string path) - { - return CreateComplexNode( - TopNode, - path, - eNodeInsertOrder.SchemaOrder, - null); - } + string nameSpaceUri = ""; + string[] nameSplit = subPath.Split(':'); - /// <summary> - /// Create a complex node. Insert the node according to the <paramref name="path"/> - /// using the <paramref name="topNode"/> as the parent - /// </summary> - /// <param name="topNode"></param> - /// <param name="path"></param> - /// <returns></returns> - internal XmlNode CreateComplexNode( - XmlNode topNode, - string path) - { - return CreateComplexNode( - topNode, - path, - eNodeInsertOrder.SchemaOrder, - null); - } + if (SchemaNodeOrder != null && subPath[0] != '@') { + insertFirst = false; + prependNode = GetPrependNode(subPath, node); + } - /// <summary> - /// Creates complex XML nodes + if (nameSplit.Length > 1) { + nodePrefix = nameSplit[0]; + if (nodePrefix[0] == '@') { + nodePrefix = nodePrefix.Substring(1, nodePrefix.Length - 1); + } + nameSpaceUri = NameSpaceManager.LookupNamespace(nodePrefix); + nodeName = nameSplit[1]; + } else { + nodePrefix = ""; + nameSpaceUri = ""; + nodeName = nameSplit[0]; + } + if (subPath.StartsWith("@")) { + XmlAttribute addedAtt = node.OwnerDocument.CreateAttribute( + subPath.Substring(1, subPath.Length - 1), + nameSpaceUri); //nameSpaceURI + node.Attributes.Append(addedAtt); + } else { + if (nodePrefix == "") { + subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri); + } else { + if (nodePrefix == "" + || (node.OwnerDocument != null + && node.OwnerDocument.DocumentElement != null + && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceUri + && node.OwnerDocument.DocumentElement.Prefix == "")) { + subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri); + } else { + subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceUri); + } + } + if (prependNode != null) { + node.InsertBefore(subNode, prependNode); + prependNode = null; + } else if (insertFirst) { + node.PrependChild(subNode); + } else { + node.AppendChild(subNode); + } + } + } + node = subNode; + } + return node; + } + + /// <summary> + /// Options to insert a node in the XmlDocument + /// </summary> + internal enum eNodeInsertOrder { + /// <summary> + /// Insert as first node of "topNode" /// </summary> - /// <remarks> - /// 1. "d:conditionalFormatting" - /// 1.1. Creates/find the first "conditionalFormatting" node - /// - /// 2. "d:conditionalFormatting/@sqref" - /// 2.1. Creates/find the first "conditionalFormatting" node - /// 2.2. Creates (if not exists) the @sqref attribute - /// - /// 3. "d:conditionalFormatting/@id='7'/@sqref='A9:B99'" - /// 3.1. Creates/find the first "conditionalFormatting" node - /// 3.2. Creates/update its @id attribute to "7" - /// 3.3. Creates/update its @sqref attribute to "A9:B99" - /// - /// 4. "d:conditionalFormatting[@id='7']/@sqref='X1:X5'" - /// 4.1. Creates/find the first "conditionalFormatting" node with @id=7 - /// 4.2. Creates/update its @sqref attribute to "X1:X5" - /// - /// 5. "d:conditionalFormatting[@id='7']/@id='8'/@sqref='X1:X5'/d:cfRule/@id='AB'" - /// 5.1. Creates/find the first "conditionalFormatting" node with @id=7 - /// 5.2. Set its @id attribute to "8" - /// 5.2. Creates/update its @sqref attribute and set it to "X1:X5" - /// 5.3. Creates/find the first "cfRule" node (inside the node) - /// 5.4. Creates/update its @id attribute to "AB" - /// - /// 6. "d:cfRule/@id=''" - /// 6.1. Creates/find the first "cfRule" node - /// 6.1. Remove the @id attribute - /// </remarks> - /// <param name="topNode"></param> - /// <param name="path"></param> - /// <param name="nodeInsertOrder"></param> - /// <param name="referenceNode"></param> - /// <returns>The last node creates/found</returns> - internal XmlNode CreateComplexNode( - XmlNode topNode, - string path, - eNodeInsertOrder nodeInsertOrder, - XmlNode referenceNode) - { - // Path is obrigatory - if ((path == null) || (path == string.Empty)) - { - return topNode; - } + First, - XmlNode node = topNode; - string nameSpaceURI = string.Empty; + /// <summary> + /// Insert as the last child of "topNode" + /// </summary> + Last, - //TODO: BUG: when the "path" contains "/" in an attrribue value, it gives an error. + /// <summary> + /// Insert after the "referenceNode" + /// </summary> + After, - // Separate the XPath to Nodes and Attributes - foreach (string subPath in path.Split('/')) - { - // The subPath can be any one of those: - // nodeName - // x:nodeName - // nodeName[find criteria] - // x:nodeName[find criteria] - // @attribute - // @attribute='attribute value' + /// <summary> + /// Insert before the "referenceNode" + /// </summary> + Before, - // Check if the subPath has at least one character - if (subPath.Length > 0) - { - // Check if the subPath is an attribute (with or without value) - if (subPath.StartsWith("@")) - { - // @attribute --> Create attribute - // @attribute='' --> Remove attribute - // @attribute='attribute value' --> Create attribute + update value - string[] attributeSplit = subPath.Split('='); - string attributeName = attributeSplit[0].Substring(1, attributeSplit[0].Length - 1); - string attributeValue = null; // Null means no attribute value + /// <summary> + /// Use the Schema List to insert in the right order. If the Schema list + /// is null or empty, consider "Last" as the selected option + /// </summary> + SchemaOrder, + } - // Check if we have an attribute value to set - if (attributeSplit.Length > 1) - { - // Remove the ' or " from the attribute value - attributeValue = attributeSplit[1].Replace("'", "").Replace("\"", ""); - } + /// <summary> + /// Create a complex node. Insert the node according to SchemaOrder + /// using the TopNode as the parent + /// </summary> + /// <param name="path"></param> + /// <returns></returns> + internal XmlNode CreateComplexNode(string path) { + return CreateComplexNode(TopNode, path, eNodeInsertOrder.SchemaOrder, null); + } - // Get the attribute (if exists) - XmlAttribute attribute = (XmlAttribute)(node.Attributes.GetNamedItem(attributeName)); + /// <summary> + /// Create a complex node. Insert the node according to the <paramref name="path"/> + /// using the <paramref name="topNode"/> as the parent + /// </summary> + /// <param name="topNode"></param> + /// <param name="path"></param> + /// <returns></returns> + internal XmlNode CreateComplexNode(XmlNode topNode, string path) { + return CreateComplexNode(topNode, path, eNodeInsertOrder.SchemaOrder, null); + } - // Remove the attribute if value is empty (not null) - if (attributeValue == string.Empty) - { - // Only if the attribute exists - if (attribute != null) - { - node.Attributes.Remove(attribute); - } - } - else - { - // Create the attribue if does not exists - if (attribute == null) - { - // Create the attribute - attribute = node.OwnerDocument.CreateAttribute( - attributeName); - - // Add it to the current node - node.Attributes.Append(attribute); - } - - // Update the attribute value - if (attributeValue != null) - { - node.Attributes[attributeName].Value = attributeValue; - } - } - } - else - { - // nodeName - // x:nodeName - // nodeName[find criteria] - // x:nodeName[find criteria] - - // Look for the node (with or without filter criteria) - XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager); - - // Check if the node does not exists - if (subNode == null) - { - string nodeName; - string nodePrefix; - string[] nameSplit = subPath.Split(':'); - nameSpaceURI = string.Empty; - - // Check if the name has a prefix like "d:nodeName" - if (nameSplit.Length > 1) - { - nodePrefix = nameSplit[0]; - nameSpaceURI = NameSpaceManager.LookupNamespace(nodePrefix); - nodeName = nameSplit[1]; - } - else - { - nodePrefix = string.Empty; - nameSpaceURI = string.Empty; - nodeName = nameSplit[0]; - } - - // Check if we have a criteria part in the node name - if (nodeName.IndexOf("[") > 0) - { - // remove the criteria from the node name - nodeName = nodeName.Substring(0, nodeName.IndexOf("[")); - } - - if (nodePrefix == string.Empty) - { - subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceURI); - } - else - { - if (node.OwnerDocument != null - && node.OwnerDocument.DocumentElement != null - && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceURI - && node.OwnerDocument.DocumentElement.Prefix == string.Empty) - { - subNode = node.OwnerDocument.CreateElement( - nodeName, - nameSpaceURI); - } - else - { - subNode = node.OwnerDocument.CreateElement( - nodePrefix, - nodeName, - nameSpaceURI); - } - } - - // Check if we need to use the "SchemaOrder" - if (nodeInsertOrder == eNodeInsertOrder.SchemaOrder) - { - // Check if the Schema Order List is empty - if ((SchemaNodeOrder == null) || (SchemaNodeOrder.Length == 0)) - { - // Use the "Insert Last" option when Schema Order List is empty - nodeInsertOrder = eNodeInsertOrder.Last; - } - else - { - // Find the prepend node in order to insert - referenceNode = GetPrependNode(nodeName, node); - - if (referenceNode != null) - { - nodeInsertOrder = eNodeInsertOrder.Before; - } - else - { - nodeInsertOrder = eNodeInsertOrder.Last; - } - } - } - - switch (nodeInsertOrder) - { - case eNodeInsertOrder.After: - node.InsertAfter(subNode, referenceNode); - referenceNode = null; - break; - - case eNodeInsertOrder.Before: - node.InsertBefore(subNode, referenceNode); - referenceNode = null; - break; - - case eNodeInsertOrder.First: - node.PrependChild(subNode); - break; - - case eNodeInsertOrder.Last: - node.AppendChild(subNode); - break; - } - } - - // Make the newly created node the top node when the rest of the path - // is being evaluated. So newly created nodes will be the children of the - // one we just created. - node = subNode; - } - } - } - - // Return the last created/found node - return node; - } - - /// <summary> - /// return Prepend node - /// </summary> - /// <param name="nodeName">name of the node to check</param> - /// <param name="node">Topnode to check children</param> - /// <returns></returns> - private XmlNode GetPrependNode(string nodeName, XmlNode node) - { - int pos = GetNodePos(nodeName); - if (pos < 0) - { - return null; - } - XmlNode prependNode = null; - foreach (XmlNode childNode in node.ChildNodes) - { - int childPos = GetNodePos(childNode.Name); - if (childPos > -1) //Found? - { - if (childPos > pos) //Position is before - { - prependNode = childNode; - break; - } - } - } - return prependNode; - } - private int GetNodePos(string nodeName) - { - int ix = nodeName.IndexOf(":"); - if (ix > 0) - { - nodeName = nodeName.Substring(ix + 1, nodeName.Length - (ix + 1)); - } - for (int i = 0; i < _schemaNodeOrder.Length; i++) - { - if (nodeName == _schemaNodeOrder[i]) - { - return i; - } - } - return -1; - } - internal void DeleteAllNode(string path) - { - string[] split = path.Split('/'); - XmlNode node = TopNode; - foreach (string s in split) - { - node = node.SelectSingleNode(s, NameSpaceManager); - if (node != null) - { - if (node is XmlAttribute) - { - (node as XmlAttribute).OwnerElement.Attributes.Remove(node as XmlAttribute); - } - else - { - node.ParentNode.RemoveChild(node); - } - } - else - { - break; - } - } - } - internal void DeleteNode(string path) - { - var node = TopNode.SelectSingleNode(path, NameSpaceManager); - if (node != null) - { - if (node is XmlAttribute) - { - var att = (XmlAttribute)node; - att.OwnerElement.Attributes.Remove(att); - } - else - { - node.ParentNode.RemoveChild(node); - } - } - } - internal void DeleteTopNode() - { - TopNode.ParentNode.RemoveChild(TopNode); + /// <summary> + /// Creates complex XML nodes + /// </summary> + /// <remarks> + /// 1. "d:conditionalFormatting" + /// 1.1. Creates/find the first "conditionalFormatting" node + /// + /// 2. "d:conditionalFormatting/@sqref" + /// 2.1. Creates/find the first "conditionalFormatting" node + /// 2.2. Creates (if not exists) the @sqref attribute + /// + /// 3. "d:conditionalFormatting/@id='7'/@sqref='A9:B99'" + /// 3.1. Creates/find the first "conditionalFormatting" node + /// 3.2. Creates/update its @id attribute to "7" + /// 3.3. Creates/update its @sqref attribute to "A9:B99" + /// + /// 4. "d:conditionalFormatting[@id='7']/@sqref='X1:X5'" + /// 4.1. Creates/find the first "conditionalFormatting" node with @id=7 + /// 4.2. Creates/update its @sqref attribute to "X1:X5" + /// + /// 5. "d:conditionalFormatting[@id='7']/@id='8'/@sqref='X1:X5'/d:cfRule/@id='AB'" + /// 5.1. Creates/find the first "conditionalFormatting" node with @id=7 + /// 5.2. Set its @id attribute to "8" + /// 5.2. Creates/update its @sqref attribute and set it to "X1:X5" + /// 5.3. Creates/find the first "cfRule" node (inside the node) + /// 5.4. Creates/update its @id attribute to "AB" + /// + /// 6. "d:cfRule/@id=''" + /// 6.1. Creates/find the first "cfRule" node + /// 6.1. Remove the @id attribute + /// </remarks> + /// <param name="topNode"></param> + /// <param name="path"></param> + /// <param name="nodeInsertOrder"></param> + /// <param name="referenceNode"></param> + /// <returns>The last node creates/found</returns> + internal XmlNode CreateComplexNode( + XmlNode topNode, + string path, + eNodeInsertOrder nodeInsertOrder, + XmlNode referenceNode) { + // Path is obrigatory + if ((path == null) || (path == string.Empty)) { + return topNode; } - internal void SetXmlNodeString(string path, string value) - { - SetXmlNodeString(TopNode, path, value, false, false); - } - internal void SetXmlNodeString(string path, string value, bool removeIfBlank) - { - SetXmlNodeString(TopNode, path, value, removeIfBlank, false); - } - internal void SetXmlNodeString(XmlNode node, string path, string value) - { - SetXmlNodeString(node, path, value, false, false); - } - internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank) - { - SetXmlNodeString(node, path, value, removeIfBlank, false); - } - internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank, bool insertFirst) - { - if (node == null) - { - return; - } - if (value == "" && removeIfBlank) - { - DeleteAllNode(path); - } - else - { - XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager); - if (nameNode == null) - { - CreateNode(path, insertFirst); - nameNode = node.SelectSingleNode(path, NameSpaceManager); - } - //if (nameNode.InnerText != value) HasChanged(); - nameNode.InnerText = value; - } - } - internal void SetXmlNodeBool(string path, bool value) - { - SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false); - } - internal void SetXmlNodeBool(string path, bool value, bool removeIf) - { - if (value == removeIf) - { - var node = TopNode.SelectSingleNode(path, NameSpaceManager); - if (node != null) - { - if (node is XmlAttribute) - { - var elem = (node as XmlAttribute).OwnerElement; - elem.ParentNode.RemoveChild(elem); - } - else - { - TopNode.RemoveChild(node); - } - } - } - else - { - SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false); - } - } - internal bool ExistNode(string path) - { - if (TopNode == null || TopNode.SelectSingleNode(path, NameSpaceManager) == null) - { - return false; - } - else - { - return true; - } - } - internal bool? GetXmlNodeBoolNullable(string path) - { - var value = GetXmlNodeString(path); - if (string.IsNullOrEmpty(value)) - { - return null; - } - return GetXmlNodeBool(path); - } - internal bool GetXmlNodeBool(string path) - { - return GetXmlNodeBool(path, false); - } - internal bool GetXmlNodeBool(string path, bool blankValue) - { - string value = GetXmlNodeString(path); - if (value == "1" || value == "-1" || value.Equals("true",StringComparison.InvariantCultureIgnoreCase)) - { - return true; - } - else if (value == "") - { - return blankValue; - } - else - { - return false; - } - } - internal int GetXmlNodeInt(string path) - { - int i; - if (int.TryParse(GetXmlNodeString(path), out i)) - { - return i; - } - else - { - return int.MinValue; - } - } - internal int? GetXmlNodeIntNull(string path) - { - int i; - string s = GetXmlNodeString(path); - if (s!="" && int.TryParse(s, out i)) - { - return i; - } - else - { - return null; - } - } - internal decimal GetXmlNodeDecimal(string path) - { - decimal d; - if (decimal.TryParse(GetXmlNodeString(path), NumberStyles.Any, CultureInfo.InvariantCulture, out d)) - { - return d; - } - else - { - return 0; - } - } - internal decimal? GetXmlNodeDecimalNull(string path) - { - decimal d; - if (decimal.TryParse(GetXmlNodeString(path), NumberStyles.Any, CultureInfo.InvariantCulture, out d)) - { - return d; + XmlNode node = topNode; + string nameSpaceUri = string.Empty; + + //TODO: BUG: when the "path" contains "/" in an attrribue value, it gives an error. + + // Separate the XPath to Nodes and Attributes + foreach (string subPath in path.Split('/')) { + // The subPath can be any one of those: + // nodeName + // x:nodeName + // nodeName[find criteria] + // x:nodeName[find criteria] + // @attribute + // @attribute='attribute value' + + // Check if the subPath has at least one character + if (subPath.Length > 0) { + // Check if the subPath is an attribute (with or without value) + if (subPath.StartsWith("@")) { + // @attribute --> Create attribute + // @attribute='' --> Remove attribute + // @attribute='attribute value' --> Create attribute + update value + string[] attributeSplit = subPath.Split('='); + string attributeName = attributeSplit[0].Substring(1, attributeSplit[0].Length - 1); + string attributeValue = null; // Null means no attribute value + + // Check if we have an attribute value to set + if (attributeSplit.Length > 1) { + // Remove the ' or " from the attribute value + attributeValue = attributeSplit[1].Replace("'", "").Replace("\"", ""); + } + + // Get the attribute (if exists) + XmlAttribute attribute = (XmlAttribute)(node.Attributes.GetNamedItem(attributeName)); + + // Remove the attribute if value is empty (not null) + if (attributeValue == string.Empty) { + // Only if the attribute exists + if (attribute != null) { + node.Attributes.Remove(attribute); } - else - { - return null; + } else { + // Create the attribue if does not exists + if (attribute == null) { + // Create the attribute + attribute = node.OwnerDocument.CreateAttribute(attributeName); + + // Add it to the current node + node.Attributes.Append(attribute); } + + // Update the attribute value + if (attributeValue != null) { + node.Attributes[attributeName].Value = attributeValue; + } + } + } else { + // nodeName + // x:nodeName + // nodeName[find criteria] + // x:nodeName[find criteria] + + // Look for the node (with or without filter criteria) + XmlNode subNode = node.SelectSingleNode(subPath, NameSpaceManager); + + // Check if the node does not exists + if (subNode == null) { + string nodeName; + string nodePrefix; + string[] nameSplit = subPath.Split(':'); + nameSpaceUri = string.Empty; + + // Check if the name has a prefix like "d:nodeName" + if (nameSplit.Length > 1) { + nodePrefix = nameSplit[0]; + nameSpaceUri = NameSpaceManager.LookupNamespace(nodePrefix); + nodeName = nameSplit[1]; + } else { + nodePrefix = string.Empty; + nameSpaceUri = string.Empty; + nodeName = nameSplit[0]; + } + + // Check if we have a criteria part in the node name + if (nodeName.IndexOf("[") > 0) { + // remove the criteria from the node name + nodeName = nodeName.Substring(0, nodeName.IndexOf("[")); + } + + if (nodePrefix == string.Empty) { + subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri); + } else { + if (node.OwnerDocument != null + && node.OwnerDocument.DocumentElement != null + && node.OwnerDocument.DocumentElement.NamespaceURI == nameSpaceUri + && node.OwnerDocument.DocumentElement.Prefix == string.Empty) { + subNode = node.OwnerDocument.CreateElement(nodeName, nameSpaceUri); + } else { + subNode = node.OwnerDocument.CreateElement(nodePrefix, nodeName, nameSpaceUri); + } + } + + // Check if we need to use the "SchemaOrder" + if (nodeInsertOrder == eNodeInsertOrder.SchemaOrder) { + // Check if the Schema Order List is empty + if ((SchemaNodeOrder == null) || (SchemaNodeOrder.Length == 0)) { + // Use the "Insert Last" option when Schema Order List is empty + nodeInsertOrder = eNodeInsertOrder.Last; + } else { + // Find the prepend node in order to insert + referenceNode = GetPrependNode(nodeName, node); + + if (referenceNode != null) { + nodeInsertOrder = eNodeInsertOrder.Before; + } else { + nodeInsertOrder = eNodeInsertOrder.Last; + } + } + } + + switch (nodeInsertOrder) { + case eNodeInsertOrder.After: + node.InsertAfter(subNode, referenceNode); + referenceNode = null; + break; + + case eNodeInsertOrder.Before: + node.InsertBefore(subNode, referenceNode); + referenceNode = null; + break; + + case eNodeInsertOrder.First: + node.PrependChild(subNode); + break; + + case eNodeInsertOrder.Last: + node.AppendChild(subNode); + break; + } + } + + // Make the newly created node the top node when the rest of the path + // is being evaluated. So newly created nodes will be the children of the + // one we just created. + node = subNode; } - internal double? GetXmlNodeDoubleNull(string path) - { - string s = GetXmlNodeString(path); - if (s == "") - { - return null; - } - else - { - double v; - if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) - { - return v; - } - else - { - return null; - } - } - } - internal double GetXmlNodeDouble(string path) - { - string s = GetXmlNodeString(path); - if (s == "") - { - return double.NaN; - } - else - { - double v; - if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) - { - return v; - } - else - { - return double.NaN; - } - } - } - internal string GetXmlNodeString(XmlNode node, string path) - { - if (node == null) - { - return ""; } + } + // Return the last created/found node + return node; + } + + /// <summary> + /// return Prepend node + /// </summary> + /// <param name="nodeName">name of the node to check</param> + /// <param name="node">Topnode to check children</param> + /// <returns></returns> + private XmlNode GetPrependNode(string nodeName, XmlNode node) { + int pos = GetNodePos(nodeName); + if (pos < 0) { + return null; + } + XmlNode prependNode = null; + foreach (XmlNode childNode in node.ChildNodes) { + int childPos = GetNodePos(childNode.Name); + if (childPos + > -1) //Found? + { + if (childPos + > pos) //Position is before + { + prependNode = childNode; + break; + } + } + } + return prependNode; + } + + private int GetNodePos(string nodeName) { + int ix = nodeName.IndexOf(":"); + if (ix > 0) { + nodeName = nodeName.Substring(ix + 1, nodeName.Length - (ix + 1)); + } + for (int i = 0; i < _schemaNodeOrder.Length; i++) { + if (nodeName == _schemaNodeOrder[i]) { + return i; + } + } + return -1; + } + + internal void DeleteAllNode(string path) { + string[] split = path.Split('/'); + XmlNode node = TopNode; + foreach (string s in split) { + node = node.SelectSingleNode(s, NameSpaceManager); + if (node != null) { + if (node is XmlAttribute) { + (node as XmlAttribute).OwnerElement.Attributes.Remove(node as XmlAttribute); + } else { + node.ParentNode.RemoveChild(node); + } + } else { + break; + } + } + } + + internal void DeleteNode(string path) { + var node = TopNode.SelectSingleNode(path, NameSpaceManager); + if (node != null) { + if (node is XmlAttribute) { + var att = (XmlAttribute)node; + att.OwnerElement.Attributes.Remove(att); + } else { + node.ParentNode.RemoveChild(node); + } + } + } + + internal void DeleteTopNode() { + TopNode.ParentNode.RemoveChild(TopNode); + } + + internal void SetXmlNodeString(string path, string value) { + SetXmlNodeString(TopNode, path, value, false, false); + } + + internal void SetXmlNodeString(string path, string value, bool removeIfBlank) { + SetXmlNodeString(TopNode, path, value, removeIfBlank, false); + } + + internal void SetXmlNodeString(XmlNode node, string path, string value) { + SetXmlNodeString(node, path, value, false, false); + } + + internal void SetXmlNodeString(XmlNode node, string path, string value, bool removeIfBlank) { + SetXmlNodeString(node, path, value, removeIfBlank, false); + } + + internal void SetXmlNodeString( + XmlNode node, + string path, + string value, + bool removeIfBlank, + bool insertFirst) { + if (node == null) { + return; + } + if (value == "" && removeIfBlank) { + DeleteAllNode(path); + } else { XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager); + if (nameNode == null) { + CreateNode(path, insertFirst); + nameNode = node.SelectSingleNode(path, NameSpaceManager); + } + //if (nameNode.InnerText != value) HasChanged(); + nameNode.InnerText = value; + } + } - if (nameNode != null) - { - if (nameNode.NodeType == XmlNodeType.Attribute) - { - return nameNode.Value != null ? nameNode.Value : ""; - } - else - { - return nameNode.InnerText; + internal void SetXmlNodeBool(string path, bool value) { + SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false); + } + + internal void SetXmlNodeBool(string path, bool value, bool removeIf) { + if (value == removeIf) { + var node = TopNode.SelectSingleNode(path, NameSpaceManager); + if (node != null) { + if (node is XmlAttribute) { + var elem = (node as XmlAttribute).OwnerElement; + elem.ParentNode.RemoveChild(elem); + } else { + TopNode.RemoveChild(node); } } - else - { - return ""; + } else { + SetXmlNodeString(TopNode, path, value ? "1" : "0", false, false); + } + } + + internal bool ExistNode(string path) { + if (TopNode == null || TopNode.SelectSingleNode(path, NameSpaceManager) == null) { + return false; + } + return true; + } + + internal bool? GetXmlNodeBoolNullable(string path) { + var value = GetXmlNodeString(path); + if (string.IsNullOrEmpty(value)) { + return null; + } + return GetXmlNodeBool(path); + } + + internal bool GetXmlNodeBool(string path) { + return GetXmlNodeBool(path, false); + } + + internal bool GetXmlNodeBool(string path, bool blankValue) { + string value = GetXmlNodeString(path); + if (value == "1" + || value == "-1" + || value.Equals("true", StringComparison.InvariantCultureIgnoreCase)) { + return true; + } + if (value == "") { + return blankValue; + } + return false; + } + + internal int GetXmlNodeInt(string path) { + int i; + if (int.TryParse(GetXmlNodeString(path), out i)) { + return i; + } + return int.MinValue; + } + + internal int? GetXmlNodeIntNull(string path) { + int i; + string s = GetXmlNodeString(path); + if (s != "" && int.TryParse(s, out i)) { + return i; + } + return null; + } + + internal decimal GetXmlNodeDecimal(string path) { + decimal d; + if (decimal.TryParse( + GetXmlNodeString(path), + NumberStyles.Any, + CultureInfo.InvariantCulture, + out d)) { + return d; + } + return 0; + } + + internal decimal? GetXmlNodeDecimalNull(string path) { + decimal d; + if (decimal.TryParse( + GetXmlNodeString(path), + NumberStyles.Any, + CultureInfo.InvariantCulture, + out d)) { + return d; + } + return null; + } + + internal double? GetXmlNodeDoubleNull(string path) { + string s = GetXmlNodeString(path); + if (s == "") { + return null; + } + double v; + if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) { + return v; + } + return null; + } + + internal double GetXmlNodeDouble(string path) { + string s = GetXmlNodeString(path); + if (s == "") { + return double.NaN; + } + double v; + if (double.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out v)) { + return v; + } + return double.NaN; + } + + internal string GetXmlNodeString(XmlNode node, string path) { + if (node == null) { + return ""; + } + + XmlNode nameNode = node.SelectSingleNode(path, NameSpaceManager); + + if (nameNode != null) { + if (nameNode.NodeType == XmlNodeType.Attribute) { + return nameNode.Value != null ? nameNode.Value : ""; + } + return nameNode.InnerText; + } + return ""; + } + + internal string GetXmlNodeString(string path) { + return GetXmlNodeString(TopNode, path); + } + + internal static Uri GetNewUri(ZipPackage package, string sUri) { + return GetNewUri(package, sUri, 1); + } + + internal static Uri GetNewUri(ZipPackage package, string sUri, int id) { + Uri uri; + do { + uri = new(string.Format(sUri, id++), UriKind.Relative); + } while (package.PartExists(uri)); + return uri; + } + + /// <summary> + /// Insert the new node before any of the nodes in the comma separeted list + /// </summary> + /// <param name="parentNode">Parent node</param> + /// <param name="beforeNodes">comma separated list containing nodes to insert after. Left to right order</param> + /// <param name="newNode">The new node to be inserterd</param> + internal void InserAfter(XmlNode parentNode, string beforeNodes, XmlNode newNode) { + string[] nodePaths = beforeNodes.Split(','); + + foreach (string nodePath in nodePaths) { + XmlNode node = parentNode.SelectSingleNode(nodePath, NameSpaceManager); + if (node != null) { + parentNode.InsertAfter(newNode, node); + return; } } - internal string GetXmlNodeString(string path) - { - return GetXmlNodeString(TopNode, path); - } - internal static Uri GetNewUri(Packaging.ZipPackage package, string sUri) - { - return GetNewUri(package, sUri, 1); - } - internal static Uri GetNewUri(Packaging.ZipPackage package, string sUri, int id) - { - Uri uri; - do - { - uri = new Uri(string.Format(sUri, id++), UriKind.Relative); - } - while (package.PartExists(uri)); - return uri; - } - /// <summary> - /// Insert the new node before any of the nodes in the comma separeted list - /// </summary> - /// <param name="parentNode">Parent node</param> - /// <param name="beforeNodes">comma separated list containing nodes to insert after. Left to right order</param> - /// <param name="newNode">The new node to be inserterd</param> - internal void InserAfter(XmlNode parentNode, string beforeNodes, XmlNode newNode) - { - string[] nodePaths = beforeNodes.Split(','); + parentNode.InsertAfter(newNode, null); + } - foreach (string nodePath in nodePaths) - { - XmlNode node = parentNode.SelectSingleNode(nodePath, NameSpaceManager); - if (node != null) - { - parentNode.InsertAfter(newNode, node); - return; - } - } - parentNode.InsertAfter(newNode, null); - } - internal static void LoadXmlSafe(XmlDocument xmlDoc, Stream stream) - { - XmlReaderSettings settings = new XmlReaderSettings(); - //Disable entity parsing (to aviod xmlbombs, External Entity Attacks etc). - settings.ProhibitDtd = true; - XmlReader reader = XmlReader.Create(stream, settings); - xmlDoc.Load(reader); - } - internal static void LoadXmlSafe(XmlDocument xmlDoc, string xml, Encoding encoding) - { - var stream = new MemoryStream(encoding.GetBytes(xml)); - LoadXmlSafe(xmlDoc, stream); - } - } + internal static void LoadXmlSafe(XmlDocument xmlDoc, Stream stream) { + XmlReaderSettings settings = new XmlReaderSettings(); + //Disable entity parsing (to aviod xmlbombs, External Entity Attacks etc). + settings.ProhibitDtd = true; + XmlReader reader = XmlReader.Create(stream, settings); + xmlDoc.Load(reader); + } + + internal static void LoadXmlSafe(XmlDocument xmlDoc, string xml, Encoding encoding) { + var stream = new MemoryStream(encoding.GetBytes(xml)); + LoadXmlSafe(xmlDoc, stream); + } }
diff --git a/EPPlus/XmlHelperFactory.cs b/EPPlus/XmlHelperFactory.cs index b2106a2..0af078b 100644 --- a/EPPlus/XmlHelperFactory.cs +++ b/EPPlus/XmlHelperFactory.cs
@@ -1,4 +1,4 @@ -/******************************************************************************* +/******************************************************************************* * You may amend and distribute as you like, but don't remove this header! * * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. @@ -13,52 +13,41 @@ * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html * - * All code and executables are provided "as is" with no warranty either express or implied. + * All code and executables are provided "as is" with no warranty either express or implied. * The author accepts no liability for any damage or loss of business that this product may cause. * * Code change notes: - * + * * Author Change Date * ****************************************************************************** * Mats Alm Initial Release 2011-05-01 * Jan Källman License changed GPL-->LGPL 2011-12-27 *******************************************************************************/ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; + using System.Xml; -namespace OfficeOpenXml -{ - internal class XmlHelperInstance : XmlHelper - { - internal XmlHelperInstance(XmlNamespaceManager namespaceManager) - : base(namespaceManager) - {} +namespace OfficeOpenXml; - internal XmlHelperInstance(XmlNamespaceManager namespaceManager, XmlNode topNode) - : base(namespaceManager, topNode) - {} +internal class XmlHelperInstance : XmlHelper { + internal XmlHelperInstance(XmlNamespaceManager namespaceManager) + : base(namespaceManager) {} - } + internal XmlHelperInstance(XmlNamespaceManager namespaceManager, XmlNode topNode) + : base(namespaceManager, topNode) {} +} - internal static class XmlHelperFactory - { - internal static XmlHelper Create(XmlNamespaceManager namespaceManager) - { - return new XmlHelperInstance(namespaceManager); - } +internal static class XmlHelperFactory { + internal static XmlHelper Create(XmlNamespaceManager namespaceManager) { + return new XmlHelperInstance(namespaceManager); + } - internal static XmlHelper Create(XmlNamespaceManager namespaceManager, XmlNode topNode) - { - return new XmlHelperInstance(namespaceManager, topNode); - } - } + internal static XmlHelper Create(XmlNamespaceManager namespaceManager, XmlNode topNode) { + return new XmlHelperInstance(namespaceManager, topNode); + } }
diff --git a/NetCoreTests/ExcelPackageTest.cs b/NetCoreTests/ExcelPackageTest.cs index e59278f..975fadc 100644 --- a/NetCoreTests/ExcelPackageTest.cs +++ b/NetCoreTests/ExcelPackageTest.cs
@@ -7,24 +7,21 @@ namespace NetCoreTests; [TestClass] -public class ExcelPackageTest -{ - [TestMethod] - public void TestGetAsByteArray() - { - var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("Times.xlsx"))); - var data = package.GetAsByteArray(); - - // Verify that we can reload - var newPackage = new ExcelPackage(new MemoryStream(data, false)); - newPackage.Workbook.Worksheets.Count.Should().Be(1); - var worksheet = newPackage.Workbook.Worksheets.First(); - worksheet.Name.Should().Be("Times_csv"); - } - - private static string GetTestWorkbookPath(string filename) - { - var assemblyPath = Path.GetDirectoryName(typeof(ExcelPackageTest).Assembly.Location)!; - return Path.Combine(assemblyPath, "TestWorkbooks", filename); - } -} \ No newline at end of file +public class ExcelPackageTest { + [TestMethod] + public void TestGetAsByteArray() { + var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("Times.xlsx"))); + var data = package.GetAsByteArray(); + + // Verify that we can reload + var newPackage = new ExcelPackage(new MemoryStream(data, false)); + newPackage.Workbook.Worksheets.Count.Should().Be(1); + var worksheet = newPackage.Workbook.Worksheets.First(); + worksheet.Name.Should().Be("Times_csv"); + } + + private static string GetTestWorkbookPath(string filename) { + var assemblyPath = Path.GetDirectoryName(typeof(ExcelPackageTest).Assembly.Location)!; + return Path.Combine(assemblyPath, "TestWorkbooks", filename); + } +}
diff --git a/NetCoreTests/NetCoreTests.csproj b/NetCoreTests/NetCoreTests.csproj index 3f11e9f..b5e9414 100644 --- a/NetCoreTests/NetCoreTests.csproj +++ b/NetCoreTests/NetCoreTests.csproj
@@ -4,19 +4,19 @@ <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> - <PackageReference Include="FluentAssertions" Version="6.6.0" /> + <PackageReference Include="FluentAssertions" Version="6.6.0"/> <PackageReference Include="MSTest.TestAdapter" Version="2.2.8"/> - <PackageReference Include="MSTest.TestFramework" Version="2.2.8" /> + <PackageReference Include="MSTest.TestFramework" Version="2.2.8"/> <PackageReference Include="Microsoft.NET.Test.SDK" Version="17.1.0"/> <PackageReference Include="System.Net.Http" Version="4.3.4"/> - <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" /> + <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0"/> <PackageReference Include="System.Text.RegularExpressions" Version="4.3.1"/> - <ProjectReference Include="..\EPPlus\EPPlusSDK.csproj" /> - + <ProjectReference Include="..\EPPlus\EPPlusSDK.csproj"/> + <None Include="TestWorkbooks/**" CopyToOutputDirectory="PreserveNewest"/> <!--Transient dependency; required to address b/230278644--> - <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> + <PackageReference Include="Newtonsoft.Json" Version="13.0.1"/> </ItemGroup> </Project>
diff --git a/NetCoreTests/TimeTest.cs b/NetCoreTests/TimeTest.cs index b207ff0..8ce92f5 100644 --- a/NetCoreTests/TimeTest.cs +++ b/NetCoreTests/TimeTest.cs
@@ -1,4 +1,4 @@ -using System; +using System; using System.IO; using System.Linq; using System.Text; @@ -9,57 +9,52 @@ namespace NetCoreTests; [TestClass] -public class TimeTest -{ - static TimeTest() - { - Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - } - - [TestMethod] - public void TestIncorrectDurationFromOADate() - { - ExcelWorksheet.IncorrectDurationFromOADate(2.75).Should().Be(new(1900, 1, 1, 18, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(1.75).Should().Be(new(1899, 12, 31, 18, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(0.75).Should().Be(new(1899, 12, 30, 18, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(0.5).Should().Be(new(1899, 12, 30, 12, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(0.25).Should().Be(new(1899, 12, 30, 6, 0, 0)); +public class TimeTest { + static TimeTest() { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + } - ExcelWorksheet.IncorrectDurationFromOADate(0).Should().Be(new(1899, 12, 30, 0, 0, 0)); - - ExcelWorksheet.IncorrectDurationFromOADate(-0.25).Should().Be(new(1899, 12, 29, 18, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(-0.5).Should().Be(new(1899, 12, 29, 12, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(-0.75).Should().Be(new(1899, 12, 29, 6, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(-1.75).Should().Be(new(1899, 12, 28, 6, 0, 0)); - ExcelWorksheet.IncorrectDurationFromOADate(-2.75).Should().Be(new(1899, 12, 27, 6, 0, 0)); - } + [TestMethod] + public void TestIncorrectDurationFromOaDate() { + ExcelWorksheet.IncorrectDurationFromOaDate(2.75).Should().Be(new(1900, 1, 1, 18, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(1.75).Should().Be(new(1899, 12, 31, 18, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(0.75).Should().Be(new(1899, 12, 30, 18, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(0.5).Should().Be(new(1899, 12, 30, 12, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(0.25).Should().Be(new(1899, 12, 30, 6, 0, 0)); - [TestMethod] - public void TestDateParse() - { - var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("Times.xlsx"))); - var sheet = package.Workbook.Worksheets.First(); + ExcelWorksheet.IncorrectDurationFromOaDate(0).Should().Be(new(1899, 12, 30, 0, 0, 0)); - sheet.Cells["B3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 30)); - sheet.Cells["C3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 0)); - sheet.Cells["D3"].Value.Should().Be(0.13541666666666666); - sheet.Cells["E3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 30)); - sheet.Cells["F3"].Value.Should().Be(0.13576388888888888); - sheet.Cells["G3"].Value.Should().Be(0.13541666666666666); - sheet.Cells["H3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 30)); - - sheet.Cells["B7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 59)); - sheet.Cells["C7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 0)); - sheet.Cells["D7"].Value.Should().Be(0.9993055555555556); - sheet.Cells["E7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 59)); - sheet.Cells["F7"].Value.Should().Be(0.999988425925926); - sheet.Cells["G7"].Value.Should().Be(0.9993055555555556); - sheet.Cells["H7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 59)); - } + ExcelWorksheet.IncorrectDurationFromOaDate(-0.25).Should().Be(new(1899, 12, 29, 18, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(-0.5).Should().Be(new(1899, 12, 29, 12, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(-0.75).Should().Be(new(1899, 12, 29, 6, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(-1.75).Should().Be(new(1899, 12, 28, 6, 0, 0)); + ExcelWorksheet.IncorrectDurationFromOaDate(-2.75).Should().Be(new(1899, 12, 27, 6, 0, 0)); + } - private static string GetTestWorkbookPath(string filename) - { - var assemblyPath = Path.GetDirectoryName(typeof(TimeTest).Assembly.Location)!; - return Path.Combine(assemblyPath, "TestWorkbooks", filename); - } + [TestMethod] + public void TestDateParse() { + var package = new ExcelPackage(new FileInfo(GetTestWorkbookPath("Times.xlsx"))); + var sheet = package.Workbook.Worksheets.First(); + + sheet.Cells["B3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 30)); + sheet.Cells["C3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 0)); + sheet.Cells["D3"].Value.Should().Be(0.13541666666666666); + sheet.Cells["E3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 30)); + sheet.Cells["F3"].Value.Should().Be(0.13576388888888888); + sheet.Cells["G3"].Value.Should().Be(0.13541666666666666); + sheet.Cells["H3"].Value.Should().Be(new DateTime(1899, 12, 30, 3, 15, 30)); + + sheet.Cells["B7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 59)); + sheet.Cells["C7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 0)); + sheet.Cells["D7"].Value.Should().Be(0.9993055555555556); + sheet.Cells["E7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 59)); + sheet.Cells["F7"].Value.Should().Be(0.999988425925926); + sheet.Cells["G7"].Value.Should().Be(0.9993055555555556); + sheet.Cells["H7"].Value.Should().Be(new DateTime(1899, 12, 30, 23, 59, 59)); + } + + private static string GetTestWorkbookPath(string filename) { + var assemblyPath = Path.GetDirectoryName(typeof(TimeTest).Assembly.Location)!; + return Path.Combine(assemblyPath, "TestWorkbooks", filename); + } }
diff --git a/dotnet-csharpier b/dotnet-csharpier new file mode 100755 index 0000000..61b2200 --- /dev/null +++ b/dotnet-csharpier Binary files differ