| /******************************************************************************* |
| * You may amend and distribute as you like, but don't remove this header! |
| * |
| * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets. |
| * See http://www.codeplex.com/EPPlus for details. |
| * |
| * Copyright (C) 2011 Jan Källman |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| * See the GNU Lesser General Public License for more details. |
| * |
| * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php |
| * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html |
| * |
| * All code and executables are provided "as is" with no warranty either express or implied. |
| * The author accepts no liability for any damage or loss of business that this product may cause. |
| * |
| * Code change notes: |
| * |
| * Author Change Date |
| * ****************************************************************************** |
| * Jan Källman Initial Release 2010-01-28 |
| * Jan Källman License changed GPL-->LGPL 2011-12-27 |
| * Eyal Seagull Conditional Formatting 2012-04-03 |
| *******************************************************************************/ |
| |
| using System; |
| using System.Collections; |
| using System.Collections.Generic; |
| using System.Globalization; |
| using System.Security; |
| using System.Text; |
| using System.Xml; |
| |
| namespace AppsheetEpplus; |
| |
| /// <summary> |
| /// A range of cells |
| /// </summary> |
| public class ExcelRangeBase |
| : ExcelAddress, |
| IExcelCell, |
| IDisposable, |
| IEnumerable<ExcelRangeBase>, |
| IEnumerator<ExcelRangeBase> { |
| /// <summary> |
| /// Reference to the worksheet |
| /// </summary> |
| protected ExcelWorksheet _worksheet; |
| internal ExcelWorkbook _workbook; |
| |
| private delegate void ChangePropHandler(SetValueHandler method, object value); |
| |
| private delegate void SetValueHandler(object value, int row, int col); |
| |
| private ChangePropHandler _changePropMethod; |
| private int _styleID; |
| |
| private class CopiedCell { |
| internal int Row { get; set; } |
| |
| internal int Column { get; set; } |
| |
| internal object Value { get; set; } |
| |
| internal string Type { get; set; } |
| |
| internal object Formula { get; set; } |
| |
| internal int? StyleID { get; set; } |
| |
| internal Uri HyperLink { get; set; } |
| |
| internal ExcelComment Comment { get; set; } |
| |
| internal Byte Flag { get; set; } |
| } |
| |
| //private class CopiedFlag |
| //{ |
| // internal int Row { get; set; } |
| // internal int Column { get; set; } |
| // internal Byte Flag { get; set; } |
| //} |
| |
| |
| internal ExcelRangeBase(ExcelWorksheet worksheet) { |
| _worksheet = worksheet; |
| _ws = _worksheet.Name; |
| _workbook = _worksheet.Workbook; |
| AddressChange += ExcelRangeBase_AddressChange; |
| SetDelegate(); |
| } |
| |
| private void ExcelRangeBase_AddressChange(object sender, EventArgs e) { |
| if (Table != null) { |
| SetRcFromTable(_workbook, null); |
| } |
| SetDelegate(); |
| } |
| |
| internal ExcelRangeBase(ExcelWorksheet worksheet, string address) |
| : base(worksheet == null ? "" : worksheet.Name, address) { |
| _worksheet = worksheet; |
| _workbook = worksheet.Workbook; |
| SetRcFromTable(_workbook, null); |
| if (string.IsNullOrEmpty(_ws)) { |
| _ws = _worksheet == null ? "" : _worksheet.Name; |
| } |
| AddressChange += ExcelRangeBase_AddressChange; |
| SetDelegate(); |
| } |
| |
| internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName) |
| : base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName) { |
| SetRcFromTable(wb, null); |
| _worksheet = xlWorksheet; |
| _workbook = wb; |
| if (string.IsNullOrEmpty(_ws)) { |
| _ws = xlWorksheet?.Name; |
| } |
| AddressChange += ExcelRangeBase_AddressChange; |
| SetDelegate(); |
| } |
| |
| ~ExcelRangeBase() { |
| //this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange); |
| } |
| |
| private void SetDelegate() { |
| if (_fromRow == -1) { |
| _changePropMethod = SetUnknown; |
| } |
| //Single cell |
| else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null) { |
| _changePropMethod = SetSingle; |
| } |
| //Range (ex A1:A2) |
| else if (Addresses == null) { |
| _changePropMethod = SetRange; |
| } |
| //Multi Range (ex A1:A2,C1:C2) |
| else { |
| _changePropMethod = SetMultiRange; |
| } |
| } |
| |
| /// <summary> |
| /// We dont know the address yet. Set the delegate first time a property is set. |
| /// </summary> |
| /// <param name="valueMethod"></param> |
| /// <param name="value"></param> |
| private void SetUnknown(SetValueHandler valueMethod, object value) { |
| //Address is not set use, selected range |
| if (_fromRow == -1) { |
| SetToSelectedRange(); |
| } |
| SetDelegate(); |
| _changePropMethod(valueMethod, value); |
| } |
| |
| /// <summary> |
| /// Set a single cell |
| /// </summary> |
| /// <param name="valueMethod"></param> |
| /// <param name="value"></param> |
| private void SetSingle(SetValueHandler valueMethod, object value) { |
| valueMethod(value, _fromRow, _fromCol); |
| } |
| |
| /// <summary> |
| /// Set a range |
| /// </summary> |
| /// <param name="valueMethod"></param> |
| /// <param name="value"></param> |
| private void SetRange(SetValueHandler valueMethod, object value) { |
| SetValueAddress(this, valueMethod, value); |
| } |
| |
| /// <summary> |
| /// Set a multirange (A1:A2,C1:C2) |
| /// </summary> |
| /// <param name="valueMethod"></param> |
| /// <param name="value"></param> |
| private void SetMultiRange(SetValueHandler valueMethod, object value) { |
| SetValueAddress(this, valueMethod, value); |
| foreach (var address in Addresses) { |
| SetValueAddress(address, valueMethod, value); |
| } |
| } |
| |
| /// <summary> |
| /// Set the property for an address |
| /// </summary> |
| /// <param name="address"></param> |
| /// <param name="valueMethod"></param> |
| /// <param name="value"></param> |
| private void SetValueAddress(ExcelAddress address, SetValueHandler valueMethod, object value) { |
| IsRangeValid(""); |
| if (_fromRow == 1 |
| && _fromCol == 1 |
| && _toRow == ExcelPackage.MaxRows |
| && _toCol |
| == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging |
| { |
| throw (new ArgumentException( |
| "Can't reference all cells. Please use the indexer to set the range")); |
| } |
| for (int col = address.Start.Column; col <= address.End.Column; col++) { |
| for (int row = address.Start.Row; row <= address.End.Row; row++) { |
| valueMethod(value, row, col); |
| } |
| } |
| } |
| |
| private void Set_StyleID(object value, int row, int col) { |
| _worksheet._styles.SetValue(row, col, (int)value); |
| } |
| |
| private void Set_Value(object value, int row, int col) { |
| //ExcelCell c = _worksheet.Cell(row, col); |
| var sfi = _worksheet._formulas.GetValue(row, col); |
| if (sfi is int) { |
| SplitFormulas(_worksheet.Cells[row, col]); |
| } |
| if (sfi != null) { |
| _worksheet._formulas.SetValue(row, col, string.Empty); |
| } |
| _worksheet._values.SetValue(row, col, value); |
| } |
| |
| private void Set_Formula(object value, int row, int col) { |
| //ExcelCell c = _worksheet.Cell(row, col); |
| var f = _worksheet._formulas.GetValue(row, col); |
| if (f is int i && i >= 0) { |
| SplitFormulas(_worksheet.Cells[row, col]); |
| } |
| |
| string formula = (value == null ? string.Empty : value.ToString()); |
| if (formula == string.Empty) { |
| _worksheet._formulas.SetValue(row, col, string.Empty); |
| } else { |
| if (formula[0] == '=') { |
| value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign. |
| } |
| _worksheet._formulas.SetValue(row, col, formula); |
| _worksheet._values.SetValue(row, col, null); |
| } |
| } |
| |
| /// <summary> |
| /// Handles shared formulas |
| /// </summary> |
| /// <param name="value">The formula</param> |
| /// <param name="address">The address of the formula</param> |
| /// <param name="isArray">If the forumla is an array formula.</param> |
| private void Set_SharedFormula(string value, ExcelAddress address, bool isArray) { |
| if (_fromRow == 1 |
| && _fromCol == 1 |
| && _toRow == ExcelPackage.MaxRows |
| && _toCol |
| == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging |
| { |
| throw (new InvalidOperationException("Can't set a formula for the entire worksheet")); |
| } |
| if (address.Start.Row == address.End.Row |
| && address.Start.Column == address.End.Column |
| && !isArray) //is it really a shared formula? Arrayformulas can be one cell only |
| { |
| //Nope, single cell. Set the formula |
| Set_Formula(value, address.Start.Row, address.Start.Column); |
| return; |
| } |
| //RemoveFormuls(address); |
| CheckAndSplitSharedFormula(address); |
| ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default); |
| f.Formula = value; |
| f.Index = _worksheet.GetMaxShareFunctionIndex(isArray); |
| f.Address = address.FirstAddress; |
| f.StartCol = address.Start.Column; |
| f.StartRow = address.Start.Row; |
| f.IsArray = isArray; |
| |
| _worksheet._sharedFormulas.Add(f.Index, f); |
| //_worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index; |
| //_worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value; |
| |
| for (int col = address.Start.Column; col <= address.End.Column; col++) { |
| for (int row = address.Start.Row; row <= address.End.Row; row++) { |
| //_worksheet.Cell(row, col).SharedFormulaID = f.Index; |
| _worksheet._formulas.SetValue(row, col, f.Index); |
| _worksheet._values.SetValue(row, col, null); |
| } |
| } |
| } |
| |
| private void Set_HyperLink(object value, int row, int col) { |
| //_worksheet.Cell(row, col).Hyperlink = value as Uri; |
| if (value is Uri uri) { |
| _worksheet._hyperLinks.SetValue(row, col, uri); |
| |
| if (uri is ExcelHyperLink link) { |
| _worksheet._values.SetValue(row, col, link.Display); |
| } else { |
| _worksheet._values.SetValue(row, col, uri.OriginalString); |
| } |
| } else { |
| _worksheet._hyperLinks.SetValue(row, col, null); |
| _worksheet._values.SetValue(row, col, null); |
| } |
| } |
| |
| private void Set_IsArrayFormula(object value, int row, int col) { |
| _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.ArrayFormula); |
| } |
| |
| private void Set_IsRichText(object value, int row, int col) { |
| //_worksheet.Cell(row, col).IsRichText = (bool)value; |
| _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.RichText); |
| } |
| |
| private void Exists_Comment(object value, int row, int col) { |
| ulong cellId = GetCellId(_worksheet.SheetID, row, col); |
| if (_worksheet.Comments._comments.ContainsKey(cellId)) { |
| throw (new InvalidOperationException( |
| string.Format( |
| "Cell {0} already contain a comment.", |
| new ExcelCellAddress(row, col).Address))); |
| } |
| } |
| |
| private void SetToSelectedRange() { |
| if (_worksheet.View.SelectedRange == "") { |
| Address = "A1"; |
| } else { |
| Address = _worksheet.View.SelectedRange; |
| } |
| } |
| |
| private void IsRangeValid(string type) { |
| if (_fromRow <= 0) { |
| if (_address == "") { |
| SetToSelectedRange(); |
| } else { |
| if (type == "") { |
| throw (new InvalidOperationException( |
| string.Format("Range is not valid for this operation: {0}", _address))); |
| } |
| throw (new InvalidOperationException( |
| string.Format("Range is not valid for {0} : {1}", type, _address))); |
| } |
| } |
| } |
| |
| /// <summary> |
| /// The styleobject for the range. |
| /// </summary> |
| public ExcelStyle Style { |
| get { |
| IsRangeValid("styling"); |
| int s = 0; |
| if (!_worksheet._styles.Exists( |
| _fromRow, |
| _fromCol, |
| ref s)) //Cell exists |
| { |
| if (!_worksheet._styles.Exists( |
| _fromRow, |
| 0, |
| ref s)) //No, check Row style |
| { |
| var c = Worksheet.GetColumn(_fromCol); |
| if (c == null) { |
| s = 0; |
| } else { |
| s = c.StyleID; |
| } |
| } |
| } |
| return _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, Address); |
| } |
| } |
| |
| /// <summary> |
| /// The named style |
| /// </summary> |
| public string StyleName { |
| get { |
| IsRangeValid("styling"); |
| int xfId; |
| if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows) { |
| xfId = GetColumnStyle(_fromCol); |
| } else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) { |
| xfId = 0; |
| if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) { |
| xfId = GetColumnStyle(_fromCol); |
| } |
| } else { |
| xfId = 0; |
| if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref xfId)) { |
| if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId)) { |
| xfId = GetColumnStyle(_fromCol); |
| } |
| } |
| } |
| int nsId; |
| if (xfId <= 0) { |
| nsId = Style.Styles.CellXfs[0].XfId; |
| } else { |
| nsId = Style.Styles.CellXfs[xfId].XfId; |
| } |
| foreach (var ns in Style.Styles.NamedStyles) { |
| if (ns.StyleXfId == nsId) { |
| return ns.Name; |
| } |
| } |
| |
| return ""; |
| } |
| set { |
| _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value); |
| int col = _fromCol; |
| if (_fromRow == 1 |
| && _toRow |
| == ExcelPackage.MaxRows) //Full column |
| { |
| ExcelColumn column; |
| //Get the startcolumn |
| //ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, column); |
| var c = _worksheet.GetValue(0, _fromCol); |
| if (c == null) { |
| column = _worksheet.Column(_fromCol); |
| //if (_worksheet._values.PrevCell(ref row, ref col)) |
| //{ |
| // var prevCol = (ExcelColumn)_worksheet._values.GetValue(row, col); |
| // column = prevCol.Clone(_worksheet, column); |
| // prevCol.ColumnMax = column - 1; |
| //} |
| } else { |
| column = (ExcelColumn)c; |
| } |
| |
| column.StyleName = value; |
| column.StyleID = _styleID; |
| |
| //var index = _worksheet._columns.IndexOf(colID); |
| var cols = new CellsStoreEnumerator<object>(_worksheet._values, 0, _fromCol + 1, 0, _toCol); |
| if (cols.Next()) { |
| col = _fromCol; |
| while (column.ColumnMin <= _toCol) { |
| if (column.ColumnMax > _toCol) { |
| var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax); |
| column.ColumnMax = _toCol; |
| } |
| |
| column._styleName = value; |
| column.StyleID = _styleID; |
| |
| if (cols.Value == null) { |
| break; |
| } |
| var nextCol = (ExcelColumn)cols.Value; |
| if (column.ColumnMax < nextCol.ColumnMax - 1) { |
| column.ColumnMax = nextCol.ColumnMax - 1; |
| } |
| column = nextCol; |
| cols.Next(); |
| } |
| } |
| if (column.ColumnMax < _toCol) { |
| column.ColumnMax = _toCol; |
| } |
| //if (column.ColumnMin == column) |
| //{ |
| // column.ColumnMax = _toCol; |
| //} |
| //else if (column._columnMax < _toCol) |
| //{ |
| // var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn; |
| // newCol._columnMax = _toCol; |
| |
| // newCol._styleID = _styleID; |
| // newCol._styleName = value; |
| //} |
| if (_fromCol == 1 |
| && _toCol |
| == ExcelPackage.MaxColumns) //FullRow |
| { |
| var rows = new CellsStoreEnumerator<object>( |
| _worksheet._values, |
| 1, |
| 0, |
| ExcelPackage.MaxRows, |
| 0); |
| rows.Next(); |
| while (rows.Value != null) { |
| _worksheet._styles.SetValue(rows.Row, 0, _styleID); |
| if (!rows.Next()) { |
| break; |
| } |
| } |
| } |
| } else if (_fromCol == 1 |
| && _toCol |
| == ExcelPackage.MaxColumns) //FullRow |
| { |
| for (int r = _fromRow; r <= _toRow; r++) { |
| _worksheet.Row(r)._styleName = value; |
| _worksheet.Row(r).StyleID = _styleID; |
| } |
| } |
| |
| if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows) |
| || (_fromCol == 1 |
| && _toCol |
| == ExcelPackage.MaxColumns))) //Cell specific |
| { |
| for (int c = _fromCol; c <= _toCol; c++) { |
| for (int r = _fromRow; r <= _toRow; r++) { |
| _worksheet._styles.SetValue(r, c, _styleID); |
| } |
| } |
| } else //Only set name on created cells. (uncreated cells is set on full row or full column). |
| { |
| var cells = new CellsStoreEnumerator<object>( |
| _worksheet._values, |
| _fromRow, |
| _fromCol, |
| _toRow, |
| _toCol); |
| while (cells.Next()) { |
| _worksheet._styles.SetValue(cells.Row, cells.Column, _styleID); |
| } |
| } |
| //_changePropMethod(Set_StyleName, value); |
| } |
| } |
| |
| private int GetColumnStyle(int col) { |
| object c = null; |
| if (_worksheet._values.Exists(0, col, ref c)) { |
| return (c as ExcelColumn).StyleID; |
| } |
| int row = 0; |
| if (_worksheet._values.PrevCell(ref row, ref col)) { |
| var column = _worksheet._values.GetValue(row, col) as ExcelColumn; |
| if (column.ColumnMax >= col) { |
| return _worksheet._styles.GetValue(row, col); |
| } |
| } |
| return 0; |
| } |
| |
| /// <summary> |
| /// The style ID. |
| /// It is not recomended to use this one. Use Named styles as an alternative. |
| /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook. |
| /// </summary> |
| public int StyleID { |
| get { |
| int s = 0; |
| if (!_worksheet._styles.Exists(_fromRow, _fromCol, ref s)) { |
| if (!_worksheet._styles.Exists(_fromRow, 0, ref s)) { |
| s = _worksheet._styles.GetValue(0, _fromCol); |
| } |
| } |
| return s; |
| } |
| set => _changePropMethod(Set_StyleID, value); |
| } |
| |
| /// <summary> |
| /// Set the range to a specific value |
| /// </summary> |
| public object Value { |
| get { |
| if (IsName) { |
| if (_worksheet == null) { |
| return _workbook._names[_address].NameValue; |
| } |
| return _worksheet.Names[_address].NameValue; |
| } |
| if (_fromRow == _toRow && _fromCol == _toCol) { |
| return _worksheet.GetValue(_fromRow, _fromCol); |
| } |
| return GetValueArray(); |
| } |
| set { |
| if (IsName) { |
| if (_worksheet == null) { |
| _workbook._names[_address].NameValue = value; |
| } else { |
| _worksheet.Names[_address].NameValue = value; |
| } |
| } else { |
| _changePropMethod(Set_Value, value); |
| } |
| } |
| } |
| |
| private object GetValueArray() { |
| ExcelAddressBase addr; |
| if (_fromRow == 1 |
| && _fromCol == 1 |
| && _toRow == ExcelPackage.MaxRows |
| && _toCol == ExcelPackage.MaxColumns) { |
| addr = _worksheet.Dimension; |
| if (addr == null) { |
| return null; |
| } |
| } else { |
| addr = this; |
| } |
| object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1]; |
| |
| for (int col = addr._fromCol; col <= addr._toCol; col++) { |
| for (int row = addr._fromRow; row <= addr._toRow; row++) { |
| if (_worksheet._values.Exists(row, col)) { |
| if (_worksheet._flags.GetFlagValue(row, col, CellFlags.RichText)) { |
| v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text; |
| } else { |
| v[row - addr._fromRow, col - addr._fromCol] = _worksheet._values.GetValue(row, col); |
| } |
| } |
| } |
| } |
| return v; |
| } |
| |
| /// <summary> |
| /// Returns the formatted value. |
| /// </summary> |
| public string Text => GetFormattedText(false); |
| |
| private string GetFormattedText(bool forWidthCalc) { |
| object v = Value; |
| if (v == null) { |
| return ""; |
| } |
| var styles = Worksheet.Workbook.Styles; |
| var nfId = styles.CellXfs[StyleID].NumberFormatId; |
| ExcelNumberFormatXml.ExcelFormatTranslator nf = null; |
| for (int i = 0; i < styles.NumberFormats.Count; i++) { |
| if (nfId == styles.NumberFormats[i].NumFmtId) { |
| nf = styles.NumberFormats[i].FormatTranslator; |
| break; |
| } |
| } |
| |
| string format, |
| textFormat; |
| if (forWidthCalc) { |
| format = nf.NetFormatForWidth; |
| textFormat = nf.NetTextFormatForWidth; |
| } else { |
| format = nf.NetFormat; |
| textFormat = nf.NetTextFormat; |
| } |
| |
| return FormatValue(v, nf, format, textFormat); |
| } |
| |
| internal static string FormatValue( |
| object v, |
| ExcelNumberFormatXml.ExcelFormatTranslator nf, |
| string format, |
| string textFormat) { |
| if (v is decimal || v.GetType().IsPrimitive) { |
| double d; |
| try { |
| d = Convert.ToDouble(v); |
| } catch { |
| return ""; |
| } |
| |
| if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number) { |
| if (string.IsNullOrEmpty(nf.FractionFormat)) { |
| return d.ToString(format, nf.Culture); |
| } |
| return nf.FormatFraction(d); |
| } |
| if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { |
| var date = DateTime.FromOADate(d); |
| return date.ToString(format, nf.Culture); |
| } |
| } else if (v is DateTime time) { |
| if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { |
| return time.ToString(format, nf.Culture); |
| } |
| double d = time.ToOADate(); |
| if (string.IsNullOrEmpty(nf.FractionFormat)) { |
| return d.ToString(format, nf.Culture); |
| } |
| return nf.FormatFraction(d); |
| } else if (v is TimeSpan span) { |
| if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime) { |
| return new DateTime(span.Ticks).ToString(format, nf.Culture); |
| } |
| double d = (new DateTime(span.Ticks)).ToOADate(); |
| if (string.IsNullOrEmpty(nf.FractionFormat)) { |
| return d.ToString(format, nf.Culture); |
| } |
| return nf.FormatFraction(d); |
| } else { |
| if (textFormat == "") { |
| return v.ToString(); |
| } |
| return string.Format(textFormat, v); |
| } |
| return v.ToString(); |
| } |
| |
| /// <summary> |
| /// Gets or sets a formula for a range. |
| /// </summary> |
| public string Formula { |
| get { |
| if (IsName) { |
| if (_worksheet == null) { |
| return _workbook._names[_address].NameFormula; |
| } |
| return _worksheet.Names[_address].NameFormula; |
| } |
| return _worksheet.GetFormula(_fromRow, _fromCol); |
| } |
| set { |
| if (IsName) { |
| if (_worksheet == null) { |
| _workbook._names[_address].NameFormula = value; |
| } else { |
| _worksheet.Names[_address].NameFormula = value; |
| } |
| } else { |
| if (value == null || value.Trim() == "") { |
| //Set the cells to null |
| Value = null; |
| } else if (_fromRow == _toRow && _fromCol == _toCol) { |
| Set_Formula(value, _fromRow, _fromCol); |
| } else { |
| Set_SharedFormula(value, this, false); |
| if (Addresses != null) { |
| foreach (var address in Addresses) { |
| Set_SharedFormula(value, address, false); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Gets or Set a formula in R1C1 format. |
| /// </summary> |
| public string FormulaR1C1 { |
| get { |
| IsRangeValid("FormulaR1C1"); |
| return _worksheet.GetFormulaR1C1(_fromRow, _fromCol); |
| } |
| set { |
| IsRangeValid("FormulaR1C1"); |
| if (value.Length > 0 && value[0] == '=') { |
| value = value.Substring(1, value.Length - 1); // remove any starting equalsign. |
| } |
| |
| if (value == null || value.Trim() == "") { |
| //Set the cells to null |
| _worksheet.Cells[TranslateFromR1C1(value, _fromRow, _fromCol)].Value = null; |
| } else if (Addresses == null) { |
| Set_SharedFormula(TranslateFromR1C1(value, _fromRow, _fromCol), this, false); |
| } else { |
| Set_SharedFormula( |
| TranslateFromR1C1(value, _fromRow, _fromCol), |
| new(WorkSheet, FirstAddress), |
| false); |
| foreach (var address in Addresses) { |
| Set_SharedFormula( |
| TranslateFromR1C1(value, address.Start.Row, address.Start.Column), |
| address, |
| false); |
| } |
| } |
| } |
| } |
| |
| /// <summary> |
| /// Gets or Set a formula in R1C1 format. |
| /// |
| public string FormulaR1C1_V1 { |
| get { |
| IsRangeValid("FormulaR1C1"); |
| return _worksheet.GetFormulaR1C1_V1(_fromRow, _fromCol); |
| } |
| } |
| |
| public string ArrayFormulaAddress { |
| get { |
| IsRangeValid("FormulaR1C1"); |
| return _worksheet.GetArrayFormulaAddress(_fromRow, _fromCol); |
| } |
| } |
| |
| /// <summary> |
| /// Set the hyperlink property for a range of cells |
| /// </summary> |
| public Uri Hyperlink { |
| get { |
| IsRangeValid("formulaR1C1"); |
| return _worksheet._hyperLinks.GetValue(_fromRow, _fromCol); |
| } |
| set => _changePropMethod(Set_HyperLink, value); |
| } |
| |
| /// <summary> |
| /// If the cells in the range are merged. |
| /// </summary> |
| public bool Merge { |
| get { |
| IsRangeValid("merging"); |
| for (int col = _fromCol; col <= _toCol; col++) { |
| for (int row = _fromRow; row <= _toRow; row++) { |
| if (_worksheet.MergedCells[row, col] == null) { |
| return false; |
| } |
| //if (!_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged)) |
| //{ |
| // return false; |
| //} |
| } |
| } |
| return true; |
| } |
| set { |
| IsRangeValid("merging"); |
| //SetMerge(value, FirstAddress); |
| if (value) { |
| _worksheet.MergedCells.Add(new(FirstAddress), true); |
| if (Addresses != null) { |
| foreach (var address in Addresses) { |
| _worksheet.MergedCells.Add(address, true); |
| //SetMerge(value, address._address); |
| } |
| } |
| } else { |
| _worksheet.MergedCells.Clear(this); |
| if (Addresses != null) { |
| foreach (var address in Addresses) { |
| _worksheet.MergedCells.Clear(address); |
| ; |
| } |
| } |
| } |
| } |
| } |
| |
| //private void SetMerge(bool value, string address) |
| //{ |
| // if (!value) |
| // { |
| // if (_worksheet.MergedCells.List.Contains(address)) |
| // { |
| // SetCellMerge(false, address); |
| // _worksheet.MergedCells.List.Remove(address); |
| // } |
| // else if (!CheckMergeDiff(false, address)) |
| // { |
| // throw (new Exception("Range is not fully merged.Specify the exact range")); |
| // } |
| // } |
| // else |
| // { |
| // if (CheckMergeDiff(false, address)) |
| // { |
| // SetCellMerge(true, address); |
| // _worksheet.MergedCells.List.Add(address); |
| // } |
| // else |
| // { |
| // if (!_worksheet.MergedCells.List.Contains(address)) |
| // { |
| // throw (new Exception("Cells are already merged")); |
| // } |
| // } |
| // } |
| //} |
| /// <summary> |
| /// Set an autofilter for the range |
| /// </summary> |
| public bool AutoFilter { |
| get { |
| IsRangeValid("autofilter"); |
| ExcelAddressBase address = _worksheet.AutoFilterAddress; |
| if (address == null) { |
| return false; |
| } |
| if (_fromRow >= address.Start.Row |
| && _toRow <= address.End.Row |
| && _fromCol >= address.Start.Column |
| && _toCol <= address.End.Column) { |
| return true; |
| } |
| return false; |
| } |
| set { |
| IsRangeValid("autofilter"); |
| _worksheet.AutoFilterAddress = this; |
| if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase")) { |
| _worksheet.Names.Remove("_xlnm._FilterDatabase"); |
| } |
| var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this); |
| result.IsNameHidden = true; |
| } |
| } |
| |
| /// <summary> |
| /// If the value is in richtext format. |
| /// </summary> |
| public bool IsRichText { |
| get { |
| IsRangeValid("richtext"); |
| return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.RichText); |
| } |
| set => _changePropMethod(Set_IsRichText, value); |
| } |
| |
| /// <summary> |
| /// Is the range a part of an Arrayformula |
| /// </summary> |
| public bool IsArrayFormula { |
| get { |
| IsRangeValid("arrayformulas"); |
| return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.ArrayFormula); |
| } |
| set => _changePropMethod(Set_IsArrayFormula, value); |
| } |
| |
| private ExcelRichTextCollection _rtc; |
| |
| /// <summary> |
| /// Cell value is richtext formatted. |
| /// Richtext-property only apply to the left-top cell of the range. |
| /// </summary> |
| public ExcelRichTextCollection RichText { |
| get { |
| IsRangeValid("richtext"); |
| if (_rtc == null) { |
| _rtc = GetRichText(_fromRow, _fromCol); |
| } |
| return _rtc; |
| } |
| } |
| |
| private ExcelRichTextCollection GetRichText(int row, int col) { |
| XmlDocument xml = new XmlDocument(); |
| var v = _worksheet._values.GetValue(row, col); |
| var isRt = _worksheet._flags.GetFlagValue(row, col, CellFlags.RichText); |
| if (v != null) { |
| if (isRt) { |
| XmlHelper.LoadXmlSafe( |
| xml, |
| "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >" |
| + v |
| + "</d:si>", |
| Encoding.UTF8); |
| } else { |
| xml.LoadXml( |
| "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ><d:r><d:t>" |
| + SecurityElement.Escape(v.ToString()) |
| + "</d:t></d:r></d:si>"); |
| } |
| } else { |
| xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />"); |
| } |
| var rtc = new ExcelRichTextCollection( |
| _worksheet.NameSpaceManager, |
| xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager), |
| this); |
| return rtc; |
| } |
| |
| /// <summary> |
| /// returns the comment object of the first cell in the range |
| /// </summary> |
| public ExcelComment Comment { |
| get { |
| IsRangeValid("comments"); |
| ulong cellId = GetCellId(_worksheet.SheetID, _fromRow, _fromCol); |
| if (_worksheet.Comments._comments.ContainsKey(cellId)) { |
| return _worksheet._comments._comments[cellId] as ExcelComment; |
| } |
| return null; |
| } |
| } |
| |
| /// <summary> |
| /// WorkSheet object |
| /// </summary> |
| public ExcelWorksheet Worksheet => _worksheet; |
| |
| /// <summary> |
| /// Address including sheetname |
| /// </summary> |
| public string FullAddress { |
| get { |
| string fullAddress = GetFullAddress(_worksheet.Name, _address); |
| if (Addresses != null) { |
| foreach (var a in Addresses) { |
| fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address); |
| ; |
| } |
| } |
| return fullAddress; |
| } |
| } |
| |
| /// <summary> |
| /// Address including sheetname |
| /// </summary> |
| public string FullAddressAbsolute { |
| get { |
| string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws; |
| string fullAddress = GetFullAddress( |
| wbwsRef, |
| GetAddress(_fromRow, _fromCol, _toRow, _toCol, true)); |
| if (Addresses != null) { |
| foreach (var a in Addresses) { |
| fullAddress += |
| "," |
| + GetFullAddress( |
| wbwsRef, |
| GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true)); |
| ; |
| } |
| } |
| return fullAddress; |
| } |
| } |
| |
| /// <summary> |
| /// Address including sheetname |
| /// </summary> |
| internal string FullAddressAbsoluteNoFullRowCol { |
| get { |
| string wbwsRef = string.IsNullOrEmpty(_wb) ? _ws : "[" + _wb.Replace("'", "''") + "]" + _ws; |
| string fullAddress = GetFullAddress( |
| wbwsRef, |
| GetAddress(_fromRow, _fromCol, _toRow, _toCol, true), |
| false); |
| if (Addresses != null) { |
| foreach (var a in Addresses) { |
| fullAddress += |
| "," |
| + GetFullAddress( |
| wbwsRef, |
| GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true), |
| false); |
| ; |
| } |
| } |
| return fullAddress; |
| } |
| } |
| |
| /// <summary> |
| /// Set the value without altering the richtext property |
| /// </summary> |
| /// <param name="value">the value</param> |
| internal void SetValueRichText(object value) { |
| if (_fromRow == 1 |
| && _fromCol == 1 |
| && _toRow == ExcelPackage.MaxRows |
| && _toCol |
| == ExcelPackage.MaxColumns) //Full sheet (ex ws.Cells.Value=0). Set value for A1 only to avoid hanging |
| { |
| //_worksheet.Cell(1, 1).SetValueRichText(value); |
| SetValue(value, 1, 1); |
| } else { |
| //for (int col = _fromCol; col <= _toCol; col++) |
| //{ |
| // for (int row = _fromRow; row <= _toRow; row++) |
| // { |
| //_worksheet.Cell(row, col).SetValueRichText(value); |
| SetValue(value, _fromRow, _fromCol); |
| //} |
| //} |
| } |
| } |
| |
| private void SetValue(object value, int row, int col) { |
| _worksheet.SetValue(row, col, value); |
| // if (value is string) _worksheet._types.SetValue(row, col, "S"); else _worksheet._types.SetValue(row, col, ""); |
| _worksheet._formulas.SetValue(row, col, ""); |
| } |
| |
| internal void SetSharedFormulaId(int id) { |
| for (int col = _fromCol; col <= _toCol; col++) { |
| for (int row = _fromRow; row <= _toRow; row++) { |
| _worksheet._formulas.SetValue(row, col, id); |
| } |
| } |
| } |
| |
| private void CheckAndSplitSharedFormula(ExcelAddressBase address) { |
| for (int col = address._fromCol; col <= address._toCol; col++) { |
| for (int row = address._fromRow; row <= address._toRow; row++) { |
| var f = _worksheet._formulas.GetValue(row, col); |
| if (f is int i && i >= 0) { |
| SplitFormulas(address); |
| return; |
| } |
| } |
| } |
| } |
| |
| private void SplitFormulas(ExcelAddressBase address) { |
| List<int> formulas = []; |
| for (int col = address._fromCol; col <= address._toCol; col++) { |
| for (int row = address._fromRow; row <= address._toRow; row++) { |
| var f = _worksheet._formulas.GetValue(row, col); |
| if (f is int id) { |
| if (id >= 0 && !formulas.Contains(id)) { |
| if (_worksheet._sharedFormulas[id].IsArray |
| && Collide(_worksheet.Cells[_worksheet._sharedFormulas[id].Address]) |
| == eAddressCollition.Partly) // If the formula is an array formula and its on the inside the overwriting range throw an exception |
| { |
| throw (new InvalidOperationException("Can not overwrite a part of an array-formula")); |
| } |
| formulas.Add(id); |
| } |
| } |
| } |
| } |
| |
| foreach (int ix in formulas) { |
| SplitFormula(address, ix); |
| } |
| |
| ////Clear any formula references inside the refered range |
| //_worksheet._formulas.Clear(address._fromRow, address._toRow, address._toRow - address._fromRow + 1, address._toCol - address.column + 1); |
| } |
| |
| private void SplitFormula(ExcelAddressBase address, int ix) { |
| var f = _worksheet._sharedFormulas[ix]; |
| var fRange = _worksheet.Cells[f.Address]; |
| var collide = address.Collide(fRange); |
| |
| //The formula is inside the currenct range, remove it |
| if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside) { |
| _worksheet._sharedFormulas.Remove(ix); |
| return; |
| //fRange.SetSharedFormulaID(int.MinValue); |
| } |
| var firstCellCollide = address.Collide( |
| new(fRange._fromRow, fRange._fromCol, fRange._fromRow, fRange._fromCol)); |
| if (collide == eAddressCollition.Partly |
| && (firstCellCollide == eAddressCollition.Inside |
| || firstCellCollide |
| == eAddressCollition.Equal)) //Do we need to split? Only if the functions first row is inside the new range. |
| { |
| //The formula partly collides with the current range |
| bool fIsSet = false; |
| string formulaR1C1 = fRange.FormulaR1C1; |
| //Top Range |
| if (fRange._fromRow < _fromRow) { |
| f.Address = GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol); |
| fIsSet = true; |
| } |
| //Left Range |
| if (fRange._fromCol < address._fromCol) { |
| if (fIsSet) { |
| f = new(SourceCodeTokenizer.Default); |
| f.Index = _worksheet.GetMaxShareFunctionIndex(false); |
| f.StartCol = fRange._fromCol; |
| f.IsArray = false; |
| _worksheet._sharedFormulas.Add(f.Index, f); |
| } else { |
| fIsSet = true; |
| } |
| if (fRange._fromRow < address._fromRow) { |
| f.StartRow = address._fromRow; |
| } else { |
| f.StartRow = fRange._fromRow; |
| } |
| if (fRange._toRow < address._toRow) { |
| f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, address._fromCol - 1); |
| } else { |
| f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, address._fromCol - 1); |
| } |
| f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); |
| _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); |
| } |
| //Right Range |
| if (fRange._toCol > address._toCol) { |
| if (fIsSet) { |
| f = new(SourceCodeTokenizer.Default); |
| f.Index = _worksheet.GetMaxShareFunctionIndex(false); |
| f.IsArray = false; |
| _worksheet._sharedFormulas.Add(f.Index, f); |
| } else { |
| fIsSet = true; |
| } |
| f.StartCol = address._toCol + 1; |
| if (address._fromRow < fRange._fromRow) { |
| f.StartRow = fRange._fromRow; |
| } else { |
| f.StartRow = address._fromRow; |
| } |
| |
| if (fRange._toRow < address._toRow) { |
| f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol); |
| } else { |
| f.Address = GetAddress(f.StartRow, f.StartCol, address._toRow, fRange._toCol); |
| } |
| f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); |
| _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); |
| } |
| //Bottom Range |
| if (fRange._toRow > address._toRow) { |
| if (fIsSet) { |
| f = new(SourceCodeTokenizer.Default); |
| f.Index = _worksheet.GetMaxShareFunctionIndex(false); |
| f.IsArray = false; |
| _worksheet._sharedFormulas.Add(f.Index, f); |
| } |
| |
| f.StartCol = fRange._fromCol; |
| f.StartRow = _toRow + 1; |
| |
| f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol); |
| |
| f.Address = GetAddress(f.StartRow, f.StartCol, fRange._toRow, fRange._toCol); |
| _worksheet.Cells[f.Address].SetSharedFormulaId(f.Index); |
| } |
| } |
| } |
| |
| private object ConvertData(ExcelTextFormat format, string v, int col, bool isText) { |
| if (isText && (format.DataTypes == null || format.DataTypes.Length < col)) { |
| return v; |
| } |
| |
| double d; |
| DateTime dt; |
| if (format.DataTypes == null |
| || format.DataTypes.Length <= col |
| || format.DataTypes[col] == eDataTypes.Unknown) { |
| string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; |
| if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) { |
| if (v2 == v) { |
| return d; |
| } |
| return d / 100; |
| } |
| if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) { |
| return dt; |
| } |
| return v; |
| } |
| switch (format.DataTypes[col]) { |
| case eDataTypes.Number: |
| if (double.TryParse(v, NumberStyles.Any, format.Culture, out d)) { |
| return d; |
| } |
| return v; |
| case eDataTypes.DateTime: |
| if (DateTime.TryParse(v, format.Culture, DateTimeStyles.None, out dt)) { |
| return dt; |
| } |
| return v; |
| case eDataTypes.Percent: |
| string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v; |
| if (double.TryParse(v2, NumberStyles.Any, format.Culture, out d)) { |
| return d / 100; |
| } |
| return v; |
| |
| default: |
| return v; |
| } |
| } |
| |
| /// <summary> |
| /// Conditional Formatting for this range. |
| /// </summary> |
| public IRangeConditionalFormatting ConditionalFormatting => |
| new RangeConditionalFormatting(_worksheet, new(Address)); |
| |
| /// <summary> |
| /// Data validation for this range. |
| /// </summary> |
| public IRangeDataValidation DataValidation => new RangeDataValidation(_worksheet, Address); |
| |
| /// <summary> |
| /// Get the strongly typed value of the cell. |
| /// </summary> |
| /// <typeparam name="T">The type</typeparam> |
| /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns> |
| public T GetValue<T>() { |
| return _worksheet.GetTypedValue<T>(Value); |
| } |
| |
| /// <summary> |
| /// Get a range with an offset from the top left cell. |
| /// The new range has the same dimensions as the current range |
| /// </summary> |
| /// <param name="rowOffset">Row Offset</param> |
| /// <param name="columnOffset">Column Offset</param> |
| /// <returns></returns> |
| public ExcelRangeBase Offset(int rowOffset, int columnOffset) { |
| if (_fromRow + rowOffset < 1 |
| || _fromCol + columnOffset < 1 |
| || _fromRow + rowOffset > ExcelPackage.MaxRows |
| || _fromCol + columnOffset > ExcelPackage.MaxColumns) { |
| throw (new ArgumentOutOfRangeException("Offset value out of range")); |
| } |
| string address = GetAddress( |
| _fromRow + rowOffset, |
| _fromCol + columnOffset, |
| _toRow + rowOffset, |
| _toCol + columnOffset); |
| return new(_worksheet, address); |
| } |
| |
| /// <summary> |
| /// Get a range with an offset from the top left cell. |
| /// </summary> |
| /// <param name="rowOffset">Row Offset</param> |
| /// <param name="columnOffset">Column Offset</param> |
| /// <param name="numberOfRows">Number of rows. Minimum 1</param> |
| /// <param name="numberOfColumns">Number of colums. Minimum 1</param> |
| /// <returns></returns> |
| public ExcelRangeBase Offset( |
| int rowOffset, |
| int columnOffset, |
| int numberOfRows, |
| int numberOfColumns) { |
| if (numberOfRows < 1 || numberOfColumns < 1) { |
| throw (new("Number of rows/columns must be greater than 0")); |
| } |
| numberOfRows--; |
| numberOfColumns--; |
| if (_fromRow + rowOffset < 1 |
| || _fromCol + columnOffset < 1 |
| || _fromRow + rowOffset > ExcelPackage.MaxRows |
| || _fromCol + columnOffset > ExcelPackage.MaxColumns |
| || _fromRow + rowOffset + numberOfRows < 1 |
| || _fromCol + columnOffset + numberOfColumns < 1 |
| || _fromRow + rowOffset + numberOfRows > ExcelPackage.MaxRows |
| || _fromCol + columnOffset + numberOfColumns > ExcelPackage.MaxColumns) { |
| throw (new ArgumentOutOfRangeException("Offset value out of range")); |
| } |
| string address = GetAddress( |
| _fromRow + rowOffset, |
| _fromCol + columnOffset, |
| _fromRow + rowOffset + numberOfRows, |
| _fromCol + columnOffset + numberOfColumns); |
| return new(_worksheet, address); |
| } |
| |
| /// <summary> |
| /// Clear all cells |
| /// </summary> |
| public void Clear() { |
| Delete(this, false); |
| } |
| |
| /// <summary> |
| /// Creates an array-formula. |
| /// </summary> |
| /// <param name="arrayFormula">The formula</param> |
| public void CreateArrayFormula(string arrayFormula) { |
| if (Addresses != null) { |
| throw (new("An Arrayformula can not have more than one address")); |
| } |
| Set_SharedFormula(arrayFormula, this, true); |
| } |
| |
| //private void Clear(ExcelAddressBase Range) |
| //{ |
| // Clear(Range, true); |
| //} |
| internal void Delete(ExcelAddressBase range, bool shift) { |
| //DeleteCheckMergedCells(Range); |
| _worksheet.MergedCells.Clear(range); |
| //First find the start cell |
| int fromRow, |
| fromCol; |
| var d = Worksheet.Dimension; |
| if (d != null |
| && range._fromRow <= d._fromRow |
| && range._toRow |
| >= d._toRow) //EntireRow? |
| { |
| fromRow = 0; |
| } else { |
| fromRow = range._fromRow; |
| } |
| if (d != null |
| && range._fromCol <= d._fromCol |
| && range._toCol |
| >= d._toCol) //EntireRow? |
| { |
| fromCol = 0; |
| } else { |
| fromCol = range._fromCol; |
| } |
| |
| var rows = range._toRow - fromRow + 1; |
| var cols = range._toCol - fromCol + 1; |
| |
| _worksheet._values.Delete(fromRow, fromCol, rows, cols, shift); |
| _worksheet._types.Delete(fromRow, fromCol, rows, cols, shift); |
| _worksheet._styles.Delete(fromRow, fromCol, rows, cols, shift); |
| _worksheet._formulas.Delete(fromRow, fromCol, rows, cols, shift); |
| _worksheet._hyperLinks.Delete(fromRow, fromCol, rows, cols, shift); |
| _worksheet._flags.Delete(fromRow, fromCol, rows, cols, shift); |
| _worksheet._commentsStore.Delete(fromRow, fromCol, rows, cols, shift); |
| |
| //if(shift) |
| //{ |
| // _worksheet.AdjustFormulasRow(fromRow, rows); |
| //} |
| |
| //Clear multi addresses as well |
| if (Addresses != null) { |
| foreach (var sub in Addresses) { |
| Delete(sub, shift); |
| } |
| } |
| } |
| |
| public void Dispose() {} |
| |
| //int _index; |
| //ulong _toCellId; |
| //int _enumAddressIx; |
| private CellsStoreEnumerator<object> cellEnum; |
| |
| public IEnumerator<ExcelRangeBase> GetEnumerator() { |
| Reset(); |
| return this; |
| } |
| |
| IEnumerator IEnumerable.GetEnumerator() { |
| Reset(); |
| return this; |
| } |
| |
| /// <summary> |
| /// The current range when enumerating |
| /// </summary> |
| public ExcelRangeBase Current => new(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column)); |
| |
| /// <summary> |
| /// The current range when enumerating |
| /// </summary> |
| object IEnumerator.Current => |
| new ExcelRangeBase(_worksheet, GetAddress(cellEnum.Row, cellEnum.Column)); |
| |
| private int _enumAddressIx = -1; |
| |
| public bool MoveNext() { |
| if (cellEnum.Next()) { |
| return true; |
| } |
| if (_addresses != null) { |
| _enumAddressIx++; |
| if (_enumAddressIx < _addresses.Count) { |
| cellEnum = new( |
| _worksheet._values, |
| _addresses[_enumAddressIx]._fromRow, |
| _addresses[_enumAddressIx]._fromCol, |
| _addresses[_enumAddressIx]._toRow, |
| _addresses[_enumAddressIx]._toCol); |
| return MoveNext(); |
| } |
| return false; |
| } |
| return false; |
| } |
| |
| public void Reset() { |
| _enumAddressIx = -1; |
| cellEnum = new(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol); |
| } |
| |
| //private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol) |
| //{ |
| // if (_index >= _worksheet._cells.Count) return; |
| // ExcelCell cell = _worksheet._cells[_index] as ExcelCell; |
| // while (cell.Column > toCol || cell.Column < fromCol) |
| // { |
| // if (cell.Column < fromCol) |
| // { |
| // _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol)); |
| // } |
| // else |
| // { |
| // _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol)); |
| // } |
| |
| // if (_index < 0) |
| // { |
| // _index = ~_index; |
| // } |
| // if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId) |
| // { |
| // break; |
| // } |
| // cell = _worksheet._cells[_index] as ExcelCell; |
| // } |
| //} |
| |
| //private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol) |
| //{ |
| // _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol)); |
| // _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol); |
| // if (_index < 0) |
| // { |
| // _index = ~_index; |
| // } |
| // _index--; |
| //} |
| } |