diff --git a/ClosedXML/ClosedXML.csproj b/ClosedXML/ClosedXML.csproj
index 893e0dd..0aa0a6a 100644
--- a/ClosedXML/ClosedXML.csproj
+++ b/ClosedXML/ClosedXML.csproj
@@ -68,6 +68,7 @@
+
diff --git a/ClosedXML/Excel/CalcEngine/CalcEngine.cs b/ClosedXML/Excel/CalcEngine/CalcEngine.cs
index 71e3d72..8cc752e 100644
--- a/ClosedXML/Excel/CalcEngine/CalcEngine.cs
+++ b/ClosedXML/Excel/CalcEngine/CalcEngine.cs
@@ -77,18 +77,20 @@
// skip leading equals sign
if (_len > 0 && _expr[0] == '=')
- {
_ptr++;
- }
+
+ // skip leading +'s
+ while (_len > _ptr && _expr[_ptr] == '+')
+ _ptr++;
// parse the expression
var expr = ParseExpression();
// check for errors
- if (_token.ID != TKID.END)
- {
- Throw();
- }
+ if (_token.ID == TKID.OPEN)
+ Throw("Unknown function: " + expr.LastParseItem);
+ else if (_token.ID != TKID.END)
+ Throw("Expected end of expression");
// optimize expression
if (_optimize)
@@ -113,10 +115,9 @@
///
public object Evaluate(string expression)
{
- var x = //Parse(expression);
- _cache != null
- ? _cache[expression]
- : Parse(expression);
+ var x = _cache != null
+ ? _cache[expression]
+ : Parse(expression);
return x.Evaluate();
}
@@ -413,11 +414,11 @@
var pCnt = p == null ? 0 : p.Count;
if (fnDef.ParmMin != -1 && pCnt < fnDef.ParmMin)
{
- Throw("Too few parameters.");
+ Throw(string.Format("Too few parameters for function '{0}'. Expected a minimum of {1} and a maximum of {2}.", id, fnDef.ParmMin, fnDef.ParmMax));
}
if (fnDef.ParmMax != -1 && pCnt > fnDef.ParmMax)
{
- Throw("Too many parameters.");
+ Throw(string.Format("Too many parameters for function '{0}'.Expected a minimum of {1} and a maximum of {2}.", id, fnDef.ParmMin, fnDef.ParmMax));
}
x = new FunctionExpression(fnDef, p);
break;
@@ -713,7 +714,7 @@
if (isEnclosed && disallowedSymbols.Contains(c))
break;
- var allowedSymbols = new List() { '_' };
+ var allowedSymbols = new List() { '_', '.' };
if (!isLetter && !isDigit
&& !(isEnclosed || allowedSymbols.Contains(c))
@@ -771,10 +772,10 @@
}
// make sure the list was closed correctly
- if (_token.ID != TKID.CLOSE)
- {
- Throw();
- }
+ if (_token.ID == TKID.OPEN)
+ Throw("Unknown function: " + expr.LastParseItem);
+ else if (_token.ID != TKID.CLOSE)
+ Throw("Syntax error: expected ')'");
// done
return parms;
@@ -816,7 +817,7 @@
private static void Throw(string msg)
{
- throw new Exception(msg);
+ throw new ExpressionParseException(msg);
}
#endregion ** static helpers
diff --git a/ClosedXML/Excel/CalcEngine/Expression.cs b/ClosedXML/Excel/CalcEngine/Expression.cs
index dcac3c0..9dfdf28 100644
--- a/ClosedXML/Excel/CalcEngine/Expression.cs
+++ b/ClosedXML/Excel/CalcEngine/Expression.cs
@@ -1,11 +1,17 @@
using System;
-using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
+using System.Linq;
+using System.Threading;
namespace ClosedXML.Excel.CalcEngine
{
+ internal abstract class ExpressionBase
+ {
+ public abstract string LastParseItem { get; }
+ }
+
///
/// Base class that represents parsed expressions.
///
@@ -16,34 +22,39 @@
/// object val = expr.Evaluate();
///
///
- internal class Expression : IComparable
+ internal class Expression : ExpressionBase, IComparable
{
//---------------------------------------------------------------------------
+
#region ** fields
- internal Token _token;
+ internal readonly Token _token;
- #endregion
+ #endregion ** fields
//---------------------------------------------------------------------------
+
#region ** ctors
internal Expression()
{
_token = new Token(null, TKID.ATOM, TKTYPE.IDENTIFIER);
}
+
internal Expression(object value)
{
_token = new Token(value, TKID.ATOM, TKTYPE.LITERAL);
}
+
internal Expression(Token tk)
{
_token = tk;
}
- #endregion
+ #endregion ** ctors
//---------------------------------------------------------------------------
+
#region ** object model
public virtual object Evaluate()
@@ -54,14 +65,16 @@
}
return _token.Value;
}
+
public virtual Expression Optimize()
{
return this;
}
- #endregion
+ #endregion ** object model
//---------------------------------------------------------------------------
+
#region ** implicit converters
public static implicit operator string(Expression x)
@@ -69,6 +82,7 @@
var v = x.Evaluate();
return v == null ? string.Empty : v.ToString();
}
+
public static implicit operator double(Expression x)
{
// evaluate
@@ -102,6 +116,7 @@
CultureInfo _ci = Thread.CurrentThread.CurrentCulture;
return (double)Convert.ChangeType(v, typeof(double), _ci);
}
+
public static implicit operator bool(Expression x)
{
// evaluate
@@ -128,6 +143,7 @@
// handle everything else
return (double)x == 0 ? false : true;
}
+
public static implicit operator DateTime(Expression x)
{
// evaluate
@@ -150,9 +166,10 @@
return (DateTime)Convert.ChangeType(v, typeof(DateTime), _ci);
}
- #endregion
+ #endregion ** implicit converters
//---------------------------------------------------------------------------
+
#region ** IComparable
public int CompareTo(Expression other)
@@ -197,15 +214,27 @@
return c1.CompareTo(c2);
}
- #endregion
+ #endregion ** IComparable
+
+ //---------------------------------------------------------------------------
+
+ #region ** ExpressionBase
+
+ public override string LastParseItem
+ {
+ get { return _token?.Value?.ToString() ?? "Unknown value"; }
+ }
+
+ #endregion ** ExpressionBase
}
+
///
/// Unary expression, e.g. +123
///
- class UnaryExpression : Expression
+ internal class UnaryExpression : Expression
{
// ** fields
- Expression _expr;
+ private Expression _expr;
// ** ctor
public UnaryExpression(Token tk, Expression expr) : base(tk)
@@ -220,11 +249,13 @@
{
case TKID.ADD:
return +(double)_expr;
+
case TKID.SUB:
return -(double)_expr;
}
throw new ArgumentException("Bad expression.");
}
+
public override Expression Optimize()
{
_expr = _expr.Optimize();
@@ -232,20 +263,27 @@
? new Expression(this.Evaluate())
: this;
}
+
+ public override string LastParseItem
+ {
+ get { return _expr.LastParseItem; }
+ }
}
+
///
/// Binary expression, e.g. 1+2
///
- class BinaryExpression : Expression
+ internal class BinaryExpression : Expression
{
// ** fields
- Expression _lft;
- Expression _rgt;
+ private Expression _lft;
+
+ private Expression _rgt;
// ** ctor
public BinaryExpression(Token tk, Expression exprLeft, Expression exprRight) : base(tk)
{
- _lft = exprLeft;
+ _lft = exprLeft;
_rgt = exprRight;
}
@@ -272,18 +310,25 @@
{
case TKID.CONCAT:
return (string)_lft + (string)_rgt;
+
case TKID.ADD:
return (double)_lft + (double)_rgt;
+
case TKID.SUB:
return (double)_lft - (double)_rgt;
+
case TKID.MUL:
return (double)_lft * (double)_rgt;
+
case TKID.DIV:
return (double)_lft / (double)_rgt;
+
case TKID.DIVINT:
return (double)(int)((double)_lft / (double)_rgt);
+
case TKID.MOD:
return (double)(int)((double)_lft % (double)_rgt);
+
case TKID.POWER:
var a = (double)_lft;
var b = (double)_rgt;
@@ -297,6 +342,7 @@
}
throw new ArgumentException("Bad expression.");
}
+
public override Expression Optimize()
{
_lft = _lft.Optimize();
@@ -305,20 +351,27 @@
? new Expression(this.Evaluate())
: this;
}
+
+ public override string LastParseItem
+ {
+ get { return _rgt.LastParseItem; }
+ }
}
+
///
/// Function call expression, e.g. sin(0.5)
///
- class FunctionExpression : Expression
+ internal class FunctionExpression : Expression
{
// ** fields
- FunctionDefinition _fn;
- List _parms;
+ private readonly FunctionDefinition _fn;
+
+ private readonly List _parms;
// ** ctor
internal FunctionExpression()
- {
- }
+ { }
+
public FunctionExpression(FunctionDefinition function, List parms)
{
_fn = function;
@@ -330,6 +383,7 @@
{
return _fn.Function(_parms);
}
+
public override Expression Optimize()
{
bool allLits = true;
@@ -349,33 +403,46 @@
? new Expression(this.Evaluate())
: this;
}
+
+ public override string LastParseItem
+ {
+ get { return _parms.Last().LastParseItem; }
+ }
}
+
///
/// Simple variable reference.
///
- class VariableExpression : Expression
+ internal class VariableExpression : Expression
{
- Dictionary _dct;
- string _name;
+ private readonly Dictionary _dct;
+ private readonly string _name;
public VariableExpression(Dictionary dct, string name)
{
_dct = dct;
_name = name;
}
+
public override object Evaluate()
{
return _dct[_name];
}
+
+ public override string LastParseItem
+ {
+ get { return _name; }
+ }
}
+
///
/// Expression that represents an external object.
///
- class XObjectExpression :
+ internal class XObjectExpression :
Expression,
IEnumerable
{
- object _value;
+ private readonly object _value;
// ** ctor
internal XObjectExpression(object value)
@@ -398,18 +465,29 @@
// return raw object
return _value;
}
+
public IEnumerator GetEnumerator()
{
return (_value as IEnumerable).GetEnumerator();
}
+
+ public override string LastParseItem
+ {
+ get { return Value.ToString(); }
+ }
}
///
/// Expression that represents an omitted parameter.
///
- class EmptyValueExpression : Expression
+ internal class EmptyValueExpression : Expression
{
internal EmptyValueExpression() { }
+
+ public override string LastParseItem
+ {
+ get { return ""; }
+ }
}
///
diff --git a/ClosedXML/Excel/CalcEngine/ExpressionParseException.cs b/ClosedXML/Excel/CalcEngine/ExpressionParseException.cs
new file mode 100644
index 0000000..2de2293
--- /dev/null
+++ b/ClosedXML/Excel/CalcEngine/ExpressionParseException.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Text;
+
+namespace ClosedXML.Excel.CalcEngine
+{
+ ///
+ /// The exception that is thrown when the strings to be parsed to an expression is invalid.
+ ///
+ public class ExpressionParseException : Exception
+ {
+ ///
+ /// Initializes a new instance of the ExpressionParseException class with a
+ /// specified error message.
+ ///
+ /// The message that describes the error.
+ public ExpressionParseException(string message)
+ : base(message)
+ {
+ }
+ }
+}
diff --git a/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs b/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs
index 8a9ac19..964e72b 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/Lookup.cs
@@ -15,7 +15,7 @@
//ce.RegisterFunction("COLUMNS", , Columns); // Returns the number of columns in a reference
//ce.RegisterFunction("FORMULATEXT", , Formulatext); // Returns the formula at the given reference as text
//ce.RegisterFunction("GETPIVOTDATA", , Getpivotdata); // Returns data stored in a PivotTable report
- ce.RegisterFunction("HLOOKUP", 4, Hlookup); // Looks in the top row of an array and returns the value of the indicated cell
+ ce.RegisterFunction("HLOOKUP", 3, 4, Hlookup); // Looks in the top row of an array and returns the value of the indicated cell
//ce.RegisterFunction("HYPERLINK", , Hyperlink); // Creates a shortcut or jump that opens a document stored on a network server, an intranet, or the Internet
//ce.RegisterFunction("INDEX", , Index); // Uses an index to choose a value from a reference or array
//ce.RegisterFunction("INDIRECT", , Indirect); // Returns a reference indicated by a text value
@@ -26,7 +26,7 @@
//ce.RegisterFunction("ROWS", , Rows); // Returns the number of rows in a reference
//ce.RegisterFunction("RTD", , Rtd); // Retrieves real-time data from a program that supports COM automation
//ce.RegisterFunction("TRANSPOSE", , Transpose); // Returns the transpose of an array
- ce.RegisterFunction("VLOOKUP", 4, Vlookup); // Looks in the first column of an array and moves across the row to return the value of a cell
+ ce.RegisterFunction("VLOOKUP", 3, 4, Vlookup); // Looks in the first column of an array and moves across the row to return the value of a cell
}
private static object Hlookup(List p)
@@ -34,20 +34,25 @@
var lookup_value = p[0];
var table_array = p[1] as XObjectExpression;
+ if (table_array == null)
+ throw new ArgumentException("table_array has to be a range");
+
var range_reference = table_array.Value as CellRangeReference;
+ if (range_reference == null)
+ throw new ArgumentException("table_array has to be a range");
+
var range = range_reference.Range;
var row_index_num = (int)(p[2]);
- var range_lookup = p.Count < 4 || (bool)(p[3]);
-
- if (table_array == null || range_reference == null)
- throw new ApplicationException("table_array has to be a range");
+ var range_lookup = p.Count < 4
+ || p[3] is EmptyValueExpression
+ || (bool)(p[3]);
if (row_index_num < 1)
- throw new ApplicationException("col_index_num has to be positive");
+ throw new ArgumentOutOfRangeException("Row index", "row_index_num has to be positive");
if (row_index_num > range.RowCount())
- throw new ApplicationException("col_index_num must be smaller or equal to the number of rows in the table array");
+ throw new ArgumentOutOfRangeException("Row index", "row_index_num has to be positive");
IXLRangeColumn matching_column;
matching_column = range.FindColumn(c => !c.Cell(1).IsEmpty() && new Expression(c.Cell(1).Value).CompareTo(lookup_value) == 0);
@@ -67,7 +72,7 @@
}
if (matching_column == null)
- throw new ApplicationException("No matches found.");
+ throw new ArgumentException("No matches found.");
return matching_column
.Cell(row_index_num)
@@ -79,20 +84,25 @@
var lookup_value = p[0];
var table_array = p[1] as XObjectExpression;
+ if (table_array == null)
+ throw new ArgumentException("table_array has to be a range");
+
var range_reference = table_array.Value as CellRangeReference;
+ if (range_reference == null)
+ throw new ArgumentException("table_array has to be a range");
+
var range = range_reference.Range;
var col_index_num = (int)(p[2]);
- var range_lookup = p.Count < 4 || (bool)(p[3]);
-
- if (table_array == null || range_reference == null)
- throw new ApplicationException("table_array has to be a range");
+ var range_lookup = p.Count < 4
+ || p[3] is EmptyValueExpression
+ || (bool)(p[3]);
if (col_index_num < 1)
- throw new ApplicationException("col_index_num has to be positive");
+ throw new ArgumentOutOfRangeException("Column index", "col_index_num has to be positive");
if (col_index_num > range.ColumnCount())
- throw new ApplicationException("col_index_num must be smaller or equal to the number of columns in the table array");
+ throw new ArgumentOutOfRangeException("Column index", "col_index_num must be smaller or equal to the number of columns in the table array");
IXLRangeRow matching_row;
matching_row = range.FindRow(r => !r.Cell(1).IsEmpty() && new Expression(r.Cell(1).Value).CompareTo(lookup_value) == 0);
@@ -112,7 +122,7 @@
}
if (matching_row == null)
- throw new ApplicationException("No matches found.");
+ throw new ArgumentException("No matches found.");
return matching_row
.Cell(col_index_num)
diff --git a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
index c4e86ca..12e0995 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/MathTrig.cs
@@ -1,8 +1,8 @@
+using ClosedXML.Excel.CalcEngine.Functions;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
-using ClosedXML.Excel.CalcEngine.Functions;
namespace ClosedXML.Excel.CalcEngine
{
@@ -29,7 +29,8 @@
ce.RegisterFunction("EXP", 1, Exp);
ce.RegisterFunction("FACT", 1, Fact);
ce.RegisterFunction("FACTDOUBLE", 1, FactDouble);
- ce.RegisterFunction("FLOOR", 1, Floor);
+ ce.RegisterFunction("FLOOR", 1, 2, Floor);
+ ce.RegisterFunction("FLOOR.MATH", 1, 3, FloorMath);
ce.RegisterFunction("GCD", 1, 255, Gcd);
ce.RegisterFunction("INT", 1, Int);
ce.RegisterFunction("LCM", 1, 255, Lcm);
@@ -120,12 +121,44 @@
private static object Floor(List p)
{
- return Math.Floor(p[0]);
+ double number = p[0];
+ double significance = 1;
+ if (p.Count > 1)
+ significance = p[1];
+
+ if (significance < 0)
+ {
+ number = -number;
+ significance = -significance;
+
+ return -Math.Floor(number / significance) * significance;
+ }
+ else if (significance == 1)
+ return Math.Floor(number);
+ else
+ return Math.Floor(number / significance) * significance;
+ }
+
+ private static object FloorMath(List p)
+ {
+ double number = p[0];
+ double significance = 1;
+ if (p.Count > 1) significance = p[1];
+
+ double mode = 0;
+ if (p.Count > 2) mode = p[2];
+
+ if (number >= 0)
+ return Math.Floor(number / Math.Abs(significance)) * Math.Abs(significance);
+ else if (mode >= 0)
+ return Math.Floor(number / Math.Abs(significance)) * Math.Abs(significance);
+ else
+ return -Math.Floor(-number / Math.Abs(significance)) * Math.Abs(significance);
}
private static object Int(List p)
{
- return (int) ((double) p[0]);
+ return (int)((double)p[0]);
}
private static object Ln(List p)
@@ -135,7 +168,7 @@
private static object Log(List p)
{
- var lbase = p.Count > 1 ? (double) p[1] : 10;
+ var lbase = p.Count > 1 ? (double)p[1] : 10;
return Math.Log(p[0], lbase);
}
@@ -161,7 +194,7 @@
private static object RandBetween(List p)
{
- return _rnd.Next((int) (double) p[0], (int) (double) p[1]);
+ return _rnd.Next((int)(double)p[0], (int)(double)p[1]);
}
private static object Sign(List p)
@@ -240,42 +273,42 @@
private static object Trunc(List p)
{
- return (double) (int) ((double) p[0]);
+ return (double)(int)((double)p[0]);
}
public static double DegreesToRadians(double degrees)
{
- return (Math.PI/180.0)*degrees;
+ return (Math.PI / 180.0) * degrees;
}
public static double RadiansToDegrees(double radians)
{
- return (180.0/Math.PI)*radians;
+ return (180.0 / Math.PI) * radians;
}
public static double GradsToRadians(double grads)
{
- return (grads/200.0)*Math.PI;
+ return (grads / 200.0) * Math.PI;
}
public static double RadiansToGrads(double radians)
{
- return (radians/Math.PI)*200.0;
+ return (radians / Math.PI) * 200.0;
}
public static double DegreesToGrads(double degrees)
{
- return (degrees/9.0)*10.0;
+ return (degrees / 9.0) * 10.0;
}
public static double GradsToDegrees(double grads)
{
- return (grads/10.0)*9.0;
+ return (grads / 10.0) * 9.0;
}
public static double ASinh(double x)
{
- return (Math.Log(x + Math.Sqrt(x*x + 1.0)));
+ return (Math.Log(x + Math.Sqrt(x * x + 1.0)));
}
private static object Acosh(List p)
@@ -295,8 +328,8 @@
private static object Combin(List p)
{
- Int32 n = (int) p[0];
- Int32 k = (int) p[1];
+ Int32 n = (int)p[0];
+ Int32 k = (int)p[1];
return XLMath.Combin(n, k);
}
@@ -305,8 +338,6 @@
return p[0] * (180.0 / Math.PI);
}
-
-
private static object Fact(List p)
{
var num = Math.Floor(p[0]);
@@ -348,15 +379,15 @@
private static int Lcm(int a, int b)
{
if (a == 0 || b == 0) return 0;
- return a * ( b / Gcd(a, b));
+ return a * (b / Gcd(a, b));
}
private static object Mod(List p)
{
- Int32 n = (int)Math.Abs(p[0]);
- Int32 d = (int)p[1];
- var ret = n % d;
- return d < 0 ? ret * -1 : ret;
+ double number = p[0];
+ double divisor = p[1];
+
+ return number - Math.Floor(number / divisor) * divisor;
}
private static object MRound(List p)
@@ -479,7 +510,6 @@
temp = Math.Round(temp, 0, MidpointRounding.AwayFromZero);
return temp * Math.Pow(10, digits);
}
-
}
private static object RoundDown(List p)
@@ -512,7 +542,7 @@
var obj = p[3] as XObjectExpression;
if (obj == null)
- return p[3] * Math.Pow(x , n);
+ return p[3] * Math.Pow(x, n);
Double total = 0;
Int32 i = 0;
@@ -540,26 +570,37 @@
{
case 1:
return tally.Average();
+
case 2:
return tally.Count(true);
+
case 3:
return tally.Count(false);
+
case 4:
return tally.Max();
+
case 5:
return tally.Min();
+
case 6:
return tally.Product();
+
case 7:
return tally.Std();
+
case 8:
return tally.StdP();
+
case 9:
return tally.Sum();
+
case 10:
return tally.Var();
+
case 11:
return tally.VarP();
+
default:
throw new ArgumentException("Function not supported.");
}
@@ -591,19 +632,18 @@
}
}
-
return C;
}
private static double[,] GetArray(Expression expression)
{
var oExp1 = expression as XObjectExpression;
- if (oExp1 == null) return new [,]{{(Double)expression}};
+ if (oExp1 == null) return new[,] { { (Double)expression } };
var range = (oExp1.Value as CellRangeReference).Range;
var rowCount = range.RowCount();
var columnCount = range.ColumnCount();
- var arr = new double[rowCount,columnCount];
+ var arr = new double[rowCount, columnCount];
for (int row = 0; row < rowCount; row++)
{
diff --git a/ClosedXML/Excel/CalcEngine/Functions/Text.cs b/ClosedXML/Excel/CalcEngine/Functions/Text.cs
index cb66322..6046455 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/Text.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/Text.cs
@@ -76,7 +76,7 @@
}
var index = text.IndexOf(srch, start, StringComparison.Ordinal);
if (index == -1)
- throw new Exception("String not found.");
+ throw new ArgumentException("String not found.");
else
return index + 1;
}
@@ -192,7 +192,7 @@
var search = WildcardToRegex((string)p[0]);
var text = (string)p[1];
- if ("" == text) throw new Exception("Invalid input string.");
+ if ("" == text) throw new ArgumentException("Invalid input string.");
var start = 0;
if (p.Count > 2)
@@ -203,12 +203,12 @@
Regex r = new Regex(search, RegexOptions.Compiled | RegexOptions.IgnoreCase);
var match = r.Match(text.Substring(start));
if (!match.Success)
- throw new Exception("Search failed.");
+ throw new ArgumentException("Search failed.");
else
return match.Index + start + 1;
//var index = text.IndexOf(search, start, StringComparison.OrdinalIgnoreCase);
//if (index == -1)
- // throw new Exception("String not found.");
+ // throw new ArgumentException("String not found.");
//else
// return index + 1;
}
@@ -233,7 +233,7 @@
int index = (int)p[3];
if (index < 1)
{
- throw new Exception("Invalid index in Substitute.");
+ throw new ArgumentException("Invalid index in Substitute.");
}
int pos = text.IndexOf(oldText);
while (pos > -1 && index > 1)
diff --git a/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs b/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs
index 80d2663..79d6a70 100644
--- a/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs
+++ b/ClosedXML/Excel/CalcEngine/Functions/XLMatrix.cs
@@ -59,7 +59,7 @@
public void MakeLU() // Function for LU decomposition
{
- if (!IsSquare()) throw new Exception("The matrix is not square!");
+ if (!IsSquare()) throw new InvalidOperationException("The matrix is not square!");
L = IdentityMatrix(rows, cols);
U = Duplicate();
@@ -79,8 +79,8 @@
k0 = i;
}
}
- if (p == 0)
- throw new Exception("The matrix is singular!");
+ if (p == 0)
+ throw new InvalidOperationException("The matrix is singular!");
var pom1 = pi[k];
pi[k] = pi[k0];
@@ -115,8 +115,8 @@
public XLMatrix SolveWith(XLMatrix v) // Function solves Ax = v in confirmity with solution vector "v"
{
- if (rows != cols) throw new Exception("The matrix is not square!");
- if (rows != v.rows) throw new Exception("Wrong number of results in solution vector!");
+ if (rows != cols) throw new InvalidOperationException("The matrix is not square!");
+ if (rows != v.rows) throw new ArgumentException("Wrong number of results in solution vector!");
if (L == null) MakeLU();
var b = new XLMatrix(rows, 1);
@@ -242,9 +242,9 @@
for (var j = 0; j < nums.Length; j++) matrix[i, j] = double.Parse(nums[j]);
}
}
- catch (FormatException)
+ catch (FormatException fe)
{
- throw new Exception("Wrong input format!");
+ throw new FormatException("Wrong input format!", fe);
}
return matrix;
}
@@ -345,7 +345,7 @@
private static XLMatrix StrassenMultiply(XLMatrix A, XLMatrix B) // Smart matrix multiplication
{
- if (A.cols != B.rows) throw new Exception("Wrong dimension of matrix!");
+ if (A.cols != B.rows) throw new ArgumentException("Wrong dimension of matrix!");
XLMatrix R;
@@ -513,7 +513,7 @@
public static XLMatrix StupidMultiply(XLMatrix m1, XLMatrix m2) // Stupid matrix multiplication
{
- if (m1.cols != m2.rows) throw new Exception("Wrong dimensions of matrix!");
+ if (m1.cols != m2.rows) throw new ArgumentException("Wrong dimensions of matrix!");
var result = ZeroMatrix(m1.rows, m2.cols);
for (var i = 0; i < result.rows; i++)
@@ -535,7 +535,7 @@
private static XLMatrix Add(XLMatrix m1, XLMatrix m2)
{
if (m1.rows != m2.rows || m1.cols != m2.cols)
- throw new Exception("Matrices must have the same dimensions!");
+ throw new ArgumentException("Matrices must have the same dimensions!");
var r = new XLMatrix(m1.rows, m1.cols);
for (var i = 0; i < r.rows; i++)
for (var j = 0; j < r.cols; j++)
diff --git a/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs b/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs
index 6d5dc53..108ea40 100644
--- a/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs
+++ b/ClosedXML/Excel/CalcEngine/XLCalcEngine.cs
@@ -92,7 +92,7 @@
{
if (_evaluating)
{
- throw new Exception("Circular Reference");
+ throw new InvalidOperationException("Circular Reference");
}
try
{
diff --git a/ClosedXML/Excel/Cells/IXLCell.cs b/ClosedXML/Excel/Cells/IXLCell.cs
index d685041..9e82e5a 100644
--- a/ClosedXML/Excel/Cells/IXLCell.cs
+++ b/ClosedXML/Excel/Cells/IXLCell.cs
@@ -173,6 +173,14 @@
IXLRange InsertData(IEnumerable data);
///
+ /// Inserts the IEnumerable data elements and returns the range it occupies.
+ ///
+ /// The IEnumerable data.
+ /// if set to true the data will be transposed before inserting.
+ ///
+ IXLRange InsertData(IEnumerable data, Boolean tranpose);
+
+ ///
/// Inserts the IEnumerable data elements as a table and returns it.
/// The new table will receive a generic name: Table#
///
@@ -260,7 +268,7 @@
IXLCells InsertCellsBefore(int numberOfColumns);
///
- /// Creates a named range out of this cell.
+ /// Creates a named range out of this cell.
/// If the named range exists, it will add this range to that named range.
/// The default scope for the named range is Workbook.
///
@@ -268,7 +276,7 @@
IXLCell AddToNamed(String rangeName);
///
- /// Creates a named range out of this cell.
+ /// Creates a named range out of this cell.
/// If the named range exists, it will add this range to that named range.
/// Name of the range.
/// The scope for the named range.
@@ -276,7 +284,7 @@
IXLCell AddToNamed(String rangeName, XLScope scope);
///
- /// Creates a named range out of this cell.
+ /// Creates a named range out of this cell.
/// If the named range exists, it will add this range to that named range.
/// Name of the range.
/// The scope for the named range.
diff --git a/ClosedXML/Excel/Cells/XLCell.cs b/ClosedXML/Excel/Cells/XLCell.cs
index fc5db80..ae3d84c 100644
--- a/ClosedXML/Excel/Cells/XLCell.cs
+++ b/ClosedXML/Excel/Cells/XLCell.cs
@@ -1,4 +1,4 @@
-using FastMember;
+using FastMember;
using System;
using System.Collections;
using System.Collections.Generic;
@@ -221,6 +221,9 @@
public IXLCell SetValue(T value)
{
+ if (value == null)
+ return this.Clear(XLClearOptions.Contents);
+
FormulaA1 = String.Empty;
_richText = null;
var style = GetStyleForRead();
@@ -281,7 +284,7 @@
if (TryGetValue(out retVal))
return retVal;
- throw new Exception("Cannot convert cell value to " + typeof(T));
+ throw new FormatException("Cannot convert cell value to " + typeof(T));
}
public string GetString()
@@ -438,6 +441,8 @@
if (value as XLCells != null) throw new ArgumentException("Cannot assign IXLCells object to the cell value.");
+ if (SetTableHeader(value)) return;
+
if (SetRangeRows(value)) return;
if (SetRangeColumns(value)) return;
@@ -470,7 +475,7 @@
public IXLTable InsertTable(IEnumerable data, string tableName, bool createTable)
{
- if (data != null && data.GetType() != typeof(String))
+ if (data != null && !(data is String))
{
var ro = Address.RowNumber + 1;
var fRo = Address.RowNumber;
@@ -713,10 +718,18 @@
public IXLRange InsertData(IEnumerable data)
{
- if (data != null && data.GetType() != typeof(String))
+ return InsertData(data, false);
+ }
+
+ public IXLRange InsertData(IEnumerable data, Boolean transpose)
+ {
+ if (data != null && !(data is String))
{
- var ro = Address.RowNumber;
- var maxCo = 0;
+ var rowNumber = Address.RowNumber;
+ var columnNumber = Address.ColumnNumber;
+
+ var maxColumnNumber = 0;
+ var maxRowNumber = 0;
var isDataTable = false;
var isDataReader = false;
@@ -745,20 +758,31 @@
members = memberCache[itemType];
accessor = accessorCache[itemType];
- var co = Address.ColumnNumber;
+ if (transpose)
+ rowNumber = Address.RowNumber;
+ else
+ columnNumber = Address.ColumnNumber;
+
if (itemType.IsPrimitive || itemType == typeof(String) || itemType == typeof(DateTime) || itemType.IsNumber())
{
- SetValue(m, ro, co);
- co++;
+ SetValue(m, rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
else if (itemType.IsArray)
{
- // dynamic arr = m;
foreach (var item in (Array)m)
{
- SetValue(item, ro, co);
- co++;
+ SetValue(item, rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
else if (isDataTable || m is DataRow)
@@ -768,8 +792,12 @@
foreach (var item in (m as DataRow).ItemArray)
{
- SetValue(item, ro, co);
- co++;
+ SetValue(item, rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
else if (isDataReader || m is IDataRecord)
@@ -782,31 +810,45 @@
var fieldCount = record.FieldCount;
for (var i = 0; i < fieldCount; i++)
{
- SetValue(record[i], ro, co);
- co++;
+ SetValue(record[i], rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
else
{
foreach (var mi in members)
{
- SetValue(accessor[m, mi.Name], ro, co);
- co++;
+ SetValue(accessor[m, mi.Name], rowNumber, columnNumber);
+
+ if (transpose)
+ rowNumber++;
+ else
+ columnNumber++;
}
}
- if (co > maxCo)
- maxCo = co;
+ if (transpose)
+ columnNumber++;
+ else
+ rowNumber++;
- ro++;
+ if (columnNumber > maxColumnNumber)
+ maxColumnNumber = columnNumber;
+
+ if (rowNumber > maxRowNumber)
+ maxRowNumber = rowNumber;
}
ClearMerged();
return _worksheet.Range(
Address.RowNumber,
Address.ColumnNumber,
- ro - 1,
- maxCo - 1);
+ maxRowNumber - 1,
+ maxColumnNumber - 1);
}
return null;
@@ -1450,6 +1492,23 @@
#endregion IXLStylized Members
+ private bool SetTableHeader(object value)
+ {
+ foreach (var table in Worksheet.Tables.Where(t => t.ShowHeaderRow))
+ {
+ var cells = table.HeadersRow().CellsUsed(c => c.Address.Equals(this.Address));
+ if (cells.Any())
+ {
+ var oldName = cells.First().GetString();
+ var field = table.Field(oldName);
+ field.Name = value.ToString();
+ return true;
+ }
+ }
+
+ return false;
+ }
+
private bool SetRangeColumns(object value)
{
var columns = value as XLRangeColumns;
@@ -1620,7 +1679,7 @@
private bool SetEnumerable(object collectionObject)
{
// IXLRichText implements IEnumerable, but we don't want to handle this here.
- if ((collectionObject as IXLRichText) != null) return false;
+ if (collectionObject is IXLRichText) return false;
var asEnumerable = collectionObject as IEnumerable;
return InsertData(asEnumerable) != null;
@@ -1639,13 +1698,10 @@
{
if (value == null)
_worksheet.Cell(ro, co).SetValue(String.Empty);
+ else if (value is IConvertible)
+ _worksheet.Cell(ro, co).SetValue((T)Convert.ChangeType(value, typeof(T)));
else
- {
- if (value is IConvertible)
- _worksheet.Cell(ro, co).SetValue((T)Convert.ChangeType(value, typeof(T)));
- else
- _worksheet.Cell(ro, co).SetValue(value);
- }
+ _worksheet.Cell(ro, co).SetValue(value);
}
private void SetValue(object value)
diff --git a/ClosedXML/Excel/Columns/XLColumn.cs b/ClosedXML/Excel/Columns/XLColumn.cs
index b8036d4..f106457 100644
--- a/ClosedXML/Excel/Columns/XLColumn.cs
+++ b/ClosedXML/Excel/Columns/XLColumn.cs
@@ -786,5 +786,15 @@
return base.IsEmpty(includeFormats);
}
+
+ public Boolean IsEntireRow()
+ {
+ return false;
+ }
+
+ public Boolean IsEntireColumn()
+ {
+ return true;
+ }
}
}
diff --git a/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs b/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs
index f0bd151..ff2d3c0 100644
--- a/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs
+++ b/ClosedXML/Excel/ConditionalFormats/Save/XLCFDataBarConverter.cs
@@ -7,20 +7,32 @@
namespace ClosedXML.Excel
{
- internal class XLCFDataBarConverter:IXLCFConverter
+ internal class XLCFDataBarConverter : IXLCFConverter
{
public ConditionalFormattingRule Convert(IXLConditionalFormat cf, Int32 priority, XLWorkbook.SaveContext context)
{
var conditionalFormattingRule = new ConditionalFormattingRule { Type = cf.ConditionalFormatType.ToOpenXml(), Priority = priority };
- var dataBar = new DataBar {ShowValue = !cf.ShowBarOnly};
- var conditionalFormatValueObject1 = new ConditionalFormatValueObject { Type = cf.ContentTypes[1].ToOpenXml()};
- if (cf.Values.Count >= 1) conditionalFormatValueObject1.Val = cf.Values[1].Value;
+ var dataBar = new DataBar { ShowValue = !cf.ShowBarOnly };
+ var conditionalFormatValueObject1 = new ConditionalFormatValueObject { Type = cf.ContentTypes[1].ToOpenXml() };
+ if (cf.Values.Any() && cf.Values[1]?.Value != null) conditionalFormatValueObject1.Val = cf.Values[1].Value;
- var conditionalFormatValueObject2 = new ConditionalFormatValueObject { Type = cf.ContentTypes[2].ToOpenXml()};
- if (cf.Values.Count >= 2) conditionalFormatValueObject2.Val = cf.Values[2].Value;
+ var conditionalFormatValueObject2 = new ConditionalFormatValueObject { Type = cf.ContentTypes[2].ToOpenXml() };
+ if (cf.Values.Count >= 2 && cf.Values[2]?.Value != null) conditionalFormatValueObject2.Val = cf.Values[2].Value;
- var color = new Color { Rgb = cf.Colors[1].Color.ToHex() };
+ var color = new Color();
+ switch (cf.Colors[1].ColorType)
+ {
+ case XLColorType.Color:
+ color.Rgb = cf.Colors[1].Color.ToHex();
+ break;
+ case XLColorType.Theme:
+ color.Theme = System.Convert.ToUInt32(cf.Colors[1].ThemeColor);
+ break;
+ case XLColorType.Indexed:
+ color.Indexed = System.Convert.ToUInt32(cf.Colors[1].Indexed);
+ break;
+ }
dataBar.Append(conditionalFormatValueObject1);
dataBar.Append(conditionalFormatValueObject2);
diff --git a/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs b/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs
index a7b191f..f3f7304 100644
--- a/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs
+++ b/ClosedXML/Excel/NamedRanges/XLNamedRanges.cs
@@ -69,10 +69,16 @@
if (!match.Success)
{
- if (Worksheet == null || !XLHelper.NamedRangeReferenceRegex.Match(Worksheet.Range(rangeAddress).ToString()).Success)
- throw new ArgumentException("For named ranges in the workbook scope, specify the sheet name in the reference.");
+ var range = Worksheet?.Range(rangeAddress) ?? Workbook.Range(rangeAddress);
+ if (range == null)
+ throw new ArgumentException(string.Format("The range address '{0}' for the named range '{1}' is not a valid range.", rangeAddress, rangeName));
else
- rangeAddress = Worksheet.Range(rangeAddress).ToString();
+ {
+ if (Worksheet == null || !XLHelper.NamedRangeReferenceRegex.Match(range.ToString()).Success)
+ throw new ArgumentException("For named ranges in the workbook scope, specify the sheet name in the reference.");
+ else
+ rangeAddress = Worksheet.Range(rangeAddress).ToString();
+ }
}
}
diff --git a/ClosedXML/Excel/Ranges/IXLRangeBase.cs b/ClosedXML/Excel/Ranges/IXLRangeBase.cs
index 76902d0..064d975 100644
--- a/ClosedXML/Excel/Ranges/IXLRangeBase.cs
+++ b/ClosedXML/Excel/Ranges/IXLRangeBase.cs
@@ -1,4 +1,5 @@
using System;
+using System.Globalization;
namespace ClosedXML.Excel
{
@@ -8,7 +9,7 @@
Worksheet
}
- public interface IXLRangeBase: IDisposable
+ public interface IXLRangeBase : IDisposable
{
IXLWorksheet Worksheet { get; }
@@ -64,7 +65,6 @@
IXLHyperlinks Hyperlinks { get; }
-
///
/// Returns the collection of cells.
///
@@ -94,6 +94,15 @@
IXLCells CellsUsed(Boolean includeFormats, Func predicate);
///
+ /// Searches the cells' contents for a given piece of text
+ ///
+ /// The search text.
+ /// The compare options.
+ /// if set to true search formulae instead of cell values.
+ ///
+ IXLCells Search(String searchText, CompareOptions compareOptions = CompareOptions.Ordinal, Boolean searchFormulae = false);
+
+ ///
/// Returns the first cell of this range.
///
IXLCell FirstCell();
@@ -236,15 +245,19 @@
IXLRange AsRange();
Boolean IsMerged();
+
Boolean IsEmpty();
+
Boolean IsEmpty(Boolean includeFormats);
+ Boolean IsEntireRow();
+
+ Boolean IsEntireColumn();
IXLPivotTable CreatePivotTable(IXLCell targetCell);
+
IXLPivotTable CreatePivotTable(IXLCell targetCell, String name);
-
-
//IXLChart CreateChart(Int32 firstRow, Int32 firstColumn, Int32 lastRow, Int32 lastColumn);
IXLAutoFilter SetAutoFilter();
diff --git a/ClosedXML/Excel/Ranges/XLRangeAddress.cs b/ClosedXML/Excel/Ranges/XLRangeAddress.cs
index df631ec..fbe5135 100644
--- a/ClosedXML/Excel/Ranges/XLRangeAddress.cs
+++ b/ClosedXML/Excel/Ranges/XLRangeAddress.cs
@@ -84,7 +84,7 @@
get
{
if (IsInvalid)
- throw new Exception("Range is invalid.");
+ throw new InvalidOperationException("Range is invalid.");
return _firstAddress;
}
@@ -96,7 +96,7 @@
get
{
if (IsInvalid)
- throw new Exception("Range is an invalid state.");
+ throw new InvalidOperationException("Range is an invalid state.");
return _lastAddress;
}
diff --git a/ClosedXML/Excel/Ranges/XLRangeBase.cs b/ClosedXML/Excel/Ranges/XLRangeBase.cs
index 9e9b20e..b08cda8 100644
--- a/ClosedXML/Excel/Ranges/XLRangeBase.cs
+++ b/ClosedXML/Excel/Ranges/XLRangeBase.cs
@@ -2,36 +2,39 @@
using ClosedXML.Extensions;
using System;
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
-
-
namespace ClosedXML.Excel
{
internal abstract class XLRangeBase : IXLRangeBase, IXLStylized
{
public Boolean StyleChanged { get; set; }
+
#region Fields
private IXLStyle _style;
private XLSortElements _sortRows;
private XLSortElements _sortColumns;
- #endregion
+ #endregion Fields
private Int32 _styleCacheId;
+
protected void SetStyle(IXLStyle styleToUse)
{
_styleCacheId = Worksheet.Workbook.GetStyleId(styleToUse);
_style = null;
StyleChanged = false;
}
+
protected void SetStyle(Int32 styleId)
{
_styleCacheId = styleId;
_style = null;
StyleChanged = false;
}
+
public Int32 GetStyleId()
{
if (StyleChanged)
@@ -39,6 +42,7 @@
return _styleCacheId;
}
+
protected IXLStyle GetStyle()
{
return _style ?? (_style = new XLStyle(this, Worksheet.Workbook.GetStyleById(_styleCacheId)));
@@ -46,18 +50,17 @@
#region Constructor
- static Int32 IdCounter = 0;
- readonly Int32 Id;
+ private static Int32 IdCounter = 0;
+ private readonly Int32 Id;
protected XLRangeBase(XLRangeAddress rangeAddress)
{
-
Id = ++IdCounter;
RangeAddress = new XLRangeAddress(rangeAddress);
}
- #endregion
+ #endregion Constructor
private XLCallbackAction _shiftedRowsAction;
@@ -71,6 +74,7 @@
}
private XLCallbackAction _shiftedColumnsAction;
+
protected void SubscribeToShiftedColumns(Action action)
{
if (Worksheet == null || !Worksheet.EventTrackingEnabled) return;
@@ -82,9 +86,8 @@
#region Public properties
- //public XLRangeAddress RangeAddress { get; protected set; }
-
private XLRangeAddress _rangeAddress;
+
public XLRangeAddress RangeAddress
{
get { return _rangeAddress; }
@@ -243,8 +246,6 @@
}
}
-
-
public Object Value
{
set { Cells().ForEach(c => c.Value = value); }
@@ -255,7 +256,7 @@
set { Cells().ForEach(c => c.DataType = value); }
}
- #endregion
+ #endregion IXLRangeBase Members
#region IXLStylized Members
@@ -268,9 +269,9 @@
}
}
- #endregion
+ #endregion IXLStylized Members
- #endregion
+ #endregion Public properties
#region IXLRangeBase Members
@@ -457,17 +458,17 @@
get { return GetStyle(); }
set { Cells().ForEach(c => c.Style = value); }
}
+
IXLRange IXLRangeBase.AsRange()
{
return AsRange();
}
+
public virtual XLRange AsRange()
{
return Worksheet.Range(RangeAddress.FirstAddress, RangeAddress.LastAddress);
}
-
-
public IXLRange AddToNamed(String rangeName)
{
return AddToNamed(rangeName, XLScope.Workbook);
@@ -516,7 +517,19 @@
CellsUsed(includeFormats).Cast().Any(c => c.IsEmpty(includeFormats));
}
- #endregion
+ public Boolean IsEntireRow()
+ {
+ return RangeAddress.FirstAddress.ColumnNumber == 1
+ && RangeAddress.LastAddress.ColumnNumber == XLHelper.MaxColumnNumber;
+ }
+
+ public Boolean IsEntireColumn()
+ {
+ return RangeAddress.FirstAddress.RowNumber == 1
+ && RangeAddress.LastAddress.RowNumber == XLHelper.MaxRowNumber;
+ }
+
+ #endregion IXLRangeBase Members
#region IXLStylized Members
@@ -539,7 +552,28 @@
set { SetStyle(value); }
}
- #endregion
+ #endregion IXLStylized Members
+
+ public IXLCells Search(String searchText, CompareOptions compareOptions = CompareOptions.Ordinal, Boolean searchFormulae = false)
+ {
+ var culture = CultureInfo.CurrentCulture;
+ return this.CellsUsed(false, c =>
+ {
+ try
+ {
+ if (searchFormulae)
+ return c.HasFormula
+ && culture.CompareInfo.IndexOf(c.FormulaA1, searchText, compareOptions) >= 0
+ || culture.CompareInfo.IndexOf(c.Value.ToString(), searchText, compareOptions) >= 0;
+ else
+ return culture.CompareInfo.IndexOf(c.GetFormattedString(), searchText, compareOptions) >= 0;
+ }
+ catch
+ {
+ return false;
+ }
+ });
+ }
public XLCell FirstCell()
{
@@ -642,7 +676,6 @@
}
}
-
if (sp.Row > 0)
return Worksheet.Cell(sp.Row, sp.Column);
@@ -734,7 +767,6 @@
}
}
-
if (sp.Row > 0)
return Worksheet.Cell(sp.Row, sp.Column);
@@ -748,7 +780,6 @@
public XLCell Cell(String cellAddressInRange)
{
-
if (XLHelper.IsValidA1Address(cellAddressInRange))
return Cell(XLAddress.Create(Worksheet, cellAddressInRange));
@@ -810,7 +841,7 @@
Int32 newCellStyleId = styleId;
- // If the default style for this range base is empty, but the worksheet
+ // If the default style for this range base is empty, but the worksheet
// has a default style, use the worksheet's default style
if (styleId == 0 && worksheetStyleId != 0)
newCellStyleId = worksheetStyleId;
@@ -904,7 +935,6 @@
public XLRange Range(IXLRangeAddress rangeAddress)
{
-
var newFirstCellAddress = new XLAddress((XLWorksheet)rangeAddress.FirstAddress.Worksheet,
rangeAddress.FirstAddress.RowNumber + RangeAddress.FirstAddress.RowNumber - 1,
rangeAddress.FirstAddress.ColumnNumber + RangeAddress.FirstAddress.ColumnNumber - 1,
@@ -1077,7 +1107,6 @@
cell.ShiftFormulaColumns(asRange, numberOfColumns);
}
-
var cellsDataValidations = new Dictionary();
var cellsToInsert = new Dictionary();
var cellsToDelete = new List();
@@ -1092,10 +1121,10 @@
{
for (int co = lastColumn; co >= firstColumn; co--)
{
+ int newColumn = co + numberOfColumns;
for (int ro = lastRow; ro >= firstRow; ro--)
{
var oldKey = new XLAddress(Worksheet, ro, co, false, false);
- int newColumn = co + numberOfColumns;
var newKey = new XLAddress(Worksheet, ro, newColumn, false, false);
var oldCell = Worksheet.Internals.CellsCollection.GetCell(ro, co) ??
Worksheet.Cell(oldKey);
@@ -1106,6 +1135,11 @@
cellsToInsert.Add(newKey, newCell);
cellsToDelete.Add(oldKey);
}
+
+ if (this.IsEntireColumn())
+ {
+ Worksheet.Column(newColumn).Width = Worksheet.Column(co).Width;
+ }
}
}
}
@@ -1193,7 +1227,6 @@
: Worksheet.Style;
rangeToReturn.Row(ro).Style = styleToUse;
}
-
}
}
@@ -1284,15 +1317,17 @@
return retVal;
}
- struct DataValidationToCopy
+ private struct DataValidationToCopy
{
public XLAddress SourceAddress;
public XLDataValidation DataValidation;
}
+
public void InsertRowsAboveVoid(Boolean onlyUsedCells, Int32 numberOfRows, Boolean formatFromAbove = true)
{
InsertRowsAboveInternal(onlyUsedCells, numberOfRows, formatFromAbove, nullReturn: true);
}
+
public IXLRangeRows InsertRowsAbove(Boolean onlyUsedCells, Int32 numberOfRows, Boolean formatFromAbove = true)
{
return InsertRowsAboveInternal(onlyUsedCells, numberOfRows, formatFromAbove, nullReturn: false);
@@ -1323,10 +1358,11 @@
{
for (int ro = lastRow; ro >= firstRow; ro--)
{
+ int newRow = ro + numberOfRows;
+
for (int co = lastColumn; co >= firstColumn; co--)
{
var oldKey = new XLAddress(Worksheet, ro, co, false, false);
- int newRow = ro + numberOfRows;
var newKey = new XLAddress(Worksheet, newRow, co, false, false);
var oldCell = Worksheet.Internals.CellsCollection.GetCell(ro, co);
if (oldCell != null)
@@ -1338,6 +1374,10 @@
cellsToDelete.Add(oldKey);
}
}
+ if (this.IsEntireRow())
+ {
+ Worksheet.Row(newRow).Height = Worksheet.Row(ro).Height;
+ }
}
}
}
@@ -1363,7 +1403,6 @@
newCell.FormulaA1 = c.FormulaA1;
cellsToInsert.Add(newKey, newCell);
cellsToDelete.Add(c.Address);
-
}
}
@@ -1381,7 +1420,6 @@
cellsToDelete.ForEach(c => Worksheet.Internals.CellsCollection.Remove(c.RowNumber, c.ColumnNumber));
cellsToInsert.ForEach(c => Worksheet.Internals.CellsCollection.Add(c.Key.RowNumber, c.Key.ColumnNumber, c.Value));
-
Int32 firstRowReturn = RangeAddress.FirstAddress.RowNumber;
Int32 lastRowReturn = RangeAddress.FirstAddress.RowNumber + numberOfRows - 1;
Int32 firstColumnReturn = RangeAddress.FirstAddress.ColumnNumber;
@@ -1472,7 +1510,6 @@
RangeAddress.LastAddress.RowNumber,
RangeAddress.LastAddress.ColumnNumber);
-
foreach (
XLCell cell in
Worksheet.Workbook.Worksheets.Cast().SelectMany(
@@ -1501,7 +1538,6 @@
Worksheet.Internals.CellsCollection.MaxRowUsed,
RangeAddress.LastAddress.ColumnNumber);
-
int columnModifier = shiftDeleteCells == XLShiftDeletedCells.ShiftCellsLeft ? ColumnCount() : 0;
int rowModifier = shiftDeleteCells == XLShiftDeletedCells.ShiftCellsUp ? RowCount() : 0;
var cellsQuery = shiftDeleteCells == XLShiftDeletedCells.ShiftCellsLeft ? shiftLeftQuery : shiftUpQuery;
@@ -1523,7 +1559,6 @@
cellsToInsert.Add(newKey, newCell);
}
-
cellsToDelete.ForEach(c => Worksheet.Internals.CellsCollection.Remove(c.RowNumber, c.ColumnNumber));
cellsToInsert.ForEach(
c => Worksheet.Internals.CellsCollection.Add(c.Key.RowNumber, c.Key.ColumnNumber, c.Value));
@@ -1698,17 +1733,16 @@
// return chart;
//}
-
IXLPivotTable IXLRangeBase.CreatePivotTable(IXLCell targetCell)
{
return CreatePivotTable(targetCell);
}
+
IXLPivotTable IXLRangeBase.CreatePivotTable(IXLCell targetCell, String name)
{
return CreatePivotTable(targetCell, name);
}
-
public XLPivotTable CreatePivotTable(IXLCell targetCell)
{
return CreatePivotTable(targetCell, Guid.NewGuid().ToString());
@@ -1821,7 +1855,6 @@
return this;
}
-
#region Sort Rows
private void SortRangeRows()
@@ -1886,7 +1919,7 @@
SortingRangeRows(pivot + 1, end);
}
- #endregion
+ #endregion Sort Rows
#region Sort Columns
@@ -1951,9 +1984,9 @@
SortingRangeColumns(pivot + 1, end);
}
- #endregion
+ #endregion Sort Columns
- #endregion
+ #endregion Sort
public XLRangeColumn ColumnQuick(Int32 column)
{
@@ -2017,7 +2050,6 @@
}
}
-
internal IXLConditionalFormat AddConditionalFormat(IXLConditionalFormat source)
{
using (var asRange = AsRange())
diff --git a/ClosedXML/Excel/Rows/IXLRow.cs b/ClosedXML/Excel/Rows/IXLRow.cs
index 3bec732..70816fb 100644
--- a/ClosedXML/Excel/Rows/IXLRow.cs
+++ b/ClosedXML/Excel/Rows/IXLRow.cs
@@ -15,6 +15,11 @@
Double Height { get; set; }
///
+ /// Clears the height for the row and defaults it to the spreadsheet row height.
+ ///
+ void ClearHeight();
+
+ ///
/// Deletes this row and shifts the rows below this one accordingly.
///
void Delete();
diff --git a/ClosedXML/Excel/Rows/XLRow.cs b/ClosedXML/Excel/Rows/XLRow.cs
index 944cb17..721e29e 100644
--- a/ClosedXML/Excel/Rows/XLRow.cs
+++ b/ClosedXML/Excel/Rows/XLRow.cs
@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Drawing;
-
+using System.Linq;
namespace ClosedXML.Excel
{
@@ -15,7 +14,7 @@
private Boolean _isHidden;
private Int32 _outlineLevel;
- #endregion
+ #endregion Private fields
#region Constructor
@@ -44,7 +43,7 @@
_height = row._height;
IsReference = row.IsReference;
if (IsReference)
- SubscribeToShiftedRows((range, rowShifted) => this.WorksheetRangeShiftedRows(range, rowShifted));
+ SubscribeToShiftedRows((range, rowShifted) => this.WorksheetRangeShiftedRows(range, rowShifted));
_collapsed = row._collapsed;
_isHidden = row._isHidden;
@@ -53,7 +52,7 @@
SetStyle(row.GetStyleId());
}
- #endregion
+ #endregion Constructor
public Boolean IsReference { get; private set; }
@@ -108,6 +107,7 @@
#region IXLRow Members
private Boolean _loading;
+
public Boolean Loading
{
get { return IsReference ? Worksheet.Internals.RowsCollection[RowNumber()].Loading : _loading; }
@@ -121,6 +121,7 @@
}
public Boolean HeightChanged { get; private set; }
+
public Double Height
{
get { return IsReference ? Worksheet.Internals.RowsCollection[RowNumber()].Height : _height; }
@@ -136,6 +137,12 @@
}
}
+ public void ClearHeight()
+ {
+ Height = Worksheet.RowHeight;
+ HeightChanged = false;
+ }
+
public void Delete()
{
int rowNumber = RowNumber();
@@ -291,7 +298,7 @@
foreach (IXLRichString rt in c.RichText)
{
String formattedString = rt.Text;
- var arr = formattedString.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
+ var arr = formattedString.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
Int32 arrCount = arr.Count();
for (Int32 i = 0; i < arrCount; i++)
{
@@ -305,7 +312,7 @@
else
{
String formattedString = c.GetFormattedString();
- var arr = formattedString.Split(new[] {Environment.NewLine}, StringSplitOptions.None);
+ var arr = formattedString.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
Int32 arrCount = arr.Count();
for (Int32 i = 0; i < arrCount; i++)
{
@@ -338,7 +345,7 @@
}
}
else
- thisHeight = c.Style.Font.GetHeight( fontCache);
+ thisHeight = c.Style.Font.GetHeight(fontCache);
if (thisHeight >= maxHeight)
{
@@ -520,15 +527,15 @@
IXLRangeRow IXLRow.CopyTo(IXLCell target)
{
using (var asRange = AsRange())
- using (var copy = asRange.CopyTo(target))
- return copy.Row(1);
+ using (var copy = asRange.CopyTo(target))
+ return copy.Row(1);
}
IXLRangeRow IXLRow.CopyTo(IXLRangeBase target)
{
using (var asRange = AsRange())
- using (var copy = asRange.CopyTo(target))
- return copy.Row(1);
+ using (var copy = asRange.CopyTo(target))
+ return copy.Row(1);
}
public IXLRow CopyTo(IXLRow row)
@@ -581,7 +588,7 @@
return Row(FirstCellUsed(includeFormats), LastCellUsed(includeFormats));
}
- #endregion
+ #endregion IXLRow Members
public override XLRange AsRange()
{
@@ -676,7 +683,7 @@
return RowShift(step * -1);
}
- #endregion
+ #endregion XLRow Above
#region XLRow Below
@@ -700,7 +707,7 @@
return RowShift(step);
}
- #endregion
+ #endregion XLRow Below
public new Boolean IsEmpty()
{
@@ -715,6 +722,14 @@
return base.IsEmpty(includeFormats);
}
+ public Boolean IsEntireRow()
+ {
+ return true;
+ }
+ public Boolean IsEntireColumn()
+ {
+ return false;
+ }
}
}
diff --git a/ClosedXML/Excel/Style/Colors/XLColor_Public.cs b/ClosedXML/Excel/Style/Colors/XLColor_Public.cs
index 6feefe3..4d0d9d3 100644
--- a/ClosedXML/Excel/Style/Colors/XLColor_Public.cs
+++ b/ClosedXML/Excel/Style/Colors/XLColor_Public.cs
@@ -55,7 +55,7 @@
get
{
if (_colorType == XLColorType.Theme)
- throw new Exception("Cannot convert theme color to Color.");
+ throw new InvalidOperationException("Cannot convert theme color to Color.");
if (_colorType == XLColorType.Indexed)
if (_indexed == TOOLTIPCOLORINDEX)
@@ -72,12 +72,12 @@
get
{
if (ColorType == XLColorType.Theme)
- throw new Exception("Cannot convert theme color to indexed color.");
+ throw new InvalidOperationException("Cannot convert theme color to indexed color.");
if (ColorType == XLColorType.Indexed)
return _indexed;
- throw new Exception("Cannot convert Color to indexed color.");
+ throw new InvalidOperationException("Cannot convert Color to indexed color.");
}
}
@@ -89,9 +89,9 @@
return _themeColor;
if (ColorType == XLColorType.Indexed)
- throw new Exception("Cannot convert indexed color to theme color.");
+ throw new InvalidOperationException("Cannot convert indexed color to theme color.");
- throw new Exception("Cannot convert Color to theme color.");
+ throw new InvalidOperationException("Cannot convert Color to theme color.");
}
}
@@ -103,7 +103,7 @@
return _themeTint;
if (ColorType == XLColorType.Indexed)
- throw new Exception("Cannot extract theme tint from an indexed color.");
+ throw new InvalidOperationException("Cannot extract theme tint from an indexed color.");
return _color.A/255.0;
}
diff --git a/ClosedXML/Excel/Tables/XLTable.cs b/ClosedXML/Excel/Tables/XLTable.cs
index 27cfb2c..6048e33 100644
--- a/ClosedXML/Excel/Tables/XLTable.cs
+++ b/ClosedXML/Excel/Tables/XLTable.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@@ -105,6 +105,16 @@
}
}
+ internal void RenameField(String oldName, String newName)
+ {
+ if (!_fieldNames.ContainsKey(oldName))
+ throw new ArgumentException("The field does not exist in this table", "oldName");
+
+ var field = _fieldNames[oldName];
+ _fieldNames.Remove(oldName);
+ _fieldNames.Add(newName, field);
+ }
+
internal String RelId { get; set; }
public IXLTableRange DataRange
@@ -423,6 +433,10 @@
public Int32 GetFieldIndex(String name)
{
+ // There is a discrepancy in the way headers with line breaks are stored.
+ // The entry in the table definition will contain \r\n
+ // but the shared string value of the actual cell will contain only \n
+ name = name.Replace("\r\n", "\n");
if (FieldNames.ContainsKey(name))
return FieldNames[name].Index;
diff --git a/ClosedXML/Excel/Tables/XLTableField.cs b/ClosedXML/Excel/Tables/XLTableField.cs
index 2a085dc..528d7d2 100644
--- a/ClosedXML/Excel/Tables/XLTableField.cs
+++ b/ClosedXML/Excel/Tables/XLTableField.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Diagnostics;
using System.Linq;
@@ -37,6 +37,7 @@
if (table.ShowHeaderRow)
table.HeadersRow().Cell(Index + 1).SetValue(value);
+ table.RenameField(name, value);
name = value;
}
}
diff --git a/ClosedXML/Excel/XLWorkbook.cs b/ClosedXML/Excel/XLWorkbook.cs
index 9e86a67..baeaf73 100644
--- a/ClosedXML/Excel/XLWorkbook.cs
+++ b/ClosedXML/Excel/XLWorkbook.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using System.Data;
+using System.Globalization;
using System.IO;
using System.Linq;
@@ -442,7 +443,7 @@
{
checkForWorksheetsPresent();
if (_loadSource == XLLoadSource.New)
- throw new Exception("This is a new file, please use one of the SaveAs methods.");
+ throw new InvalidOperationException("This is a new file, please use one of the SaveAs methods.");
if (_loadSource == XLLoadSource.Stream)
{
@@ -502,7 +503,8 @@
private static SpreadsheetDocumentType GetSpreadsheetDocumentType(string filePath)
{
var extension = Path.GetExtension(filePath);
- if (extension == null) throw new Exception("Empty extension is not supported.");
+
+ if (extension == null) throw new ArgumentException("Empty extension is not supported.");
extension = extension.Substring(1).ToLowerInvariant();
switch (extension)
@@ -522,7 +524,7 @@
private void checkForWorksheetsPresent()
{
if (Worksheets.Count() == 0)
- throw new Exception("Workbooks need at least one worksheet.");
+ throw new InvalidOperationException("Workbooks need at least one worksheet.");
}
///
@@ -650,7 +652,24 @@
return columns;
}
-#region Fields
+ ///
+ /// Searches the cells' contents for a given piece of text
+ ///
+ /// The search text.
+ /// The compare options.
+ /// if set to true search formulae instead of cell values.
+ ///
+ public IEnumerable Search(String searchText, CompareOptions compareOptions = CompareOptions.Ordinal, Boolean searchFormulae = false)
+ {
+ foreach (var ws in WorksheetsInternal)
+ {
+ foreach (var cell in ws.Search(searchText, compareOptions, searchFormulae))
+ yield return cell;
+ }
+ }
+
+
+ #region Fields
private readonly XLLoadSource _loadSource = XLLoadSource.New;
private readonly String _originalFile;
@@ -866,7 +885,7 @@
public XLWorkbook SetLockWindows(Boolean value) { LockWindows = value; return this; }
internal HexBinaryValue LockPassword { get; set; }
public Boolean IsPasswordProtected { get { return LockPassword != null; } }
-
+
public void Protect(Boolean lockStructure, Boolean lockWindows, String workbookPassword)
{
if (IsPasswordProtected && workbookPassword == null)
@@ -896,7 +915,7 @@
LockStructure = lockStructure;
LockWindows = lockWindows;
}
-
+
public void Protect()
{
Protect(true);
@@ -927,4 +946,4 @@
Protect(false, false, workbookPassword);
}
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML/Excel/XLWorkbook_Load.cs b/ClosedXML/Excel/XLWorkbook_Load.cs
index 2389524..4d879ae 100644
--- a/ClosedXML/Excel/XLWorkbook_Load.cs
+++ b/ClosedXML/Excel/XLWorkbook_Load.cs
@@ -265,11 +265,15 @@
#region LoadTables
- foreach (TableDefinitionPart tablePart in wsPart.TableDefinitionParts)
+ foreach (var tablePart in wsPart.TableDefinitionParts)
{
var dTable = tablePart.Table;
- string reference = dTable.Reference.Value;
- XLTable xlTable = ws.Range(reference).CreateTable(dTable.Name, false) as XLTable;
+ String reference = dTable.Reference.Value;
+ String tableName = dTable?.Name ?? dTable.DisplayName ?? string.Empty;
+ if (String.IsNullOrWhiteSpace(tableName))
+ throw new InvalidDataException("The table name is missing.");
+
+ XLTable xlTable = ws.Range(reference).CreateTable(tableName, false) as XLTable;
if (dTable.HeaderRowCount != null && dTable.HeaderRowCount == 0)
{
xlTable._showHeaderRow = false;
@@ -500,6 +504,14 @@
if (pivotTableDefinition.ShowError != null && pivotTableDefinition.ErrorCaption != null)
pt.ErrorValueReplacement = pivotTableDefinition.ErrorCaption.Value;
+ // Subtotal configuration
+ if (pivotTableDefinition.PivotFields.Cast().All(pf => pf.SubtotalTop != null && pf.SubtotalTop.HasValue && pf.SubtotalTop.Value))
+ pt.SetSubtotals(XLPivotSubtotals.AtTop);
+ else if (pivotTableDefinition.PivotFields.Cast().All(pf => pf.SubtotalTop != null && pf.SubtotalTop.HasValue && !pf.SubtotalTop.Value))
+ pt.SetSubtotals(XLPivotSubtotals.AtBottom);
+ else
+ pt.SetSubtotals(XLPivotSubtotals.DoNotShow);
+
// Row labels
if (pivotTableDefinition.RowFields != null)
{
@@ -725,7 +737,7 @@
if (shape != null) break;
}
- if (xdoc == null) throw new Exception("Could not load comments file");
+ if (xdoc == null) throw new ArgumentException("Could not load comments file");
return xdoc;
}
@@ -1062,7 +1074,7 @@
else
{
if (!Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges.Any(nr => nr.Name == name))
- Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges.Add(name, text, comment).Visible = visible;
+ (Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges as XLNamedRanges).Add(name, text, comment, true).Visible = visible;
}
}
}
@@ -1073,7 +1085,6 @@
private IEnumerable validateDefinedNames(IEnumerable definedNames)
{
- var fixedNames = new List();
var sb = new StringBuilder();
foreach (string testName in definedNames)
{
@@ -2399,4 +2410,4 @@
return false;
}
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/Excel/XLWorkbook_Save.cs
index 26d38d4..6c67db2 100644
--- a/ClosedXML/Excel/XLWorkbook_Save.cs
+++ b/ClosedXML/Excel/XLWorkbook_Save.cs
@@ -142,9 +142,10 @@
private void DeleteSheetAndDependencies(WorkbookPart wbPart, string sheetId)
{
//Get the SheetToDelete from workbook.xml
- Sheet worksheet = wbPart.Workbook.Descendants().Where(s => s.Id == sheetId).FirstOrDefault();
+ Sheet worksheet = wbPart.Workbook.Descendants().FirstOrDefault(s => s.Id == sheetId);
if (worksheet == null)
- { }
+ return;
+
string sheetName = worksheet.Name;
// Get the pivot Table Parts
@@ -154,8 +155,8 @@
{
PivotCacheDefinition pvtCacheDef = Item.PivotCacheDefinition;
//Check if this CacheSource is linked to SheetToDelete
- var pvtCahce = pvtCacheDef.Descendants().Where(s => s.WorksheetSource.Sheet == sheetName);
- if (pvtCahce.Count() > 0)
+ var pvtCache = pvtCacheDef.Descendants().Where(s => s.WorksheetSource.Sheet == sheetName);
+ if (pvtCache.Any())
{
pvtTableCacheDefinationPart.Add(Item, Item.ToString());
}
@@ -178,7 +179,7 @@
{
List defNamesToDelete = new List();
- foreach (DefinedName Item in definedNames)
+ foreach (var Item in definedNames.OfType())
{
// This condition checks to delete only those names which are part of Sheet in question
if (Item.Text.Contains(worksheet.Name + "!"))
@@ -201,19 +202,15 @@
var calChainEntries = calChainPart.CalculationChain.Descendants().Where(c => c.SheetId == sheetId);
List calcsToDelete = new List();
foreach (CalculationCell Item in calChainEntries)
- {
calcsToDelete.Add(Item);
- }
+
foreach (CalculationCell Item in calcsToDelete)
- {
Item.Remove();
- }
- if (calChainPart.CalculationChain.Count() == 0)
- {
+
+ if (!calChainPart.CalculationChain.Any())
wbPart.DeletePart(calChainPart);
- }
}
}
@@ -350,6 +347,9 @@
GenerateCustomFilePropertiesPartContent(customFilePropertiesPart);
}
SetPackageProperties(document);
+
+ // Clear list of deleted worksheets to prevent errors on multiple saves
+ worksheets.Deleted.Clear();
}
private void DeleteComments(WorksheetPart worksheetPart, XLWorksheet worksheet, SaveContext context)
@@ -2112,6 +2112,21 @@
IXLPivotField labelField = null;
var pf = new PivotField { ShowAll = false, Name = xlpf.CustomName };
+ switch (pt.Subtotals)
+ {
+ case XLPivotSubtotals.DoNotShow:
+ pf.DefaultSubtotal = false;
+ break;
+ case XLPivotSubtotals.AtBottom:
+ pf.DefaultSubtotal = true;
+ pf.SubtotalTop = false;
+ break;
+ case XLPivotSubtotals.AtTop:
+ pf.DefaultSubtotal = true;
+ pf.SubtotalTop = true;
+ break;
+ }
+
if (pt.RowLabels.Any(p => p.SourceName == xlpf.SourceName))
{
labelField = pt.RowLabels.Single(p => p.SourceName == xlpf.SourceName);
@@ -2135,7 +2150,7 @@
var fieldItems = new Items();
- if (xlpf.SharedStrings.Count > 0)
+ if (xlpf.SharedStrings.Any())
{
for (uint i = 0; i < xlpf.SharedStrings.Count; i++)
{
@@ -2146,7 +2161,7 @@
}
}
- if (xlpf.Subtotals.Count > 0)
+ if (xlpf.Subtotals.Any())
{
foreach (var subtotal in xlpf.Subtotals)
{
@@ -2211,13 +2226,17 @@
fieldItems.AppendChild(itemSubtotal);
}
}
- else
+ // If the field itself doesn't have subtotals, but the pivot table is set to show pivot tables, add the default item
+ else if (pt.Subtotals != XLPivotSubtotals.DoNotShow)
{
fieldItems.AppendChild(new Item { ItemType = ItemValues.Default });
}
- fieldItems.Count = Convert.ToUInt32(fieldItems.Count());
- pf.AppendChild(fieldItems);
+ if (fieldItems.Any())
+ {
+ fieldItems.Count = Convert.ToUInt32(fieldItems.Count());
+ pf.AppendChild(fieldItems);
+ }
pivotFields.AppendChild(pf);
}
diff --git a/ClosedXML/Excel/XLWorksheet.cs b/ClosedXML/Excel/XLWorksheet.cs
index 033fd27..453e566 100644
--- a/ClosedXML/Excel/XLWorksheet.cs
+++ b/ClosedXML/Excel/XLWorksheet.cs
@@ -606,11 +606,18 @@
}
}
- foreach (IXLNamedRange r in NamedRanges)
+ foreach (var nr in NamedRanges)
{
var ranges = new XLRanges();
- r.Ranges.ForEach(ranges.Add);
- targetSheet.NamedRanges.Add(r.Name, ranges);
+ foreach (var r in nr.Ranges)
+ {
+ if (this == r.Worksheet)
+ // Named ranges on the source worksheet have to point to the new destination sheet
+ ranges.Add(targetSheet.Range(r.RangeAddress.FirstAddress.RowNumber, r.RangeAddress.FirstAddress.ColumnNumber, r.RangeAddress.LastAddress.RowNumber, r.RangeAddress.LastAddress.ColumnNumber));
+ else
+ ranges.Add(r);
+ }
+ targetSheet.NamedRanges.Add(nr.Name, ranges);
}
foreach (XLTable t in Tables.Cast())
@@ -1569,5 +1576,14 @@
{
return Pictures.Add(imageFile, name);
}
+ public Boolean IsEntireRow()
+ {
+ return true;
+ }
+
+ public Boolean IsEntireColumn()
+ {
+ return true;
+ }
}
}
diff --git a/ClosedXML/Excel/XLWorksheets.cs b/ClosedXML/Excel/XLWorksheets.cs
index c7b15d4..9061e1d 100644
--- a/ClosedXML/Excel/XLWorksheets.cs
+++ b/ClosedXML/Excel/XLWorksheets.cs
@@ -77,18 +77,18 @@
if (wss.Any())
return wss.First().Value;
- throw new Exception("There isn't a worksheet named '" + sheetName + "'.");
+ throw new ArgumentException("There isn't a worksheet named '" + sheetName + "'.");
}
public IXLWorksheet Worksheet(Int32 position)
{
int wsCount = _worksheets.Values.Count(w => w.Position == position);
if (wsCount == 0)
- throw new Exception("There isn't a worksheet associated with that position.");
+ throw new ArgumentException("There isn't a worksheet associated with that position.");
if (wsCount > 1)
{
- throw new Exception(
+ throw new ArgumentException(
"Can't retrieve a worksheet because there are multiple worksheets associated with that position.");
}
@@ -130,10 +130,10 @@
{
int wsCount = _worksheets.Values.Count(w => w.Position == position);
if (wsCount == 0)
- throw new Exception("There isn't a worksheet associated with that index.");
+ throw new ArgumentException("There isn't a worksheet associated with that index.");
if (wsCount > 1)
- throw new Exception(
+ throw new ArgumentException(
"Can't delete the worksheet because there are multiple worksheets associated with that index.");
var ws = _worksheets.Values.Single(w => w.Position == position);
@@ -180,7 +180,8 @@
{
if (String.IsNullOrWhiteSpace(oldSheetName) || !_worksheets.ContainsKey(oldSheetName)) return;
- if (_worksheets.Any(ws1 => ws1.Key.Equals(newSheetName, StringComparison.OrdinalIgnoreCase)))
+ if (!oldSheetName.Equals(newSheetName, StringComparison.OrdinalIgnoreCase)
+ && _worksheets.Any(ws1 => ws1.Key.Equals(newSheetName, StringComparison.OrdinalIgnoreCase)))
throw new ArgumentException(String.Format("A worksheet with the same name ({0}) has already been added.", newSheetName), nameof(newSheetName));
var ws = _worksheets[oldSheetName];
diff --git a/ClosedXML_Examples/Misc/InsertingData.cs b/ClosedXML_Examples/Misc/InsertingData.cs
index d0ade19..d1035d5 100644
--- a/ClosedXML_Examples/Misc/InsertingData.cs
+++ b/ClosedXML_Examples/Misc/InsertingData.cs
@@ -13,59 +13,65 @@
// Public
public void Create(String filePath)
{
- var wb = new XLWorkbook();
- var ws = wb.Worksheets.Add("Inserting Data");
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.Worksheets.Add("Inserting Data");
- // From a list of strings
- var listOfStrings = new List();
- listOfStrings.Add("House");
- listOfStrings.Add("001");
- ws.Cell(1, 1).Value = "From Strings";
- ws.Cell(1, 1).AsRange().AddToNamed("Titles");
- ws.Cell(2, 1).InsertData(listOfStrings);
+ // From a list of strings
+ var listOfStrings = new List();
+ listOfStrings.Add("House");
+ listOfStrings.Add("001");
+ ws.Cell(1, 1).Value = "From Strings";
+ ws.Cell(1, 1).AsRange().AddToNamed("Titles");
+ ws.Cell(2, 1).InsertData(listOfStrings);
- // From a list of arrays
- var listOfArr = new List();
- listOfArr.Add(new Int32[] { 1, 2, 3 });
- listOfArr.Add(new Int32[] { 1 });
- listOfArr.Add(new Int32[] { 1, 2, 3, 4, 5, 6 });
- ws.Cell(1, 3).Value = "From Arrays";
- ws.Range(1, 3, 1, 8).Merge().AddToNamed("Titles");
- ws.Cell(2, 3).InsertData(listOfArr);
+ // From a list of arrays
+ var listOfArr = new List();
+ listOfArr.Add(new Int32[] { 1, 2, 3 });
+ listOfArr.Add(new Int32[] { 1 });
+ listOfArr.Add(new Int32[] { 1, 2, 3, 4, 5, 6 });
+ ws.Cell(1, 3).Value = "From Arrays";
+ ws.Range(1, 3, 1, 8).Merge().AddToNamed("Titles");
+ ws.Cell(2, 3).InsertData(listOfArr);
- // From a DataTable
- var dataTable = GetTable();
- ws.Cell(6, 1).Value = "From DataTable";
- ws.Range(6, 1, 6, 4).Merge().AddToNamed("Titles");
- ws.Cell(7, 1).InsertData(dataTable.AsEnumerable());
+ // From a DataTable
+ var dataTable = GetTable();
+ ws.Cell(6, 1).Value = "From DataTable";
+ ws.Range(6, 1, 6, 4).Merge().AddToNamed("Titles");
+ ws.Cell(7, 1).InsertData(dataTable.AsEnumerable());
- // From a query
- var list = new List();
- list.Add(new Person() { Name = "John", Age = 30, House = "On Elm St." });
- list.Add(new Person() { Name = "Mary", Age = 15, House = "On Main St." });
- list.Add(new Person() { Name = "Luis", Age = 21, House = "On 23rd St." });
- list.Add(new Person() { Name = "Henry", Age = 45, House = "On 5th Ave." });
+ // From a query
+ var list = new List();
+ list.Add(new Person() { Name = "John", Age = 30, House = "On Elm St." });
+ list.Add(new Person() { Name = "Mary", Age = 15, House = "On Main St." });
+ list.Add(new Person() { Name = "Luis", Age = 21, House = "On 23rd St." });
+ list.Add(new Person() { Name = "Henry", Age = 45, House = "On 5th Ave." });
- var people = from p in list
- where p.Age >= 21
- select new { p.Name, p.House, p.Age };
+ var people = from p in list
+ where p.Age >= 21
+ select new { p.Name, p.House, p.Age };
- ws.Cell(6, 6).Value = "From Query";
- ws.Range(6, 6, 6, 8).Merge().AddToNamed("Titles");
- ws.Cell(7, 6).InsertData(people.AsEnumerable());
+ ws.Cell(6, 6).Value = "From Query";
+ ws.Range(6, 6, 6, 8).Merge().AddToNamed("Titles");
+ ws.Cell(7, 6).InsertData(people.AsEnumerable());
- // Prepare the style for the titles
- var titlesStyle = wb.Style;
- titlesStyle.Font.Bold = true;
- titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
- titlesStyle.Fill.BackgroundColor = XLColor.Cyan;
-
- // Format all titles in one shot
- wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle;
+ ws.Cell("F13").Value = "Transposed";
+ ws.Range(13, 6, 13, 8).Merge().AddToNamed("Titles");
+ ws.Cell("F14").InsertData(people.AsEnumerable(), true);
- ws.Columns().AdjustToContents();
+ // Prepare the style for the titles
+ var titlesStyle = wb.Style;
+ titlesStyle.Font.Bold = true;
+ titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
+ titlesStyle.Fill.BackgroundColor = XLColor.Cyan;
- wb.SaveAs(filePath);
+ // Format all titles in one shot
+ wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle;
+
+ ws.Columns().AdjustToContents();
+
+ wb.SaveAs(filePath);
+ }
}
class Person
diff --git a/ClosedXML_Examples/PivotTables/PivotTables.cs b/ClosedXML_Examples/PivotTables/PivotTables.cs
index 9eb24ea..fa479da 100644
--- a/ClosedXML_Examples/PivotTables/PivotTables.cs
+++ b/ClosedXML_Examples/PivotTables/PivotTables.cs
@@ -60,6 +60,8 @@
IXLWorksheet ptSheet;
IXLPivotTable pt;
+ #region Pivots
+
for (int i = 1; i <= 3; i++)
{
// Add a new sheet for our pivot table
@@ -95,7 +97,10 @@
ptSheet.Columns().AdjustToContents();
}
- // Different kind of pivot
+ #endregion Pivots
+
+ #region Different kind of pivot
+
ptSheet = wb.Worksheets.Add("pvtNoColumnLabels");
pt = ptSheet.PivotTables.AddNew("pvtNoColumnLabels", ptSheet.Cell(1, 1), dataRange);
@@ -105,8 +110,10 @@
pt.Values.Add("NumberOfOrders").SetSummaryFormula(XLPivotSummary.Sum);
pt.Values.Add("Quality").SetSummaryFormula(XLPivotSummary.Sum);
+ #endregion Different kind of pivot
- // Pivot table with collapsed fields
+ #region Pivot table with collapsed fields
+
ptSheet = wb.Worksheets.Add("pvtCollapsedFields");
pt = ptSheet.PivotTables.AddNew("pvtCollapsedFields", ptSheet.Cell(1, 1), dataRange);
@@ -116,8 +123,10 @@
pt.Values.Add("NumberOfOrders").SetSummaryFormula(XLPivotSummary.Sum);
pt.Values.Add("Quality").SetSummaryFormula(XLPivotSummary.Sum);
+ #endregion Pivot table with collapsed fields
- // Pivot table with a field both as a value and as a row/column/filter label
+ #region Pivot table with a field both as a value and as a row/column/filter label
+
ptSheet = wb.Worksheets.Add("pvtFieldAsValueAndLabel");
pt = ptSheet.PivotTables.AddNew("pvtFieldAsValueAndLabel", ptSheet.Cell(1, 1), dataRange);
@@ -126,6 +135,37 @@
pt.Values.Add("Name").SetSummaryFormula(XLPivotSummary.Count);//.NumberFormat.Format = "#0.00";
+ #endregion Pivot table with a field both as a value and as a row/column/filter label
+
+ #region Pivot table with subtotals disabled
+
+ ptSheet = wb.Worksheets.Add("pvtHideSubTotals");
+
+ // Create the pivot table, using the data from the "PastrySalesData" table
+ pt = ptSheet.PivotTables.AddNew("pvtHidesubTotals", ptSheet.Cell(1, 1), dataRange);
+
+ // The rows in our pivot table will be the names of the pastries
+ pt.RowLabels.Add(XLConstants.PivotTableValuesSentinalLabel);
+
+ // The columns will be the months
+ pt.ColumnLabels.Add("Month");
+ pt.ColumnLabels.Add("Name");
+
+ // The values in our table will come from the "NumberOfOrders" field
+ // The default calculation setting is a total of each row/column
+ pt.Values.Add("NumberOfOrders", "NumberOfOrdersPercentageOfBearclaw")
+ .ShowAsPercentageFrom("Name").And("Bearclaw")
+ .NumberFormat.Format = "0%";
+
+ pt.Values.Add("Quality", "Sum of Quality")
+ .NumberFormat.SetFormat("#,##0.00");
+
+ pt.Subtotals = XLPivotSubtotals.DoNotShow;
+
+ ptSheet.Columns().AdjustToContents();
+
+ #endregion Pivot table with subtotals disabled
+
wb.SaveAs(filePath);
}
}
diff --git a/ClosedXML_Tests/ClosedXML_Tests.csproj b/ClosedXML_Tests/ClosedXML_Tests.csproj
index 487ea3a..b3da509 100644
--- a/ClosedXML_Tests/ClosedXML_Tests.csproj
+++ b/ClosedXML_Tests/ClosedXML_Tests.csproj
@@ -80,10 +80,12 @@
+
+
@@ -285,6 +287,8 @@
+
+
diff --git a/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs b/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
index 3fca48e..3ad7f8e 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/FunctionsTests.cs
@@ -620,7 +620,7 @@
Assert.AreEqual(0, cell.Value);
cell = wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=SUM(D1,D2)");
Assert.AreEqual(0, cell.Value);
- Assert.That(() => wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=AVERAGE(D1,D2)").Value, Throws.Exception);
+ Assert.That(() => wb.Worksheet(1).Cell(3, 1).SetFormulaA1("=AVERAGE(D1,D2)").Value, Throws.TypeOf());
}
[Test]
diff --git a/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs b/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs
index a112f3d..7d39689 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/LookupTests.cs
@@ -106,6 +106,12 @@
value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8,TRUE)");
Assert.AreEqual(179.64, value);
+ value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8)");
+ Assert.AreEqual(179.64, value);
+
+ value = workbook.Evaluate("=VLOOKUP(3,Data!$B$2:$I$71,8,)");
+ Assert.AreEqual(179.64, value);
+
value = workbook.Evaluate("=VLOOKUP(14.5,Data!$B$2:$I$71,8,TRUE)");
Assert.AreEqual(174.65, value);
@@ -116,11 +122,11 @@
[Test]
public void Vlookup_Exceptions()
{
- Assert.That(() => workbook.Evaluate(@"=VLOOKUP("""",Data!$B$2:$I$71,3,FALSE)"), Throws.Exception);
- Assert.That(() => workbook.Evaluate(@"=VLOOKUP(50,Data!$B$2:$I$71,3,FALSE)"), Throws.Exception);
- Assert.That(() => workbook.Evaluate(@"=VLOOKUP(20,Data!$B$2:$I$71,9,FALSE)"), Throws.Exception);
+ Assert.That(() => workbook.Evaluate(@"=VLOOKUP("""",Data!$B$2:$I$71,3,FALSE)"), Throws.TypeOf());
+ Assert.That(() => workbook.Evaluate(@"=VLOOKUP(50,Data!$B$2:$I$71,3,FALSE)"), Throws.TypeOf());
+ Assert.That(() => workbook.Evaluate(@"=VLOOKUP(20,Data!$B$2:$I$71,9,FALSE)"), Throws.TypeOf());
- Assert.That(() => workbook.Evaluate(@"=VLOOKUP(-1,Data!$B$2:$I$71,9,TRUE)"), Throws.Exception);
+ Assert.That(() => workbook.Evaluate(@"=VLOOKUP(-1,Data!$B$2:$I$71,9,TRUE)"), Throws.TypeOf());
}
}
}
diff --git a/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs
new file mode 100644
index 0000000..5012bb5
--- /dev/null
+++ b/ClosedXML_Tests/Excel/CalcEngine/MathTrigTests.cs
@@ -0,0 +1,123 @@
+using ClosedXML.Excel;
+using NUnit.Framework;
+using System;
+
+namespace ClosedXML_Tests.Excel.CalcEngine
+{
+ [TestFixture]
+ public class MathTrigTests
+ {
+ private readonly double tolerance = 1e-10;
+
+ [Test]
+ public void Floor()
+ {
+ Object actual;
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.2)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.7)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(-1.7)");
+ Assert.AreEqual(-2, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.2, 1)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(1.7, 1)");
+ Assert.AreEqual(1, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(-1.7, 1)");
+ Assert.AreEqual(-2, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(0.4, 2)");
+ Assert.AreEqual(0, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(2.7, 2)");
+ Assert.AreEqual(2, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(7.8, 2)");
+ Assert.AreEqual(6, actual);
+
+ actual = XLWorkbook.EvaluateExpr(@"FLOOR(-5.5, -2)");
+ Assert.AreEqual(-4, actual);
+ }
+
+ [Test]
+ // Functions have to support a period first before we can implement this
+ public void FloorMath()
+ {
+ double actual;
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(24.3, 5)");
+ Assert.AreEqual(20, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(6.7)");
+ Assert.AreEqual(6, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-8.1, 2)");
+ Assert.AreEqual(-10, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, 2.1, 0)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, -2.1, 0)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, 2.1, -1)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(5.5, -2.1, -1)");
+ Assert.AreEqual(4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, 2.1, 0)");
+ Assert.AreEqual(-6.3, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, -2.1, 0)");
+ Assert.AreEqual(-6.3, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, 2.1, -1)");
+ Assert.AreEqual(-4.2, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"FLOOR.MATH(-5.5, -2.1, -1)");
+ Assert.AreEqual(-4.2, actual, tolerance);
+ }
+
+ [Test]
+ public void Mod()
+ {
+ double actual;
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(1.5, 1)");
+ Assert.AreEqual(0.5, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(3, 2)");
+ Assert.AreEqual(1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(-3, 2)");
+ Assert.AreEqual(1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(3, -2)");
+ Assert.AreEqual(-1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(-3, -2)");
+ Assert.AreEqual(-1, actual, tolerance);
+
+ //////
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(-4.3, -0.5)");
+ Assert.AreEqual(-0.3, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(6.9, -0.2)");
+ Assert.AreEqual(-0.1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(0.7, 0.6)");
+ Assert.AreEqual(0.1, actual, tolerance);
+
+ actual = (double)XLWorkbook.EvaluateExpr(@"MOD(6.2, 1.1)");
+ Assert.AreEqual(0.7, actual, tolerance);
+ }
+ }
+}
diff --git a/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs b/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs
index c59e34d..2550868 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/StatisticalTests.cs
@@ -22,7 +22,7 @@
value = ws.Evaluate("AVERAGE(G3:G45)").CastTo();
Assert.AreEqual(49.3255814, value, tolerance);
- Assert.That(() => ws.Evaluate("AVERAGE(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate("AVERAGE(D3:D45)"), Throws.TypeOf());
}
[Test]
@@ -146,7 +146,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=STDEV(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=STDEV(D3:D45)"), Throws.TypeOf());
value = ws.Evaluate(@"=STDEV(H3:H45)").CastTo();
Assert.AreEqual(47.34511769, value, tolerance);
@@ -163,7 +163,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=STDEVP(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=STDEVP(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=STDEVP(H3:H45)").CastTo();
Assert.AreEqual(46.79135458, value, tolerance);
@@ -180,7 +180,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=VAR(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=VAR(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=VAR(H3:H45)").CastTo();
Assert.AreEqual(2241.560169, value, tolerance);
@@ -197,7 +197,7 @@
{
var ws = workbook.Worksheets.First();
double value;
- Assert.That(() => ws.Evaluate(@"=VARP(D3:D45)"), Throws.Exception);
+ Assert.That(() => ws.Evaluate(@"=VARP(D3:D45)"), Throws.InvalidOperationException);
value = ws.Evaluate(@"=VARP(H3:H45)").CastTo();
Assert.AreEqual(2189.430863, value, tolerance);
diff --git a/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs b/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs
index 3a89de2..efb58d3 100644
--- a/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs
+++ b/ClosedXML_Tests/Excel/CalcEngine/TextTests.cs
@@ -1,4 +1,5 @@
using ClosedXML.Excel;
+using ClosedXML.Excel.CalcEngine;
using NUnit.Framework;
using System;
using System.Globalization;
@@ -19,13 +20,13 @@
[Test]
public void Char_Empty_Input_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Char("""")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Char("""")"), Throws.TypeOf());
}
[Test]
public void Char_Input_Too_Large()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Char(9797)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Char(9797)"), Throws.TypeOf());
}
[Test]
@@ -56,7 +57,7 @@
public void Code_Empty_Input_String()
{
// Todo: more specific exception - ValueException?
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Code("""")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Code("""")"), Throws.TypeOf());
}
[Test]
@@ -82,7 +83,7 @@
[Test]
public void Dollar_Empty_Input_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Dollar("", 3)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Dollar("", 3)"), Throws.TypeOf());
}
[Test]
@@ -121,26 +122,26 @@
[Test]
public void Find_Start_Position_Too_Large()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", ""abcdef"", 10)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", ""abcdef"", 10)"), Throws.TypeOf());
}
[Test]
public void Find_String_In_Another_Empty_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", """")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""abc"", """")"), Throws.TypeOf());
}
[Test]
public void Find_String_Not_Found()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""123"", ""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""123"", ""asdf"")"), Throws.TypeOf());
}
[Test]
public void Find_Case_Sensitive_String_Not_Found()
{
// Find is case-sensitive
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""excel"", ""Microsoft Excel 2010"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Find(""excel"", ""Microsoft Excel 2010"")"), Throws.TypeOf());
}
[Test]
@@ -159,7 +160,7 @@
[Test]
public void Fixed_Input_Is_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Fixed(""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Fixed(""asdf"")"), Throws.TypeOf());
}
[Test]
@@ -297,7 +298,7 @@
[Test]
public void Rept_Start_Is_Negative()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Rept(""Francois"", -1)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Rept(""Francois"", -1)"), Throws.TypeOf());
}
[Test]
@@ -344,7 +345,7 @@
[Test]
public void Search_No_Parameters_With_Values()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search("""", """")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search("""", """")"), Throws.TypeOf());
}
[Test]
@@ -357,31 +358,31 @@
[Test]
public void Search_Start_Position_Too_Large()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", ""abcdef"", 10)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", ""abcdef"", 10)"), Throws.TypeOf());
}
[Test]
public void Search_Empty_Input_String()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", """")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""abc"", """")"), Throws.TypeOf());
}
[Test]
public void Search_String_Not_Found()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""123"", ""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""123"", ""asdf"")"), Throws.TypeOf());
}
[Test]
public void Search_Wildcard_String_Not_Found()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""soft?2010"", ""Microsoft Excel 2010"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""soft?2010"", ""Microsoft Excel 2010"")"), Throws.TypeOf());
}
[Test]
public void Search_Start_Position_Too_Large2()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""text"", ""This is some text"", 15)"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Search(""text"", ""This is some text"", 15)"), Throws.TypeOf());
}
// http://www.excel-easy.com/examples/find-vs-search.html
@@ -517,7 +518,7 @@
[Test]
public void Value_Input_String_Is_Not_A_Number()
{
- Assert.That(() => XLWorkbook.EvaluateExpr(@"Value(""asdf"")"), Throws.Exception);
+ Assert.That(() => XLWorkbook.EvaluateExpr(@"Value(""asdf"")"), Throws.TypeOf());
}
[Test]
diff --git a/ClosedXML_Tests/Excel/Cells/XLCellTests.cs b/ClosedXML_Tests/Excel/Cells/XLCellTests.cs
index 31e66f9..2fb6166 100644
--- a/ClosedXML_Tests/Excel/Cells/XLCellTests.cs
+++ b/ClosedXML_Tests/Excel/Cells/XLCellTests.cs
@@ -83,6 +83,22 @@
}
[Test]
+ public void InsertData2()
+ {
+ IXLWorksheet ws = new XLWorkbook().Worksheets.Add("Sheet1");
+ IXLRange range = ws.Cell(2, 2).InsertData(new[] { "a", "b", "c" }, false);
+ Assert.AreEqual("Sheet1!B2:B4", range.ToString());
+ }
+
+ [Test]
+ public void InsertData3()
+ {
+ IXLWorksheet ws = new XLWorkbook().Worksheets.Add("Sheet1");
+ IXLRange range = ws.Cell(2, 2).InsertData(new[] { "a", "b", "c" }, true);
+ Assert.AreEqual("Sheet1!B2:D2", range.ToString());
+ }
+
+ [Test]
public void IsEmpty1()
{
IXLWorksheet ws = new XLWorkbook().Worksheets.Add("Sheet1");
@@ -388,5 +404,27 @@
Assert.AreEqual("\u0018", wb.Worksheets.First().FirstCell().Value);
}
}
+
+ [Test]
+ public void CanClearCellValueBySettingNullValue()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.AddWorksheet("Sheet1");
+ var cell = ws.FirstCell();
+
+ cell.Value = "Test";
+ Assert.AreEqual("Test", cell.Value);
+ Assert.AreEqual(XLCellValues.Text, cell.DataType);
+
+ string s = null;
+ cell.SetValue(s);
+ Assert.AreEqual(string.Empty, cell.Value);
+
+ cell.Value = "Test";
+ cell.Value = null;
+ Assert.AreEqual(string.Empty, cell.Value);
+ }
+ }
}
}
diff --git a/ClosedXML_Tests/Excel/Loading/LoadingTests.cs b/ClosedXML_Tests/Excel/Loading/LoadingTests.cs
index 218ae90..9ecccc6 100644
--- a/ClosedXML_Tests/Excel/Loading/LoadingTests.cs
+++ b/ClosedXML_Tests/Excel/Loading/LoadingTests.cs
@@ -27,7 +27,9 @@
@"Misc\InvalidPrintTitles.xlsx",
@"Misc\ExcelProducedWorkbookWithImages.xlsx",
@"Misc\EmptyCellValue.xlsx",
- @"Misc\AllShapes.xlsx"
+ @"Misc\AllShapes.xlsx",
+ @"Misc\TableHeadersWithLineBreaks.xlsx",
+ @"Misc\TableWithNameNull.xlsx"
};
foreach (var file in files)
diff --git a/ClosedXML_Tests/Excel/Misc/FormulaTests.cs b/ClosedXML_Tests/Excel/Misc/FormulaTests.cs
index 8d2d470..16ac2a1 100644
--- a/ClosedXML_Tests/Excel/Misc/FormulaTests.cs
+++ b/ClosedXML_Tests/Excel/Misc/FormulaTests.cs
@@ -156,5 +156,22 @@
Assert.AreEqual(6, actual);
}
}
+
+ [Test]
+ public void FormulaThatStartsWithEqualsAndPlus()
+ {
+ object actual;
+ actual = XLWorkbook.EvaluateExpr("=MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+
+ actual = XLWorkbook.EvaluateExpr("=+MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+
+ actual = XLWorkbook.EvaluateExpr("=+++++MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+
+ actual = XLWorkbook.EvaluateExpr("+MID(\"This is a test\", 6, 2)");
+ Assert.AreEqual("is", actual);
+ }
}
}
diff --git a/ClosedXML_Tests/Excel/Misc/SearchTests.cs b/ClosedXML_Tests/Excel/Misc/SearchTests.cs
new file mode 100644
index 0000000..0da76e2
--- /dev/null
+++ b/ClosedXML_Tests/Excel/Misc/SearchTests.cs
@@ -0,0 +1,78 @@
+using ClosedXML.Excel;
+using NUnit.Framework;
+using System.Globalization;
+using System.Linq;
+
+namespace ClosedXML_Tests.Excel.Misc
+{
+ [TestFixture]
+ public class SearchTests
+ {
+ [Test]
+ public void TestSearch()
+ {
+ using (var stream = TestHelper.GetStreamFromResource(TestHelper.GetResourcePath(@"Examples\Misc\CellValues.xlsx")))
+ using (var wb = new XLWorkbook(stream))
+ {
+ var ws = wb.Worksheets.First();
+
+ IXLCells foundCells;
+
+ foundCells = ws.Search("Initial Value");
+ Assert.AreEqual(1, foundCells.Count());
+ Assert.AreEqual("B2", foundCells.Single().Address.ToString());
+ Assert.AreEqual("Initial Value", foundCells.Single().GetString());
+
+ foundCells = ws.Search("Using");
+ Assert.AreEqual(2, foundCells.Count());
+ Assert.AreEqual("D2", foundCells.First().Address.ToString());
+ Assert.AreEqual("Using Get...()", foundCells.First().GetString());
+ Assert.AreEqual(2, foundCells.Count());
+ Assert.AreEqual("E2", foundCells.Last().Address.ToString());
+ Assert.AreEqual("Using GetValue()", foundCells.Last().GetString());
+
+ foundCells = ws.Search("1234");
+ Assert.AreEqual(4, foundCells.Count());
+ Assert.AreEqual("C5,D5,E5,F5", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("Sep");
+ Assert.AreEqual(2, foundCells.Count());
+ Assert.AreEqual("B3,G3", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("1234", CompareOptions.Ordinal, true);
+ Assert.AreEqual(5, foundCells.Count());
+ Assert.AreEqual("B5,C5,D5,E5,F5", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("test case", CompareOptions.Ordinal);
+ Assert.AreEqual(0, foundCells.Count());
+
+ foundCells = ws.Search("test case", CompareOptions.OrdinalIgnoreCase);
+ Assert.AreEqual(6, foundCells.Count());
+ }
+ }
+
+ [Test]
+ public void TestSearch2()
+ {
+ using (var stream = TestHelper.GetStreamFromResource(TestHelper.GetResourcePath(@"Examples\Misc\Formulas.xlsx")))
+ using (var wb = new XLWorkbook(stream))
+ {
+ var ws = wb.Worksheets.First();
+
+ IXLCells foundCells;
+
+ foundCells = ws.Search("3", CompareOptions.Ordinal);
+ Assert.AreEqual(10, foundCells.Count());
+ Assert.AreEqual("C2", foundCells.First().Address.ToString());
+
+ foundCells = ws.Search("A2", CompareOptions.Ordinal, true);
+ Assert.AreEqual(4, foundCells.Count());
+ Assert.AreEqual("C2,D2,B6,A11", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+
+ foundCells = ws.Search("RC", CompareOptions.Ordinal, true);
+ Assert.AreEqual(3, foundCells.Count());
+ Assert.AreEqual("E2,E3,E4", string.Join(",", foundCells.Select(c => c.Address.ToString()).ToArray()));
+ }
+ }
+ }
+}
diff --git a/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs b/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs
index 907bc96..afe5c7b 100644
--- a/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs
+++ b/ClosedXML_Tests/Excel/NamedRanges/NamedRangesTests.cs
@@ -140,5 +140,38 @@
Assert.Throws(() => wb.NamedRanges.Add("MyRange", "A1:C1"));
}
}
+
+ [Test]
+ public void NamedRangesWhenCopyingWorksheets()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws1 = wb.AddWorksheet("Sheet1");
+ ws1.FirstCell().Value = Enumerable.Range(1, 10);
+ wb.NamedRanges.Add("wbNamedRange", ws1.Range("A1:A10"));
+ ws1.NamedRanges.Add("wsNamedRange", ws1.Range("A3"));
+
+ var ws2 = wb.AddWorksheet("Sheet2");
+ ws2.FirstCell().Value = Enumerable.Range(101, 10);
+ ws1.NamedRanges.Add("wsNamedRangeAcrossSheets", ws2.Range("A4"));
+
+ ws1.Cell("C1").FormulaA1 = "=wbNamedRange";
+ ws1.Cell("C2").FormulaA1 = "=wsNamedRange";
+ ws1.Cell("C3").FormulaA1 = "=wsNamedRangeAcrossSheets";
+
+ Assert.AreEqual(1, ws1.Cell("C1").Value);
+ Assert.AreEqual(3, ws1.Cell("C2").Value);
+ Assert.AreEqual(104, ws1.Cell("C3").Value);
+
+ var wsCopy = ws1.CopyTo("Copy");
+ Assert.AreEqual(1, wsCopy.Cell("C1").Value);
+ Assert.AreEqual(3, wsCopy.Cell("C2").Value);
+ Assert.AreEqual(104, wsCopy.Cell("C3").Value);
+
+ Assert.AreEqual("Sheet1!A1:A10", wb.NamedRange("wbNamedRange").Ranges.First().RangeAddress.ToStringRelative(true));
+ Assert.AreEqual("Copy!A3:A3", wsCopy.NamedRange("wsNamedRange").Ranges.First().RangeAddress.ToStringRelative(true));
+ Assert.AreEqual("Sheet2!A4:A4", wsCopy.NamedRange("wsNamedRangeAcrossSheets").Ranges.First().RangeAddress.ToStringRelative(true));
+ }
+ }
}
}
diff --git a/ClosedXML_Tests/Excel/Rows/RowTests.cs b/ClosedXML_Tests/Excel/Rows/RowTests.cs
index 17cddeb..bb74d4f 100644
--- a/ClosedXML_Tests/Excel/Rows/RowTests.cs
+++ b/ClosedXML_Tests/Excel/Rows/RowTests.cs
@@ -185,6 +185,36 @@
}
[Test]
+ public void InsertingRowsAbove4()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws = wb.Worksheets.Add("Sheet1");
+
+ ws.Row(2).Height = 15;
+ ws.Row(3).Height = 20;
+ ws.Row(4).Height = 25;
+ ws.Row(5).Height = 35;
+
+ ws.Row(2).FirstCell().SetValue("Row height: 15");
+ ws.Row(3).FirstCell().SetValue("Row height: 20");
+ ws.Row(4).FirstCell().SetValue("Row height: 25");
+ ws.Row(5).FirstCell().SetValue("Row height: 35");
+
+ ws.Range("3:3").InsertRowsAbove(1);
+
+ Assert.AreEqual(15, ws.Row(2).Height);
+ Assert.AreEqual(20, ws.Row(4).Height);
+ Assert.AreEqual(25, ws.Row(5).Height);
+ Assert.AreEqual(35, ws.Row(6).Height);
+
+ Assert.AreEqual(20, ws.Row(3).Height);
+ ws.Row(3).ClearHeight();
+ Assert.AreEqual(ws.RowHeight, ws.Row(3).Height);
+ }
+ }
+
+ [Test]
public void NoRowsUsed()
{
var wb = new XLWorkbook();
@@ -224,4 +254,4 @@
ws.Rows(1, 2).Ungroup(true);
}
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML_Tests/Excel/Saving/SavingTests.cs b/ClosedXML_Tests/Excel/Saving/SavingTests.cs
index ca2fd98..60a1d7a 100644
--- a/ClosedXML_Tests/Excel/Saving/SavingTests.cs
+++ b/ClosedXML_Tests/Excel/Saving/SavingTests.cs
@@ -34,6 +34,35 @@
}
[Test]
+ public void CanSaveFileMultipleTimesAfterDeletingWorksheet()
+ {
+ // https://github.com/ClosedXML/ClosedXML/issues/435
+
+
+ using (var ms = new MemoryStream())
+ {
+ using (XLWorkbook book1 = new XLWorkbook())
+ {
+ book1.AddWorksheet("sheet1");
+ book1.AddWorksheet("sheet2");
+
+ book1.SaveAs(ms);
+ }
+ ms.Position = 0;
+
+ using (XLWorkbook book2 = new XLWorkbook(ms))
+ {
+ var ws = book2.Worksheet(1);
+ Assert.AreEqual("sheet1", ws.Name);
+ ws.Delete();
+ book2.Save();
+ book2.Save();
+ }
+ }
+ }
+
+
+ [Test]
public void CanSaveAndValidateFileInAnotherCulture()
{
string[] cultures = new string[] { "it", "de-AT" };
diff --git a/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs b/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs
index 3c94664..326340b 100644
--- a/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs
+++ b/ClosedXML_Tests/Excel/Styles/NumberFormatTests.cs
@@ -14,7 +14,6 @@
using (var wb = new XLWorkbook())
{
var ws = wb.AddWorksheet("Sheet1");
- ws.Column(1).Style.NumberFormat.Format = "yy-MM-dd";
var table = new DataTable();
table.Columns.Add("Date", typeof(DateTime));
@@ -24,9 +23,13 @@
table.Rows.Add(new DateTime(2017, 1, 1).AddMonths(i));
}
+ ws.Column(1).Style.NumberFormat.Format = "yy-MM-dd";
ws.Cell("A1").InsertData(table.AsEnumerable());
-
Assert.AreEqual("yy-MM-dd", ws.Cell("A5").Style.DateFormat.Format);
+
+ ws.Row(1).Style.NumberFormat.Format = "yy-MM-dd";
+ ws.Cell("A1").InsertData(table.AsEnumerable(), true);
+ Assert.AreEqual("yy-MM-dd", ws.Cell("E1").Style.DateFormat.Format);
}
}
}
diff --git a/ClosedXML_Tests/Excel/Tables/TablesTests.cs b/ClosedXML_Tests/Excel/Tables/TablesTests.cs
index 12d0c2d..1a35952 100644
--- a/ClosedXML_Tests/Excel/Tables/TablesTests.cs
+++ b/ClosedXML_Tests/Excel/Tables/TablesTests.cs
@@ -1,4 +1,4 @@
-using ClosedXML.Attributes;
+using ClosedXML.Attributes;
using ClosedXML.Excel;
using NUnit.Framework;
using System;
@@ -391,6 +391,12 @@
tbl.SetShowHeaderRow(true);
nameAfter = tbl.Cell("B1").Value.ToString();
Assert.AreEqual("LastNameChanged", nameAfter);
+
+ var field = tbl.Field("LastNameChanged");
+ Assert.AreEqual("LastNameChanged", field.Name);
+
+ tbl.Cell(1, 1).Value = "FirstName";
+ Assert.AreEqual("FirstName", tbl.Field(0).Name);
}
}
diff --git a/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs b/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs
index f679187..0918e5a 100644
--- a/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs
+++ b/ClosedXML_Tests/Excel/Worksheets/XLWorksheetTests.cs
@@ -140,5 +140,25 @@
Assert.AreEqual(6, value);
}
}
+
+ [Test]
+ public void CanRenameWorksheet()
+ {
+ using (var wb = new XLWorkbook())
+ {
+ var ws1 = wb.AddWorksheet("Sheet1");
+ var ws2 = wb.AddWorksheet("Sheet2");
+
+ ws1.Name = "New sheet name";
+ Assert.AreEqual("New sheet name", ws1.Name);
+
+ ws2.Name = "sheet2";
+ Assert.AreEqual("sheet2", ws2.Name);
+
+ Assert.Throws(() => ws1.Name = "SHEET2");
+
+
+ }
+ }
}
-}
\ No newline at end of file
+}
diff --git a/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx b/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx
index 9e9d20f..c8ae77a 100644
--- a/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/Misc/InsertingData.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx b/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx
index 6e3156d..7c0b68e 100644
--- a/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx
+++ b/ClosedXML_Tests/Resource/Examples/PivotTables/PivotTables.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Misc/TableHeadersWithLineBreaks.xlsx b/ClosedXML_Tests/Resource/Misc/TableHeadersWithLineBreaks.xlsx
new file mode 100644
index 0000000..8e7dbdc
--- /dev/null
+++ b/ClosedXML_Tests/Resource/Misc/TableHeadersWithLineBreaks.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/Resource/Misc/TableWithNameNull.xlsx b/ClosedXML_Tests/Resource/Misc/TableWithNameNull.xlsx
new file mode 100644
index 0000000..0a5a8de
--- /dev/null
+++ b/ClosedXML_Tests/Resource/Misc/TableWithNameNull.xlsx
Binary files differ
diff --git a/ClosedXML_Tests/packages.config b/ClosedXML_Tests/packages.config
index c32aa84..5e0ab7c 100644
--- a/ClosedXML_Tests/packages.config
+++ b/ClosedXML_Tests/packages.config
@@ -1,5 +1,5 @@
-
-
-
-
+
+
+
+
\ No newline at end of file