diff --git a/src/EPPlus/Core/Worksheet/WorksheetCopyHelper.cs b/src/EPPlus/Core/Worksheet/WorksheetCopyHelper.cs
index 9949fb8a3..8c4c9ad29 100644
--- a/src/EPPlus/Core/Worksheet/WorksheetCopyHelper.cs
+++ b/src/EPPlus/Core/Worksheet/WorksheetCopyHelper.cs
@@ -1001,7 +1001,7 @@ private static bool HasExternalReference(string formula)
{
if(formula!=null && formula.IndexOf('[') >= 0)
{
- var t=SourceCodeTokenizer.Default.Tokenize(formula);
+ var t=SourceCodeTokenizer.Default.Tokenize(formula);
return t.Any(x => x.TokenType == TokenType.ExternalReference);
}
return false;
diff --git a/src/EPPlus/DataValidation/ExcelDatavalidationAddress.cs b/src/EPPlus/DataValidation/ExcelDatavalidationAddress.cs
index ecd34940a..d622521b1 100644
--- a/src/EPPlus/DataValidation/ExcelDatavalidationAddress.cs
+++ b/src/EPPlus/DataValidation/ExcelDatavalidationAddress.cs
@@ -25,7 +25,7 @@ internal ExcelDatavalidationAddress(string address, ExcelDataValidation val) : b
///
/// Called before the address changes
///
- internal protected override void BeforeChangeAddress()
+ internal protected override void BeforeChangeAddress(string value)
{
addressBeforeChange = _val.Address;
_val._ws.DataValidations.ClearRangeDictionary(_val.Address);
@@ -34,7 +34,7 @@ internal protected override void BeforeChangeAddress()
///
/// Called when the address changes
///
- internal protected override void ChangeAddress()
+ internal protected override void ChangeAddress(string value)
{
_val._ws.DataValidations.dvQuadTree.UpdateAddress(addressBeforeChange, _val.Address, _val);
_val._ws.DataValidations.AddToRangeDictionary(_val);
diff --git a/src/EPPlus/ExcelAddress.cs b/src/EPPlus/ExcelAddress.cs
index 421a0fbdf..48dc7352a 100644
--- a/src/EPPlus/ExcelAddress.cs
+++ b/src/EPPlus/ExcelAddress.cs
@@ -104,10 +104,10 @@ public ExcelAddress(string Address, ExcelPackage package, ExcelAddressBase refer
}
set
{
- BeforeChangeAddress();
+ BeforeChangeAddress(value);
SetAddress(value, null, null);
- ChangeAddress();
+ ChangeAddress(value);
}
- }
+ }
}
}
diff --git a/src/EPPlus/ExcelAddressBase.cs b/src/EPPlus/ExcelAddressBase.cs
index 841c1453f..e196bc689 100644
--- a/src/EPPlus/ExcelAddressBase.cs
+++ b/src/EPPlus/ExcelAddressBase.cs
@@ -466,17 +466,15 @@ internal ExcelAddressBase ToInternalAddress()
///
/// Method for actions that must be taken before address is changed
///
- internal protected virtual void BeforeChangeAddress()
+ internal protected virtual void BeforeChangeAddress(string value)
{
}
///
/// Called when the address changes
///
- internal protected virtual void ChangeAddress()
+ internal protected virtual void ChangeAddress(string value)
{
}
-
-
private void SetWbWs(string address)
{
int pos;
diff --git a/src/EPPlus/ExcelFormulaAddress.cs b/src/EPPlus/ExcelFormulaAddress.cs
index 157bd9316..029822d39 100644
--- a/src/EPPlus/ExcelFormulaAddress.cs
+++ b/src/EPPlus/ExcelFormulaAddress.cs
@@ -122,7 +122,7 @@ private void GetFixed(string address, out bool rowFixed, out bool colFixed)
set
{
SetAddress(value, null, null);
- ChangeAddress();
+ ChangeAddress(value);
SetFixed();
}
}
diff --git a/src/EPPlus/ExcelNamedRange.cs b/src/EPPlus/ExcelNamedRange.cs
index d7700d9f6..63dbd3b7f 100644
--- a/src/EPPlus/ExcelNamedRange.cs
+++ b/src/EPPlus/ExcelNamedRange.cs
@@ -11,16 +11,13 @@ Date Author Change
01/27/2020 EPPlus Software AB Initial release EPPlus 5
*************************************************************************************************/
using OfficeOpenXml.Core;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.Information;
-using OfficeOpenXml.FormulaParsing.Excel.Functions.MathFunctions;
using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
using OfficeOpenXml.FormulaParsing.Ranges;
using System;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using OfficeOpenXml.Utils;
using OfficeOpenXml.FormulaParsing;
+using OfficeOpenXml.Utils.Formula;
namespace OfficeOpenXml
{
@@ -142,11 +139,213 @@ internal object NameValue
set;
}
IList _tokens = null;
+ ///
+ /// Set to true to validate and update formulas with cell references.
+ ///
+ public static bool ValidateCellAddressInFormulas = true;
+ private string _nameFormula;
internal string NameFormula
{
- get;
- set;
- }
+ get
+ {
+ return _nameFormula;
+ }
+ set
+ {
+ if (value == null)
+ {
+ _nameFormula = value;
+ return;
+ }
+ _nameFormula = ValidateCellAddressInFormulas ? FormulaUtils.AddWorksheetReferenceToFormula(value, _worksheet, AllowRelativeAddress) : value;
+ }
+ }
+ ///
+ protected internal override void BeforeChangeAddress(string value)
+ {
+ if(!string.IsNullOrEmpty(value) && !value.Contains("!") && Worksheet == null)
+ {
+ throw new InvalidOperationException("Workbook name needs a worksheet in the address.");
+ }
+
+ }
+ ///
+ protected internal override void ChangeAddress(string value)
+ {
+
+ }
+
+ ///
+ /// Set a range for this name. Will remove exsisting formula and value.
+ ///
+ ///
+ ///
+ public void SetRange(ExcelRangeBase range, bool allowRelativeAddress = false)
+ {
+ if (range.Worksheet != _worksheet)
+ {
+ throw new InvalidOperationException($"Cannot change range to another worksheet or set a range to a workbook name: {Name}. Either create a new name or move current name first.");
+ }
+ ResetObject();
+ NameFormula = null;
+ NameValue = null;
+
+ _workbook = range._workbook;
+ _worksheet = range._worksheet;
+ if (allowRelativeAddress)
+ {
+ Address = range.FullAddress;
+ }
+ else
+ {
+ Address = range.FullAddressAbsolute;
+ }
+ Value = range.Value;
+ }
+
+ ///
+ /// Set a formula for this name. Will remove exsisting range and value.
+ ///
+ /// The formula for this name.
+ public void SetFormula(string formula)
+ {
+ ResetObject();
+ NameFormula = formula;
+ this.Formula = NameFormula;
+ NameValue = null;
+ }
+ ///
+ /// Get a formula for this name.
+ ///
+ /// The formula for this name.
+ public string GetFormula()
+ {
+ return NameFormula;
+ }
+
+ ///
+ /// Set a value for this name. Will remove exsisting range and formula.
+ ///
+ ///
+ public void SetValue(object value)
+ {
+ ResetObject();
+ NameFormula = null;
+ NameValue = value;
+ Value = value;
+ }
+ ///
+ /// Get a value for this name.
+ ///
+ ///
+ public object GetValue()
+ {
+ return NameValue;
+ }
+
+ ///
+ /// Move this defined name to a target worksheet.
+ ///
+ /// Worksheet to move this name to.
+ /// /// Optional new name for the defined name.
+ /// This name.
+ /// If this name does not contain a formula, value or range, this exception occurs.
+ public ExcelNamedRange Move(ExcelWorksheet worksheet, string name = null)
+ {
+ ExcelNamedRange enr = null;
+ name = name == null ? Name : name;
+ //Detect if formula, value or range
+ if (NameFormula != null)
+ enr = worksheet.Names.AddFormula(Name, NameFormula);
+ else if (NameValue != null)
+ enr = worksheet.Names.AddValue(Name, NameValue);
+ else if (LocalAddress != "#REF!")
+ enr = worksheet.Names.AddRange(Name, worksheet.Cells[Address]);
+ if (enr == null) throw new InvalidOperationException($"No value, formula or address has been set for this name: {Name}");
+ if(_worksheet != null)
+ _worksheet.Names.Remove(Name);
+ else if(_workbook != null)
+ _workbook.Names.Remove(Name);
+ else
+ throw new InvalidOperationException($"No workbook or worksheet has been set for this name: {Name}");
+ return enr;
+ }
+ ///
+ /// Move this defined name to target workbook.
+ ///
+ /// Workbook to move this name to.
+ /// Optional new name for the defined name.
+ /// This name.
+ /// If this name does not contain a formula, value or range, this exception occurs.
+ public ExcelNamedRange Move(ExcelWorkbook workbook, string name = null)
+ {
+ ExcelNamedRange enr = null;
+ name = name == null ? Name : name;
+ //Detect if formula, value or range
+ if (NameFormula != null)
+ enr = workbook.Names.AddFormula(Name, NameFormula);
+ else if (NameValue != null)
+ enr = workbook.Names.AddValue(Name, NameValue);
+ else if (LocalAddress != "#REF!")
+ enr = workbook.Names.AddRange(Name, _worksheet.Cells[Address]);
+ if(enr == null) throw new InvalidOperationException($"No value, formula or address has been set for this name: {Name}");
+ if (_worksheet != null)
+ _worksheet.Names.Remove(Name);
+ else if (_workbook != null)
+ _workbook.Names.Remove(Name);
+ else
+ throw new InvalidOperationException($"No workbook or worksheet has been set for this name: {Name}");
+ return enr;
+ }
+ ///
+ /// Creates a copy of the defined name to target worksheet.
+ ///
+ /// Worksheet to copy to.
+ /// The name for the copy.
+ /// A new ExcelNameRange
+ /// If the original does not contain a formula, value or range, this exception occurs.
+ public ExcelNamedRange Copy(ExcelWorksheet worksheet, string name)
+ {
+ //Detect if formula, value or range
+ if (NameFormula != null)
+ return worksheet.Names.AddFormula(name, NameFormula);
+ else if (NameValue != null)
+ return worksheet.Names.AddValue(name, NameValue);
+ else if (LocalAddress != "#REF!")
+ return worksheet.Names.AddRange(name, worksheet.Cells[Address]);
+ throw new InvalidOperationException($"No value, formula or address has been set for this name: {Name}");
+ }
+ ///
+ /// Creates a copy of the defined name to target workbook.
+ ///
+ /// Workbook to copy to.
+ /// The name for the copy.
+ /// A new ExcelNameRange
+ /// If the original does not contain a formula, value or range, this exception occurs.
+ public ExcelNamedRange Copy(ExcelWorkbook workbook, string name)
+ {
+ //Detect if formula, value or range
+ if (NameFormula != null)
+ return workbook.Names.AddFormula(name, NameFormula);
+ else if (NameValue != null)
+ return workbook.Names.AddValue(name, NameValue);
+ else if (LocalAddress != "#REF!")
+ return workbook.Names.AddRange(name, _worksheet.Cells[Address]);
+ throw new InvalidOperationException($"No value, formula or address has been set for this name: {Name}");
+ }
+
+ private void ResetObject()
+ {
+ Init(Name, _sheet, Index, AllowRelativeAddress);
+ _address = Name;
+ _fromCol = -1;
+ _fromRow = -1;
+ _toCol = -1;
+ _toRow = -1;
+ _start = null;
+ _end = null;
+ }
+
string _r1c1Formula = "";
internal string GetRelativeFormula(int row, int col)
{
@@ -305,7 +504,7 @@ internal object GetValue(FormulaCellAddress currentCell)
}
else
{
- var values = NameValue as Dictionary;
+ var values = NameValue as Dictionary;
if(values!=null)
{
if(values.ContainsKey(currentCell.CellId))
diff --git a/src/EPPlus/ExcelNamedRangeCollection.cs b/src/EPPlus/ExcelNamedRangeCollection.cs
index 5e49c185a..e5094db59 100644
--- a/src/EPPlus/ExcelNamedRangeCollection.cs
+++ b/src/EPPlus/ExcelNamedRangeCollection.cs
@@ -16,6 +16,9 @@ Date Author Change
using System.Collections;
using System.Linq;
using OfficeOpenXml.FormulaParsing.ExcelUtilities;
+using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
+using OfficeOpenXml.FormulaParsing.Excel.Functions.Text;
+using OfficeOpenXml.Utils.Formula;
namespace OfficeOpenXml
{
@@ -68,6 +71,38 @@ public ExcelNamedRange Add(string Name, ExcelRangeBase Range)
return Add(Name, Range, false);
}
+ ///
+ /// Adds a new named formula
+ ///
+ /// The name
+ /// The formula
+ ///
+ public ExcelNamedRange Add(string Name, string formula)
+ {
+ return AddFormula(Name, formula);
+ }
+
+ ///
+ /// Adds a new value
+ ///
+ /// The name
+ /// The value
+ ///
+ public ExcelNamedRange Add(string Name, object value)
+ {
+ return AddValue(Name, value);
+ }
+ ///
+ /// Adds a new named range
+ ///
+ /// The name
+ /// The range
+ ///
+ ///
+ public ExcelNamedRange AddRange(string name, ExcelRangeBase range, bool allowRelativeAddress = false )
+ {
+ return Add(name, range, allowRelativeAddress);
+ }
///
/// Adds the name without validation as Excel allows some names on load that is not permitted in the GUI
///
@@ -114,11 +149,10 @@ private void AddName(string Name, ExcelNamedRange item)
///
public ExcelNamedRange AddValue(string Name, object value)
{
- if (!ExcelAddressUtil.IsValidName(Name))
- {
- throw (new ArgumentException("Name contains invalid characters or is not valid."));
- }
-
+ if (!ExcelAddressUtil.IsValidName(Name))
+ {
+ throw (new ArgumentException("Name contains invalid characters or is not valid."));
+ }
var item = new ExcelNamedRange(Name,_wb, _ws, _dic.Count);
item.NameValue = value;
AddName(Name, item);
@@ -132,24 +166,22 @@ public ExcelNamedRange AddValue(string Name, object value)
///
///
public ExcelNamedRange AddFormula(string Name, string Formula)
- {
- if (!ExcelAddressUtil.IsValidName(Name))
- {
- throw (new ArgumentException("Name contains invalid characters or is not valid."));
- }
-
- return AddFormulaNoValidation(Name, Formula);
- }
-
- internal ExcelNamedRange AddFormulaNoValidation(string Name, string Formula)
- {
- var item = new ExcelNamedRange(Name, _wb, _ws, _dic.Count);
- item.NameFormula = Formula;
- AddName(Name, item);
- return item;
- }
+ {
+ if (!ExcelAddressUtil.IsValidName(Name))
+ {
+ throw (new ArgumentException("Name contains invalid characters or is not valid."));
+ }
+ return AddFormulaNoValidation(Name, Formula);
+ }
- internal void Insert(int rowFrom, int colFrom, int rows, int cols, int lowerLimint = 0, int upperLimit = int.MaxValue)
+ internal ExcelNamedRange AddFormulaNoValidation(string Name, string Formula)
+ {
+ var item = new ExcelNamedRange(Name, _wb, _ws, _dic.Count);
+ item.NameFormula = Formula;
+ AddName(Name, item);
+ return item;
+ }
+ internal void Insert(int rowFrom, int colFrom, int rows, int cols, int lowerLimint = 0, int upperLimit = int.MaxValue)
{
Insert(rowFrom, colFrom, rows, cols, n => true, lowerLimint, upperLimit);
}
diff --git a/src/EPPlus/ExcelRange.cs b/src/EPPlus/ExcelRange.cs
index 4ca131c49..f253b1d5c 100644
--- a/src/EPPlus/ExcelRange.cs
+++ b/src/EPPlus/ExcelRange.cs
@@ -67,7 +67,7 @@ public ExcelRange this[string Address]
}
}
SetAddress(Address, _workbook, _worksheet.Name);
- ChangeAddress();
+ ChangeAddress(_address);
}
if((_fromRow < 1 || _fromCol < 1) && Address.Equals("#REF!", StringComparison.InvariantCultureIgnoreCase)==false)
{
@@ -118,7 +118,7 @@ private ExcelRange GetTableAddess(ExcelWorksheet _worksheet, string address)
_end = null;
_addresses = null;
_address = GetAddress(_fromRow, _fromCol);
- ChangeAddress();
+ ChangeAddress(_address);
return this;
}
}
@@ -148,7 +148,7 @@ private ExcelRange GetTableAddess(ExcelWorksheet _worksheet, string address)
_end = null;
_addresses = null;
_address = GetAddress(_fromRow, _fromCol, _toRow, _toCol);
- ChangeAddress();
+ ChangeAddress(_address);
return this;
}
}
diff --git a/src/EPPlus/ExcelRangeBase.cs b/src/EPPlus/ExcelRangeBase.cs
index 1dd381478..089f3af3f 100644
--- a/src/EPPlus/ExcelRangeBase.cs
+++ b/src/EPPlus/ExcelRangeBase.cs
@@ -98,7 +98,7 @@ private void Init(ExcelWorksheet xlWorksheet)
///
/// On change address handler
///
- protected internal override void ChangeAddress()
+ protected internal override void ChangeAddress(string value)
{
if (Table != null)
{
diff --git a/src/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs b/src/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs
index 0e47f7030..f1e1cdd2c 100644
--- a/src/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs
+++ b/src/EPPlus/FormulaParsing/LexicalAnalysis/Token.cs
@@ -10,11 +10,6 @@ Date Author Change
*************************************************************************************************
01/27/2020 EPPlus Software AB Initial release EPPlus 5
*************************************************************************************************/
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis
{
///
@@ -23,7 +18,7 @@ namespace OfficeOpenXml.FormulaParsing.LexicalAnalysis
public struct Token
{
const ushort IS_NEGATED=0x0001;
- internal Token(TokenType tokenType)
+ internal Token(TokenType tokenType)
{
TokenType = tokenType;
Value = null;
diff --git a/src/EPPlus/Utils/Formula/FormulaUtils.cs b/src/EPPlus/Utils/Formula/FormulaUtils.cs
new file mode 100644
index 000000000..2d2ddd872
--- /dev/null
+++ b/src/EPPlus/Utils/Formula/FormulaUtils.cs
@@ -0,0 +1,67 @@
+using OfficeOpenXml.FormulaParsing.Exceptions;
+using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace OfficeOpenXml.Utils.Formula
+{
+ internal static class FormulaUtils
+ {
+ ///
+ /// This method detects cell addresses and updates them so they have reference to the supplied worksheet. Example: SUM(A1 + B2) becomes SUM('Sheet 1'A$1$ + 'Sheet 1'!$B$2)
+ ///
+ /// Formula to check
+ /// Worksheet to add
+ /// If address is relative or absolute. Default is absolute.
+ /// A string containing the formual with worksheet reference on cell addresses.
+ /// If worksheet is null and a cell address is found this method will throw this exception. Setting worksheet to null could be usefull for checking validity of formulas on workbook.
+ internal static string AddWorksheetReferenceToFormula(string formula, ExcelWorksheet ws, bool allowRelativeAddress = false)
+ {
+ bool isWsNull = ws == null ? true : false;
+ var tokens = SourceCodeTokenizer.Default.Tokenize(formula);
+ Dictionary addresses = new Dictionary();
+ List fixedTokens = new List();
+ //Collect tokens
+ for (int i = 0; i < tokens.Count; i++)
+ {
+ if (tokens[i].TokenType == TokenType.CellAddress)
+ {
+ if (isWsNull) throw new InvalidFormulaException("Formula with cell address must have a worksheet.");
+ if (i == 0)
+ {
+ addresses.Add(i, tokens[i]);
+ }
+ else if (tokens[i - 1].TokenType != TokenType.WorksheetName)
+ {
+ addresses.Add(i, tokens[i]);
+ }
+ }
+ }
+ //if no cell address tokens found we can quit early and return the formula as is.
+ if (addresses.Count == 0)
+ {
+ return formula;
+ }
+ //Update tokens
+ for (int i = 0; i < tokens.Count; i++)
+ {
+ if (addresses.ContainsKey(i))
+ {
+ string fullAddress = allowRelativeAddress ? ws.Cells[addresses[i].Value].FullAddress : ws.Cells[addresses[i].Value].FullAddressAbsolute;
+ var addressTokens = SourceCodeTokenizer.Default.Tokenize(fullAddress);
+ for (int j = 0; j < addressTokens.Count; j++)
+ {
+ fixedTokens.Add(addressTokens[j]);
+ }
+ }
+ else
+ {
+ fixedTokens.Add(tokens[i]);
+ }
+ }
+ //Create new formula string.
+ return string.Concat(fixedTokens.Select(t => t.Value));
+ }
+
+ }
+}
diff --git a/src/EPPlusTest/Core/ExternalReferenceTest.cs b/src/EPPlusTest/Core/ExternalReferenceTest.cs
index 937da5c44..0320ca1cc 100644
--- a/src/EPPlusTest/Core/ExternalReferenceTest.cs
+++ b/src/EPPlusTest/Core/ExternalReferenceTest.cs
@@ -84,7 +84,7 @@ public void OpenAndCalculateExternalLinkFromCache()
public void OpenAndCalculateExternalLinkFromPackage()
{
var p = OpenTemplatePackage("ExternalReferences\\ExtRef.xlsx");
-
+ ExcelNamedRange.ValidateCellAddressInFormulas = false;
p.Workbook.ExternalLinks.Directories.Add(new DirectoryInfo(_testInputPathOptional));
p.Workbook.ExternalLinks.LoadWorkbooks();
p.Workbook.ExternalLinks[0].As.ExternalWorkbook.Package.Workbook.Calculate();
@@ -275,8 +275,8 @@ public void UpdateCacheShouldBeSameAsExcel()
{
var p = OpenTemplatePackage("ExternalReferences\\ExtRef.xlsx");
-
-
+
+ ExcelNamedRange.ValidateCellAddressInFormulas = false;
var er = p.Workbook.ExternalLinks[0].As.ExternalWorkbook;
var excelCache = GetExternalCache(er);
@@ -312,6 +312,7 @@ public void UpdateCacheShouldBeSameAsExcel()
public void AddExternalLinkShouldBeSameAsExcel()
{
var p = OpenPackage("AddedExtRef.xlsx", true);
+ ExcelNamedRange.ValidateCellAddressInFormulas = false;
var ws1=CreateWorksheet1(p);
var ws2 = p.Workbook.Worksheets.Add("Sheet2");
@@ -342,6 +343,7 @@ public void AddExternalLinkShouldBeSameAsExcel()
public void AddExternalWorkbookNoUpdate()
{
var p = OpenPackage("AddedExtRefNoUpdate.xlsx", true);
+ ExcelNamedRange.ValidateCellAddressInFormulas = false;
var ws1 = CreateWorksheet1(p);
var ws2 = p.Workbook.Worksheets.Add("Sheet2");
@@ -368,6 +370,7 @@ public void AddExternalWorkbookNoUpdate()
public void AddExternalWorkbookWithChartCache()
{
var p = OpenPackage("AddedExtRefChart.xlsx", true);
+ ExcelNamedRange.ValidateCellAddressInFormulas = false;
var ws = p.Workbook.Worksheets.Add("SheetWithChart");
var er = p.Workbook.ExternalLinks.AddExternalWorkbook(new FileInfo(_testInputPath + "externalreferences\\FromWB1.xlsx"));
diff --git a/src/EPPlusTest/Drawing/DrawingTest.cs b/src/EPPlusTest/Drawing/DrawingTest.cs
index df52883bf..1742e9d77 100644
--- a/src/EPPlusTest/Drawing/DrawingTest.cs
+++ b/src/EPPlusTest/Drawing/DrawingTest.cs
@@ -713,7 +713,7 @@ public void DrawingWorksheetCopy()
if (ws == null) Assert.Inconclusive("Shapes worksheet is missing");
var wsShapes = pck.Workbook.Worksheets.Add("Copy Shapes", ws);
- Assert.AreEqual(188, wsShapes.Drawings.Count);
+ Assert.AreEqual(187, wsShapes.Drawings.Count);
ws = pck.Workbook.Worksheets["Scatter"];
if (ws == null) Assert.Inconclusive("Scatter worksheet is missing");
diff --git a/src/EPPlusTest/WorkSheetTests.cs b/src/EPPlusTest/WorkSheetTests.cs
index 72a7c4502..47048c347 100644
--- a/src/EPPlusTest/WorkSheetTests.cs
+++ b/src/EPPlusTest/WorkSheetTests.cs
@@ -42,7 +42,9 @@ Date Author Change
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Runtime.InteropServices;
using System.Threading.Tasks;
+using OfficeOpenXml.Utils.Formula;
namespace EPPlusTest
{
@@ -867,6 +869,212 @@ public void WorksheetCopy()
}
}
[TestMethod]
+ public void NameChangeValueToRange()
+ {
+ var p = new ExcelPackage();
+ var wb = p.Workbook;
+ var ws = wb.Worksheets.Add("Sheet1");
+ ws.Cells["C3"].Value = 3;
+
+ var name = ws.Names.AddValue("Text", 9);
+ Assert.AreEqual(9, name.Value);
+
+ name.SetRange(ws.Cells["C3"]);
+ Assert.AreEqual(3, name.Value);
+
+ //SaveWorkbook("DefinedNames1315.xlsx", p);
+ }
+ [TestMethod]
+ public void NameChangeValueToFormula()
+ {
+ var p = new ExcelPackage();
+ var wb = p.Workbook;
+ var ws = wb.Worksheets.Add("Sheet1");
+ ws.Cells["C3"].Value = 3;
+
+ var name = ws.Names.AddValue("Text", 9);
+ Assert.AreEqual(9, name.Value);
+ Assert.AreEqual(null, name.Formula);
+
+ name.SetFormula("SUM(7+C3)");
+ Assert.AreEqual(null, name.Value);
+ Assert.AreEqual("SUM(7+Sheet1!$C$3)", name.Formula);
+
+ //SaveWorkbook("DefinedNames1315.xlsx", p);
+ }
+ [TestMethod]
+ public void NameChangeRangeToValue()
+ {
+ var p = new ExcelPackage();
+ var wb = p.Workbook;
+ var ws = wb.Worksheets.Add("Sheet1");
+ ws.Cells["C3"].Value = 3;
+
+ var name = ws.Names.AddRange("Text", ws.Cells["C3"]);
+ Assert.AreEqual(3, name.Value);
+
+ name.SetValue(9);
+ Assert.AreEqual(9, name.Value);
+
+ //SaveWorkbook("DefinedNames1315.xlsx", p);
+ }
+ [TestMethod]
+ public void NameChangeRangeToFormula()
+ {
+ var p = new ExcelPackage();
+ var wb = p.Workbook;
+ var ws = wb.Worksheets.Add("Sheet1");
+ ws.Cells["C3"].Value = 3;
+
+ var name = ws.Names.AddRange("Text", ws.Cells["C3"]);
+ Assert.AreEqual("", name.Formula);
+
+ name.SetFormula("SUM(7+C3)");
+ Assert.AreEqual("SUM(7+Sheet1!$C$3)", name.Formula);
+
+ SaveWorkbook("DefinedNames1315.xlsx", p);
+ }
+ [TestMethod]
+ public void NameChangeFormulaToValue()
+ {
+ var p = new ExcelPackage();
+ var wb = p.Workbook;
+ var ws = wb.Worksheets.Add("Sheet1");
+ ws.Cells["C3"].Value = 3;
+
+ var name = ws.Names.AddFormula("Text", "SUM(7+C3)");
+ Assert.AreEqual(null, name.Value);
+ Assert.AreEqual("SUM(7+Sheet1!$C$3)", name.Formula);
+
+ name.SetValue(9);
+ Assert.AreEqual(9, name.Value);
+ Assert.AreEqual(null, name.Formula);
+ //SaveWorkbook("DefinedNames1315.xlsx", p);
+ }
+ [TestMethod]
+ public void NameChangeFormulaToRange()
+ {
+ var p = new ExcelPackage();
+ var wb = p.Workbook;
+ var ws = wb.Worksheets.Add("Sheet1");
+ ws.Cells["C3"].Value = 3;
+
+ var name = ws.Names.AddFormula("Text", "SUM(7+C3)");
+ Assert.AreEqual("SUM(7+Sheet1!$C$3)", name.Formula);
+
+ name.SetRange(ws.Cells["C3"]);
+ Assert.AreEqual("", name.Formula);
+ Assert.AreEqual(3, name.Value);
+
+ //SaveWorkbook("DefinedNames1315.xlsx", p);
+ }
+
+ [TestMethod]
+ public void MoveNamesTest()
+ {
+ var p1 = new ExcelPackage();
+ var p2 = new ExcelPackage();
+
+ var wb1 = p1.Workbook;
+ var wb2 = p2.Workbook;
+
+ var ws1a = p1.Workbook.Worksheets.Add("Sheet A");
+ var ws1b = p1.Workbook.Worksheets.Add("Sheet B");
+ var ws2 = p2.Workbook.Worksheets.Add("Sheet 1");
+
+ var AB = ws1a.Names.Add("MoveMeToB", ws1a.Cells["A1"]);
+ var WbA = wb1.Names.Add("MoveMeToA", 77);
+ var AWb = ws1a.Names.Add("MoveMeToWB", "SUM(45+45+45)");
+
+ //Move name from A To B
+ Assert.AreEqual(0, ws1b.Names.Count);
+ Assert.AreEqual(2, ws1a.Names.Count);
+ AB.Move(ws1b);
+ Assert.AreEqual(1, ws1b.Names.Count);
+ Assert.AreEqual(1, ws1a.Names.Count);
+
+ //Move name from wb To A
+ Assert.AreEqual(1, ws1a.Names.Count);
+ Assert.AreEqual(1, wb1.Names.Count);
+ var moved = WbA.Move(ws1a);
+ Assert.AreEqual(2, ws1a.Names.Count);
+ Assert.AreEqual(0, wb1.Names.Count);
+
+ //Move name from A to wb
+ Assert.AreEqual(0, wb1.Names.Count);
+ AWb.Move(wb1);
+ Assert.AreEqual(1, wb1.Names.Count);
+
+ //Move name from A to wb2
+ Assert.AreEqual(0, wb2.Names.Count);
+ moved.Move(wb2);
+ Assert.AreEqual(1, wb2.Names.Count);
+
+ //SaveWorkbook("DefinedNamesCopyP1.xlsx", p1);
+ //SaveWorkbook("DefinedNamesCopyP2.xlsx", p2);
+ }
+ [TestMethod]
+ public void CopyNamesTest()
+ {
+ var p1 = new ExcelPackage();
+ var p2 = new ExcelPackage();
+
+ var wb1 = p1.Workbook;
+ var wb2 = p2.Workbook;
+
+ var ws1a = p1.Workbook.Worksheets.Add("Sheet A");
+ var ws1b = p1.Workbook.Worksheets.Add("Sheet B");
+ var ws2 = p2.Workbook.Worksheets.Add("Sheet 1");
+
+ var AB = ws1a.Names.Add("CopyMeToB", ws1a.Cells["A1"]);
+ var WbA = wb1.Names.Add("CopyMeToA", 77);
+ var AWb = ws1a.Names.Add("CopyMeToWB", "SUM(45+45+45)");
+
+ //Copy name from A To B
+ Assert.AreEqual(0, ws1b.Names.Count);
+ AB.Copy(ws1b, "FromA");
+ Assert.AreEqual(1, ws1b.Names.Count);
+
+ //Copy name from wb To A
+ Assert.AreEqual(2, ws1a.Names.Count);
+ WbA.Copy(ws1a, "FromWb");
+ Assert.AreEqual(3, ws1a.Names.Count);
+
+ //Copy name from A to wb
+ Assert.AreEqual(1, wb1.Names.Count);
+ AWb.Copy(wb1, "FromA");
+ Assert.AreEqual(2, wb1.Names.Count);
+
+ //Copy name from A to wb2
+ Assert.AreEqual(0, wb2.Names.Count);
+ AWb.Copy(wb2, "FromA");
+ Assert.AreEqual(1, wb2.Names.Count);
+
+ //SaveWorkbook("DefinedNamesCopyP1.xlsx", p1);
+ //SaveWorkbook("DefinedNamesCopyP2.xlsx", p2);
+ }
+
+ [TestMethod]
+ public void AddWorksheetReferenceToFormulaTests()
+ {
+ var p = new ExcelPackage();
+ var ws = p.Workbook.Worksheets.Add("Sheet 1");
+
+ var f1 = FormulaUtils.AddWorksheetReferenceToFormula("SUM(B2+3)", ws);
+ var f2 = FormulaUtils.AddWorksheetReferenceToFormula("SUM(B2+AS123+3+D20)", ws);
+ var f3 = FormulaUtils.AddWorksheetReferenceToFormula("SUM('Sheet 1'!$B$2+3)", ws);
+ var f4 = FormulaUtils.AddWorksheetReferenceToFormula("SUM(3+2)", ws);
+ var f5 = FormulaUtils.AddWorksheetReferenceToFormula("A2*SUM(3+2)", ws);
+ var f6 = FormulaUtils.AddWorksheetReferenceToFormula("SUM(B2+3)", ws, true);
+
+ Assert.AreEqual("SUM('Sheet 1'!$B$2+3)", f1);
+ Assert.AreEqual("SUM('Sheet 1'!$B$2+'Sheet 1'!$AS$123+3+'Sheet 1'!$D$20)", f2);
+ Assert.AreEqual("SUM('Sheet 1'!$B$2+3)", f3);
+ Assert.AreEqual("SUM(3+2)", f4);
+ Assert.AreEqual("'Sheet 1'!$A$2*SUM(3+2)", f5);
+ Assert.AreEqual("SUM('Sheet 1'!B2+3)", f6);
+ }
+
public void CopyWorksheetDefinedNames()
{
using var p = OpenTemplatePackage("CopyWorksheetNames.xlsx");
@@ -916,9 +1124,8 @@ public void CopyWorksheetDefinedNamesEpplusOnly()
var ws2 = wb2.Worksheets.Add("CopyWs", ws);
var ws3 = wb2.Worksheets.Add("CopyWs2", ws);
- //To be fixed in PR 1999
- Assert.AreEqual(5,wb2.Names.Count());
- Assert.AreEqual(wb2.Names[2].Value, wb.Names[2].Value);
+ Assert.AreEqual(1 ,wb2.Names.Count());
+ Assert.AreEqual(wb2.Names.ContainsKey("AWorkbookRange"), wb.Names.ContainsKey("AWorkbookRange"));
SaveAndCleanup(p2);
}
SaveAndCleanup(p);