Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.DatasetRefactor/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/ExcelRangeBase.cs @ 12505

Last change on this file since 12505 was 12100, checked in by sraggl, 9 years ago

#2341: Reduced memory consumption by improving much used method ExcelCellBase.GetRowCol. Removing IDisposable and IEnumerator from ExcelRangeBase and move it to ExcelRangeBaseEnumerator.

File size: 100.6 KB
Line 
1/*******************************************************************************
2 * You may amend and distribute as you like, but don't remove this header!
3 *
4 * EPPlus provides server-side generation of Excel 2007/2010 spreadsheets.
5 * See http://www.codeplex.com/EPPlus for details.
6 *
7 * Copyright (C) 2011  Jan Källman
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
17 * See the GNU Lesser General Public License for more details.
18 *
19 * The GNU Lesser General Public License can be viewed at http://www.opensource.org/licenses/lgpl-license.php
20 * If you unfamiliar with this license or have questions about it, here is an http://www.gnu.org/licenses/gpl-faq.html
21 *
22 * All code and executables are provided "as is" with no warranty either express or implied.
23 * The author accepts no liability for any damage or loss of business that this product may cause.
24 *
25 * Code change notes:
26 *
27 * Author             Change            Date
28 * ******************************************************************************
29 * Jan Källman        Initial Release           2010-01-28
30 * Jan Källman        License changed GPL-->LGPL  2011-12-27
31 * Eyal Seagull       Conditional Formatting      2012-04-03
32 *******************************************************************************/
33using System;
34using System.Collections.Generic;
35using System.ComponentModel;
36using System.Text;
37using System.Data;
38using OfficeOpenXml.FormulaParsing;
39using OfficeOpenXml.Style;
40using System.Xml;
41using System.Drawing;
42using System.Globalization;
43using System.Collections;
44using OfficeOpenXml.Table;
45using System.Text.RegularExpressions;
46using System.IO;
47using System.Linq;
48using OfficeOpenXml.DataValidation;
49using OfficeOpenXml.DataValidation.Contracts;
50using System.Reflection;
51using OfficeOpenXml.Style.XmlAccess;
52using System.Security;
53using OfficeOpenXml.ConditionalFormatting;
54using OfficeOpenXml.ConditionalFormatting.Contracts;
55using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
56namespace OfficeOpenXml
57{
58    /// <summary>
59  /// A range of cells
60  /// </summary>
61  public class ExcelRangeBase : ExcelAddress, IExcelCell, IEnumerable<ExcelRangeBase>
62  {
63    /// <summary>
64    /// Reference to the worksheet
65    /// </summary>
66    protected ExcelWorksheet _worksheet;
67    internal ExcelWorkbook _workbook = null;
68    private delegate void _changeProp(_setValue method, object value);
69    private delegate void _setValue(object value, int row, int col);
70    private _changeProp _changePropMethod;
71    private int _styleID;
72        private class CopiedCell
73        {
74            internal int Row { get; set; }
75            internal int Column { get; set; }
76            internal object Value { get; set; }
77            internal string Type { get; set; }
78            internal object Formula { get; set; }
79            internal int? StyleID { get; set; }
80            internal Uri HyperLink { get; set; }
81            internal ExcelComment Comment { get; set; }
82            internal Byte Flag { get; set; }
83        }
84        //private class CopiedFlag
85        //{
86        //    internal int Row { get; set; }
87        //    internal int Column { get; set; }
88        //    internal Byte Flag { get; set; }
89        //}
90        #region Constructors
91    internal ExcelRangeBase(ExcelWorksheet xlWorksheet)
92    {
93      _worksheet = xlWorksheet;
94      _ws = _worksheet.Name;
95            _workbook = _worksheet.Workbook;
96            this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange);
97      SetDelegate();
98    }
99
100        void ExcelRangeBase_AddressChange(object sender, EventArgs e)
101        {
102            if (Table != null)
103            {
104                SetRCFromTable(_workbook._package, null);
105            }
106            SetDelegate();
107        }
108    internal ExcelRangeBase(ExcelWorksheet xlWorksheet, string address) :
109      base(xlWorksheet == null ? "" : xlWorksheet.Name, address)
110    {
111      _worksheet = xlWorksheet;
112            _workbook = _worksheet.Workbook;
113            base.SetRCFromTable(_worksheet._package, null);
114      if (string.IsNullOrEmpty(_ws)) _ws = _worksheet == null ? "" : _worksheet.Name;
115            this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange);
116            SetDelegate();
117    }
118    internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName) :
119      base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName)
120    {
121            SetRCFromTable(wb._package, null);
122            _worksheet = xlWorksheet;
123      _workbook = wb;
124      if (string.IsNullOrEmpty(_ws)) _ws = (xlWorksheet == null ? null : xlWorksheet.Name);
125            this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange);
126            SetDelegate();
127    }
128        ~ExcelRangeBase()
129        {
130            this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange);
131        }
132    #endregion
133    #region Set Value Delegates
134        private void SetDelegate()
135    {
136      if (_fromRow == -1)
137      {
138        _changePropMethod = SetUnknown;
139      }
140      //Single cell
141      else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null)
142      {
143        _changePropMethod = SetSingle;
144      }
145      //Range (ex A1:A2)
146      else if (Addresses == null)
147      {
148        _changePropMethod = SetRange;
149      }
150      //Multi Range (ex A1:A2,C1:C2)
151      else
152      {
153        _changePropMethod = SetMultiRange;
154      }
155    }
156        /// <summary>
157    /// We dont know the address yet. Set the delegate first time a property is set.
158    /// </summary>
159    /// <param name="valueMethod"></param>
160    /// <param name="value"></param>
161    private void SetUnknown(_setValue valueMethod, object value)
162    {
163      //Address is not set use, selected range
164      if (_fromRow == -1)
165      {
166        SetToSelectedRange();
167      }
168      SetDelegate();
169      _changePropMethod(valueMethod, value);
170    }
171    /// <summary>
172    /// Set a single cell
173    /// </summary>
174    /// <param name="valueMethod"></param>
175    /// <param name="value"></param>
176    private void SetSingle(_setValue valueMethod, object value)
177    {
178      valueMethod(value, _fromRow, _fromCol);
179    }
180    /// <summary>
181    /// Set a range
182    /// </summary>
183    /// <param name="valueMethod"></param>
184    /// <param name="value"></param>
185    private void SetRange(_setValue valueMethod, object value)
186    {
187      SetValueAddress(this, valueMethod, value);
188    }
189    /// <summary>
190    /// Set a multirange (A1:A2,C1:C2)
191    /// </summary>
192    /// <param name="valueMethod"></param>
193    /// <param name="value"></param>
194    private void SetMultiRange(_setValue valueMethod, object value)
195    {
196      SetValueAddress(this, valueMethod, value);
197      foreach (var address in Addresses)
198      {
199        SetValueAddress(address, valueMethod, value);
200      }
201    }
202    /// <summary>
203    /// Set the property for an address
204    /// </summary>
205    /// <param name="address"></param>
206    /// <param name="valueMethod"></param>
207    /// <param name="value"></param>
208    private void SetValueAddress(ExcelAddress address, _setValue valueMethod, object value)
209    {
210      IsRangeValid("");
211      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
212      {
213        throw (new ArgumentException("Can't reference all cells. Please use the indexer to set the range"));
214      }
215      else
216      {
217        for (int col = address.Start.Column; col <= address.End.Column; col++)
218        {
219          for (int row = address.Start.Row; row <= address.End.Row; row++)
220          {
221            valueMethod(value, row, col);
222          }
223        }
224      }
225    }
226    #endregion
227    #region Set property methods
228    private void Set_StyleID(object value, int row, int col)
229    {
230            _worksheet._styles.SetValue(row, col, (int)value);
231    }
232    private void Set_StyleName(object value, int row, int col)
233    {
234      //_worksheet.Cell(row, col).SetNewStyleName(value.ToString(), _styleID);
235            _worksheet._styles.SetValue(row, col, _styleID);
236    }
237    private void Set_Value(object value, int row, int col)
238    {
239      //ExcelCell c = _worksheet.Cell(row, col);
240            var sfi = _worksheet._formulas.GetValue(row, col);
241            if (sfi is int)
242            {
243                SplitFormulas(_worksheet.Cells[row, col]);               
244            }
245            if (sfi != null) _worksheet._formulas.SetValue(row, col, string.Empty);
246      _worksheet._values.SetValue(row, col, value);
247    }
248    private void Set_Formula(object value, int row, int col)
249    {
250      //ExcelCell c = _worksheet.Cell(row, col);
251            var f = _worksheet._formulas.GetValue(row, col);
252            if (f is int && (int)f >= 0) SplitFormulas(_worksheet.Cells[row, col]);
253
254      string formula = (value == null ? string.Empty : value.ToString());
255      if (formula == string.Empty)
256      {
257                _worksheet._formulas.SetValue(row, col, string.Empty);
258      }
259      else
260      {
261        if (formula[0] == '=') value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign.
262                _worksheet._formulas.SetValue(row, col, formula);
263                _worksheet._values.SetValue(row, col, null);
264            }
265    }
266    /// <summary>
267    /// Handles shared formulas
268    /// </summary>
269    /// <param name="value">The  formula</param>
270    /// <param name="address">The address of the formula</param>
271    /// <param name="IsArray">If the forumla is an array formula.</param>
272    private void Set_SharedFormula(string value, ExcelAddress address, bool IsArray)
273    {
274      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
275      {
276        throw (new InvalidOperationException("Can't set a formula for the entire worksheet"));
277      }
278      else if (address.Start.Row == address.End.Row && address.Start.Column == address.End.Column && !IsArray)             //is it really a shared formula? Arrayformulas can be one cell only
279      {
280        //Nope, single cell. Set the formula
281        Set_Formula(value, address.Start.Row, address.Start.Column);
282        return;
283      }
284      //RemoveFormuls(address);
285      CheckAndSplitSharedFormula(address);
286      ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default);
287      f.Formula = value;
288      f.Index = _worksheet.GetMaxShareFunctionIndex(IsArray);
289      f.Address = address.FirstAddress;
290      f.StartCol = address.Start.Column;
291      f.StartRow = address.Start.Row;
292      f.IsArray = IsArray;
293
294      _worksheet._sharedFormulas.Add(f.Index, f);
295            //_worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index;
296            //_worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value;
297
298      for (int col = address.Start.Column; col <= address.End.Column; col++)
299      {
300        for (int row = address.Start.Row; row <= address.End.Row; row++)
301        {
302          //_worksheet.Cell(row, col).SharedFormulaID = f.Index;
303                    _worksheet._formulas.SetValue(row, col, f.Index);
304                    _worksheet._values.SetValue(row, col, null);
305        }
306      }
307    }
308    private void Set_HyperLink(object value, int row, int col)
309    {
310      //_worksheet.Cell(row, col).Hyperlink = value as Uri;
311            if (value is Uri)
312            {
313                _worksheet._hyperLinks.SetValue(row, col, (Uri)value);
314
315                if (value is ExcelHyperLink)
316                {
317                    _worksheet._values.SetValue(row, col, ((ExcelHyperLink)value).Display);
318                }
319                else
320                {
321                   _worksheet._values.SetValue(row, col, ((Uri)value).OriginalString);
322                }                   
323            }
324            else
325            {
326                _worksheet._hyperLinks.SetValue(row, col, (Uri)null);
327                _worksheet._values.SetValue(row, col, (Uri)null);
328            }
329        }
330    private void Set_IsRichText(object value, int row, int col)
331    {
332      //_worksheet.Cell(row, col).IsRichText = (bool)value;
333            _worksheet._flags.SetFlagValue(row, col, (bool)value, CellFlags.RichText);
334    }
335    private void Exists_Comment(object value, int row, int col)
336    {
337      ulong cellID = GetCellID(_worksheet.SheetID, row, col);
338      if (_worksheet.Comments._comments.ContainsKey(cellID))
339      {
340        throw (new InvalidOperationException(string.Format("Cell {0} already contain a comment.", new ExcelCellAddress(row, col).Address)));
341      }
342
343    }
344    private void Set_Comment(object value, int row, int col)
345    {
346      string[] v = (string[])value;
347      Worksheet.Comments.Add(new ExcelRangeBase(_worksheet, GetAddress(_fromRow, _fromCol)), v[0], v[1]);
348      //   _worksheet.Cell(row, col).Comment = comment;
349    }
350    #endregion
351    private void SetToSelectedRange()
352    {
353      if (_worksheet.View.SelectedRange == "")
354      {
355        Address = "A1";
356      }
357      else
358      {
359        Address = _worksheet.View.SelectedRange;
360      }
361    }
362    private void IsRangeValid(string type)
363    {
364      if (_fromRow <= 0)
365      {
366        if (_address == "")
367        {
368          SetToSelectedRange();
369        }
370        else
371        {
372          if (type == "")
373          {
374            throw (new InvalidOperationException(string.Format("Range is not valid for this operation: {0}", _address)));
375          }
376          else
377          {
378            throw (new InvalidOperationException(string.Format("Range is not valid for {0} : {1}", type, _address)));
379          }
380        }
381      }
382    }
383    #region Public Properties
384    /// <summary>
385    /// The styleobject for the range.
386    /// </summary>
387    public ExcelStyle Style
388    {
389      get
390      {
391        IsRangeValid("styling");
392                int s=0;
393                if(!_worksheet._styles.Exists(_fromRow,_fromCol, ref s)) //Cell exists
394                {
395                    if(!_worksheet._styles.Exists(_fromRow,0, ref s)) //No, check Row style
396                    {
397                        var c = Worksheet.GetColumn(_fromCol);
398                        if (c == null)
399                        {
400                            s = 0;
401                        }
402                        else
403                        {
404                            s = c.StyleID;   
405                        }                       
406                    }
407                }
408        return _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, Address);
409      }
410    }
411    /// <summary>
412    /// The named style
413    /// </summary>
414    public string StyleName
415    {
416      get
417      {
418        IsRangeValid("styling");
419        int  xfId;
420                if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows)
421                {
422                    xfId=GetColumnStyle(_fromCol);
423                }
424                else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns)
425                {
426                    xfId = 0;
427                    if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId))
428                    {
429                        xfId = GetColumnStyle(_fromCol);
430                    }
431                }
432                else
433                {
434                    xfId = 0;
435                    if(!_worksheet._styles.Exists(_fromRow, _fromCol, ref xfId))
436                    {
437                        if (!_worksheet._styles.Exists(_fromRow, 0, ref xfId))
438                        {
439                            xfId = GetColumnStyle(_fromCol);
440                        }
441                    }
442                }
443                int nsID;
444                if (xfId <= 0)
445                {
446                    nsID=Style.Styles.CellXfs[0].XfId;
447                }
448                else
449                {
450                    nsID=Style.Styles.CellXfs[xfId].XfId;
451                }
452                foreach (var ns in Style.Styles.NamedStyles)
453                {
454                    if (ns.StyleXfId == nsID)
455                    {
456                        return ns.Name;
457                    }
458                }
459               
460                return "";
461      }
462      set
463      {
464        _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
465                int col = _fromCol;
466                if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows)    //Full column
467        {
468          ExcelColumn column;
469          //Get the startcolumn
470          //ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, column);
471                    var c = _worksheet.GetValue(0, _fromCol);
472                    if (c==null)
473          {
474                        column = _worksheet.Column(_fromCol);
475                        //if (_worksheet._values.PrevCell(ref row, ref col))
476                        //{
477                        //    var prevCol = (ExcelColumn)_worksheet._values.GetValue(row, col);
478                        //    column = prevCol.Clone(_worksheet, column);
479                        //    prevCol.ColumnMax = column - 1;
480                        //}
481          }
482          else
483          {
484                        column = (ExcelColumn)c;
485          }
486
487                    column.StyleName = value;
488                    column.StyleID = _styleID;
489
490                    //var index = _worksheet._columns.IndexOf(colID);
491                    var cols = new CellsStoreEnumerator<object>(_worksheet._values, 0, _fromCol + 1, 0, _toCol);
492                    if (cols.Next())
493                    {
494                        col = _fromCol;
495                        while (column.ColumnMin <= _toCol)
496                        {
497                            if (column.ColumnMax > _toCol)
498                            {
499                                var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax);
500                                column.ColumnMax = _toCol;
501                            }
502
503                            column._styleName = value;
504                            column.StyleID = _styleID;
505
506                            if (cols.Value == null)
507                            {
508                                break;
509                            }
510                            else
511                            {
512                                var nextCol = (ExcelColumn)cols.Value;
513                                if(column.ColumnMax < nextCol.ColumnMax-1)
514                                {
515                                    column.ColumnMax = nextCol.ColumnMax - 1;
516                                }
517                                column = nextCol;
518                                cols.Next();
519                            }
520                        }
521                    }
522                    if (column.ColumnMax < _toCol)
523                    {
524                        column.ColumnMax = _toCol;
525                    }
526                    //if (column.ColumnMin == column)
527                    //{
528                    //    column.ColumnMax = _toCol;
529                    //}
530                    //else if (column._columnMax < _toCol)
531                    //{
532                    //    var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn;
533                    //    newCol._columnMax = _toCol;
534
535                    //    newCol._styleID = _styleID;
536                    //    newCol._styleName = value;
537                    //}
538                    if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) //FullRow
539                    {
540                        var rows = new CellsStoreEnumerator<object>(_worksheet._values, 1, 0, ExcelPackage.MaxRows, 0);
541                        rows.Next();
542                        while(rows.Value!=null)
543                        {
544                            _worksheet._styles.SetValue(rows.Row, 0, _styleID);
545                            if (!rows.Next())
546                            {
547                                break;
548                            }
549                        }
550                    }
551        }
552                else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) //FullRow
553                {
554                    for (int r = _fromRow; r <= _toRow; r++)
555                    {
556                        _worksheet.Row(r)._styleName = value;
557                        _worksheet.Row(r).StyleID = _styleID;
558                    }
559                }
560
561                if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows) || (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns))) //Cell specific
562                {
563                    for (int c = _fromCol; c <= _toCol; c++)
564                    {
565                        for (int r = _fromRow; r <= _toRow; r++)
566                        {
567                            _worksheet._styles.SetValue(r, c, _styleID);
568                        }
569                    }
570                }
571                else //Only set name on created cells. (uncreated cells is set on full row or full column).
572                {
573                    var cells = new CellsStoreEnumerator<object>(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol);
574                    while (cells.Next())
575                    {
576                        _worksheet._styles.SetValue(cells.Row, cells.Column, _styleID);
577                    }
578                }
579                //_changePropMethod(Set_StyleName, value);
580      }
581    }
582
583        private int GetColumnStyle(int col)
584        {
585            object c=null;
586            if (_worksheet._values.Exists(0, col, ref c))
587            {
588                return (c as ExcelColumn).StyleID;
589            }
590            else
591            {
592                int row = 0;
593                if (_worksheet._values.PrevCell(ref row, ref col))
594                {
595                    var column=_worksheet._values.GetValue(row,col) as ExcelColumn;
596                    if(column.ColumnMax>=col)
597                    {
598                        return _worksheet._styles.GetValue(row, col);
599                    }
600                }
601            }
602            return 0;
603        }
604    /// <summary>
605    /// The style ID.
606    /// It is not recomended to use this one. Use Named styles as an alternative.
607    /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook.
608    /// </summary>
609    public int StyleID
610    {
611      get
612      {
613                int s=0;
614                if(!_worksheet._styles.Exists(_fromRow, _fromCol, ref s))
615                {
616                    if (!_worksheet._styles.Exists(_fromRow, 0, ref s))
617                    {
618                        s = _worksheet._styles.GetValue(0, _fromCol);
619                    }
620                }
621                return s;
622      }
623      set
624      {
625        _changePropMethod(Set_StyleID, value);
626      }
627    }
628    /// <summary>
629    /// Set the range to a specific value
630    /// </summary>
631    public object Value
632    {
633      get
634      {
635        if (IsName)
636        {
637          if (_worksheet == null)
638          {
639            return _workbook._names[_address].NameValue;
640          }
641          else
642          {
643            return _worksheet.Names[_address].NameValue;
644          }
645        }
646        else
647        {
648          if (_fromRow == _toRow && _fromCol == _toCol)
649          {
650            return _worksheet.GetValue(_fromRow, _fromCol);
651          }
652          else
653          {
654            return GetValueArray();
655          }
656        }
657      }
658      set
659      {
660        if (IsName)
661        {
662          if (_worksheet == null)
663          {
664            _workbook._names[_address].NameValue = value;
665          }
666          else
667          {
668            _worksheet.Names[_address].NameValue = value;
669          }
670        }
671        else
672        {
673          _changePropMethod(Set_Value, value);
674        }
675      }
676    }
677
678        private bool IsInfinityValue(object value)
679        {
680            double? valueAsDouble = value as double?;
681
682            if(valueAsDouble.HasValue &&
683                (double.IsNegativeInfinity(valueAsDouble.Value) || double.IsPositiveInfinity(valueAsDouble.Value)))
684            {
685                return true;
686            }
687
688            return false;
689        }
690
691    private object GetValueArray()
692    {
693      ExcelAddressBase addr;
694      if (_fromRow == 1 && _fromCol == 1 && _toRow == ExcelPackage.MaxRows && _toCol == ExcelPackage.MaxColumns)
695      {
696        addr = _worksheet.Dimension;
697        if (addr == null) return null;
698      }
699      else
700      {
701        addr = this;
702      }
703      object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1];
704
705      for (int col = addr._fromCol; col <= addr._toCol; col++)
706      {
707        for (int row = addr._fromRow; row <= addr._toRow; row++)
708        {
709          if (_worksheet._values.Exists(row,col))
710          {
711            if (IsRichText)
712            {
713              v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text;
714            }
715            else
716            {
717              v[row - addr._fromRow, col - addr._fromCol] = _worksheet._values.GetValue(row, col);
718            }
719          }
720        }
721      }
722      return v;
723    }
724    private ExcelAddressBase GetAddressDim(ExcelRangeBase addr)
725    {
726      int fromRow, fromCol, toRow, toCol;
727      var d = _worksheet.Dimension;
728      fromRow = addr._fromRow < d._fromRow ? d._fromRow : addr._fromRow;
729      fromCol = addr._fromCol < d._fromCol ? d._fromCol : addr._fromCol;
730
731      toRow = addr._toRow > d._toRow ? d._toRow : addr._toRow;
732      toCol = addr._toCol > d._toCol ? d._toCol : addr._toCol;
733
734      if (addr._fromCol == fromRow && addr._fromCol == addr._fromCol && addr._toRow == toRow && addr._toCol == _toCol)
735      {
736        return addr;
737      }
738      else
739      {
740        if (_fromRow > _toRow || _fromCol > _toCol)
741        {
742          return null;
743        }
744        else
745        {
746          return new ExcelAddressBase(fromRow, fromCol, toRow, toCol);
747        }
748      }
749    }
750
751    private object GetSingleValue()
752    {
753      if (IsRichText)
754      {
755        return RichText.Text;
756      }
757      else
758      {
759        return _worksheet._values.GetValue(_fromRow, _fromCol);
760      }
761    }
762    /// <summary>
763    /// Returns the formatted value.
764    /// </summary>
765    public string Text
766    {
767      get
768      {
769        return GetFormattedText(false);
770      }
771    }
772    /// <summary>
773    /// Set the column width from the content of the range. The minimum width is the value of the ExcelWorksheet.defaultColumnWidth property.
774    /// Note: Cells containing formulas are ignored since EPPlus don't have a calculation engine.
775    /// Wrapped and merged cells are also ignored.
776    /// </summary>
777    public void AutoFitColumns()
778    {
779      AutoFitColumns(_worksheet.DefaultColWidth);
780    }
781
782    /// <summary>
783    /// Set the column width from the content of the range.
784    /// Note: Cells containing formulas are ignored if no calculation is made.
785    ///       Wrapped and merged cells are also ignored.
786    /// </summary>
787        /// <remarks>This method will not work if you run in an environment that does not support GDI</remarks>
788    /// <param name="MinimumWidth">Minimum column width</param>
789    public void AutoFitColumns(double MinimumWidth)
790    {
791        AutoFitColumns(MinimumWidth, double.MaxValue);
792    }
793
794      /// <summary>
795      /// Set the column width from the content of the range.
796        /// Note: Cells containing formulas are ignored if no calculation is made.
797        ///       Wrapped and merged cells are also ignored.
798      /// </summary>
799      /// <param name="MinimumWidth">Minimum column width</param>
800      /// <param name="MaximumWidth">Maximum column width</param>
801      public void AutoFitColumns(double MinimumWidth, double MaximumWidth)
802    {
803            if (_worksheet.Dimension == null)
804            {
805                return;
806            }
807            if (_fromCol < 1 || _fromRow < 1)
808      {
809        SetToSelectedRange();
810      }
811            var fontCache = new Dictionary<int, Font>();
812
813          bool doAdjust = _worksheet._package.DoAdjustDrawings;
814      _worksheet._package.DoAdjustDrawings = false;
815      var drawWidths = _worksheet.Drawings.GetDrawingWidths();
816
817      var fromCol = _fromCol > _worksheet.Dimension._fromCol ? _fromCol : _worksheet.Dimension._fromCol;
818      var toCol = _toCol < _worksheet.Dimension._toCol ? _toCol : _worksheet.Dimension._toCol;
819      if (Addresses == null)
820      {
821        SetMinWidth(MinimumWidth, fromCol, toCol);
822      }
823      else
824      {
825        foreach (var addr in Addresses)
826        {
827          fromCol = addr._fromCol > _worksheet.Dimension._fromCol ? addr._fromCol : _worksheet.Dimension._fromCol;
828          toCol = addr._toCol < _worksheet.Dimension._toCol ? addr._toCol : _worksheet.Dimension._toCol;
829                    SetMinWidth(MinimumWidth, fromCol, toCol);
830                }
831      }
832
833      //Get any autofilter to widen these columns
834      var afAddr = new List<ExcelAddressBase>();
835      if (_worksheet.AutoFilterAddress != null)
836      {
837        afAddr.Add(new ExcelAddressBase(    _worksheet.AutoFilterAddress._fromRow,
838                          _worksheet.AutoFilterAddress._fromCol,
839                          _worksheet.AutoFilterAddress._fromRow,
840                          _worksheet.AutoFilterAddress._toCol));
841        afAddr[afAddr.Count - 1]._ws = WorkSheet;
842      }
843      foreach (var tbl in _worksheet.Tables)
844      {
845        if (tbl.AutoFilterAddress != null)
846        {
847          afAddr.Add(new ExcelAddressBase(tbl.AutoFilterAddress._fromRow,
848                                      tbl.AutoFilterAddress._fromCol,
849                                      tbl.AutoFilterAddress._fromRow,
850                                      tbl.AutoFilterAddress._toCol));
851          afAddr[afAddr.Count - 1]._ws = WorkSheet;
852        }
853      }
854
855      var styles = _worksheet.Workbook.Styles;
856      var nf = styles.Fonts[styles.CellXfs[0].FontId];
857      var fs = FontStyle.Regular;
858      if (nf.Bold) fs |= FontStyle.Bold;
859      if (nf.UnderLine) fs |= FontStyle.Underline;
860      if (nf.Italic) fs |= FontStyle.Italic;
861      if (nf.Strike) fs |= FontStyle.Strikeout;
862      var nfont = new Font(nf.Name, nf.Size, fs);
863           
864      using (var b = new Bitmap(1, 1))
865      {
866        using (var g = Graphics.FromImage(b))
867        {
868          var normalSize = (float)Math.Truncate(g.MeasureString("00", nfont).Width - g.MeasureString("0", nfont).Width);
869          g.PageUnit = GraphicsUnit.Pixel;
870          foreach (var cell in this)
871          {
872            if (cell.Merge == true || cell.Style.WrapText) continue;
873            var fntID = styles.CellXfs[cell.StyleID].FontId;
874              Font f;
875              if (fontCache.ContainsKey(fntID))
876            {
877              f = fontCache[fntID];
878            }
879            else
880            {
881              var fnt = styles.Fonts[fntID];
882              fs = FontStyle.Regular;
883              if (fnt.Bold) fs |= FontStyle.Bold;
884              if (fnt.UnderLine) fs |= FontStyle.Underline;
885              if (fnt.Italic) fs |= FontStyle.Italic;
886              if (fnt.Strike) fs |= FontStyle.Strikeout;
887              f = new Font(fnt.Name, fnt.Size, fs);
888              fontCache.Add(fntID, f);
889            }
890
891            //Truncate(({pixels}-5)/{Maximum Digit Width} * 100+0.5)/100
892
893                        var size = g.MeasureString(cell.TextForWidth, f);
894                        double width;
895                        double r = styles.CellXfs[cell.StyleID].TextRotation;
896                        if (r <= 0 )
897                        {
898                            width = (size.Width + 5) / normalSize;
899                        }
900                        else
901                        {
902                            r = (r <= 90 ? r : r - 90);
903                            width = (((size.Width - size.Height) * Math.Abs(System.Math.Cos(System.Math.PI * r / 180.0)) + size.Height) + 5) / normalSize;
904                        }
905
906            foreach (var a in afAddr)
907            {
908              if (a.Collide(cell) != eAddressCollition.No)
909              {
910                width += 2.25;
911                break;
912              }
913            }
914
915            if (width > _worksheet.Column(cell._fromCol).Width)
916            {
917              _worksheet.Column(cell._fromCol).Width = width > MaximumWidth ? MaximumWidth : width;
918            }
919          }
920        }
921      }
922      _worksheet.Drawings.AdjustWidth(drawWidths);
923      _worksheet._package.DoAdjustDrawings = doAdjust;
924    }
925
926        private void SetMinWidth(double minimumWidth, int fromCol, int toCol)
927        {
928            var iterator = new CellsStoreEnumerator<object>(_worksheet._values, 0, fromCol, 0, toCol);
929            var prevCol = fromCol;
930            foreach (ExcelColumn col in iterator)
931            {
932                col.Width = minimumWidth;
933                if (_worksheet.DefaultColWidth > minimumWidth && col.ColumnMin > prevCol)
934                {
935                    var newCol = _worksheet.Column(prevCol);
936                    newCol.ColumnMax = col.ColumnMin - 1;
937                    newCol.Width = minimumWidth;
938                }
939                prevCol = col.ColumnMax + 1;
940            }
941            if (_worksheet.DefaultColWidth > minimumWidth && prevCol<toCol)
942            {
943                var newCol = _worksheet.Column(prevCol);
944                newCol.ColumnMax = toCol;
945                newCol.Width = minimumWidth;
946            }
947        }
948
949        internal string TextForWidth
950    {
951      get
952      {
953        return GetFormattedText(true);
954      }
955    }
956    private string GetFormattedText(bool forWidthCalc)
957    {
958      object v = Value;
959      if (v == null) return "";
960      var styles = Worksheet.Workbook.Styles;
961      var nfID = styles.CellXfs[StyleID].NumberFormatId;
962      ExcelNumberFormatXml.ExcelFormatTranslator nf = null;
963      for (int i = 0; i < styles.NumberFormats.Count; i++)
964      {
965        if (nfID == styles.NumberFormats[i].NumFmtId)
966        {
967          nf = styles.NumberFormats[i].FormatTranslator;
968          break;
969        }
970      }
971
972      string format, textFormat;
973      if (forWidthCalc)
974      {
975        format = nf.NetFormatForWidth;
976        textFormat = nf.NetTextFormatForWidth;
977      }
978      else
979      {
980        format = nf.NetFormat;
981        textFormat = nf.NetTextFormat;
982      }
983
984            return FormatValue(v, nf, format, textFormat);
985    }
986
987        internal static string FormatValue(object v, ExcelNumberFormatXml.ExcelFormatTranslator nf, string format, string textFormat)
988        {
989      if (v is decimal || v.GetType().IsPrimitive)
990      {
991        double d;
992        try
993        {
994          d = Convert.ToDouble(v);
995        }
996        catch
997        {
998          return "";
999        }
1000
1001        if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number)
1002        {
1003          if (string.IsNullOrEmpty(nf.FractionFormat))
1004          {
1005            return d.ToString(format, nf.Culture);
1006          }
1007          else
1008          {
1009            return nf.FormatFraction(d);
1010          }
1011        }
1012        else if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime)
1013        {
1014          var date = DateTime.FromOADate(d);
1015          return date.ToString(format, nf.Culture);
1016        }
1017      }
1018      else if (v is DateTime)
1019      {
1020        if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime)
1021        {
1022          return ((DateTime)v).ToString(format, nf.Culture);
1023        }
1024        else
1025        {
1026          double d = ((DateTime)v).ToOADate();
1027          if (string.IsNullOrEmpty(nf.FractionFormat))
1028          {
1029            return d.ToString(format, nf.Culture);
1030          }
1031          else
1032          {
1033            return nf.FormatFraction(d);
1034          }
1035        }
1036      }
1037      else if (v is TimeSpan)
1038      {
1039        if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime)
1040        {
1041          return new DateTime(((TimeSpan)v).Ticks).ToString(format, nf.Culture);
1042        }
1043        else
1044        {
1045          double d = (new DateTime(((TimeSpan)v).Ticks)).ToOADate();
1046          if (string.IsNullOrEmpty(nf.FractionFormat))
1047          {
1048            return d.ToString(format, nf.Culture);
1049          }
1050          else
1051          {
1052            return nf.FormatFraction(d);
1053          }
1054        }
1055      }
1056      else
1057      {
1058        if (textFormat == "")
1059        {
1060          return v.ToString();
1061        }
1062        else
1063        {
1064          return string.Format(textFormat, v);
1065        }
1066      }
1067      return v.ToString();
1068}
1069    /// <summary>
1070    /// Gets or sets a formula for a range.
1071    /// </summary>
1072    public string Formula
1073    {
1074      get
1075      {
1076        if (IsName)
1077        {
1078          if (_worksheet == null)
1079          {
1080            return _workbook._names[_address].NameFormula;
1081          }
1082          else
1083          {
1084            return _worksheet.Names[_address].NameFormula;
1085          }
1086        }
1087        else
1088        {
1089          return _worksheet.GetFormula(_fromRow, _fromCol);                   
1090        }
1091      }
1092      set
1093      {
1094        if (IsName)
1095        {
1096          if (_worksheet == null)
1097          {
1098            _workbook._names[_address].NameFormula = value;
1099          }
1100          else
1101          {
1102            _worksheet.Names[_address].NameFormula = value;
1103          }
1104        }
1105        else
1106        {
1107          if(value==null || value.Trim()=="")
1108                    {
1109                        //Set the cells to null
1110                        Value = null;
1111                    }                   
1112                    else if (_fromRow == _toRow && _fromCol == _toCol)
1113          {
1114            Set_Formula(value, _fromRow, _fromCol);
1115          }
1116          else
1117          {
1118            Set_SharedFormula(value, this, false);
1119            if (Addresses != null)
1120            {
1121              foreach (var address in Addresses)
1122              {
1123                Set_SharedFormula(value, address, false);
1124              }
1125            }
1126          }
1127        }
1128      }
1129    }
1130    /// <summary>
1131    /// Gets or Set a formula in R1C1 format.
1132    /// </summary>
1133    public string FormulaR1C1
1134    {
1135      get
1136      {
1137        IsRangeValid("FormulaR1C1");
1138        return _worksheet.GetFormulaR1C1(_fromRow, _fromCol);
1139      }
1140      set
1141      {
1142        IsRangeValid("FormulaR1C1");
1143                if (value.Length > 0 && value[0] == '=') value = value.Substring(1, value.Length - 1); // remove any starting equalsign.
1144
1145                if (value == null || value.Trim() == "")
1146                {
1147                    //Set the cells to null
1148                    _worksheet.Cells[ExcelCellBase.TranslateFromR1C1(value, _fromRow, _fromCol)].Value = null;   
1149                }
1150        else if (Addresses == null)
1151        {
1152          Set_SharedFormula(ExcelCellBase.TranslateFromR1C1(value, _fromRow, _fromCol), this, false);
1153        }
1154        else
1155        {
1156          Set_SharedFormula(ExcelCellBase.TranslateFromR1C1(value, _fromRow, _fromCol), new ExcelAddress(WorkSheet, FirstAddress), false);
1157          foreach (var address in Addresses)
1158          {
1159            Set_SharedFormula(ExcelCellBase.TranslateFromR1C1(value, address.Start.Row, address.Start.Column), address, false);
1160          }
1161        }
1162      }
1163    }
1164    /// <summary>
1165    /// Set the hyperlink property for a range of cells
1166    /// </summary>
1167    public Uri Hyperlink
1168    {
1169      get
1170      {
1171        IsRangeValid("formulaR1C1");
1172        return _worksheet._hyperLinks.GetValue(_fromRow, _fromCol);
1173      }
1174      set
1175      {
1176        _changePropMethod(Set_HyperLink, value);
1177      }
1178    }
1179    /// <summary>
1180    /// If the cells in the range are merged.
1181    /// </summary>
1182    public bool Merge
1183    {
1184      get
1185      {
1186        IsRangeValid("merging");
1187        for (int col = _fromCol; col <= _toCol; col++)
1188        {
1189          for (int row = _fromRow; row <= _toRow; row++)
1190          {
1191                        if(_worksheet.MergedCells[row, col]==null)
1192                        {
1193                            return false;
1194                        }
1195                        //if (!_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged))
1196                        //{
1197                        //    return false;
1198                        //}
1199          }
1200        }
1201        return true;
1202      }
1203      set
1204      {
1205        IsRangeValid("merging");
1206        //SetMerge(value, FirstAddress);
1207          if (value)
1208          {
1209              _worksheet.MergedCells.Add(new ExcelAddressBase(FirstAddress), true);
1210              if (Addresses != null)
1211              {
1212                  foreach (var address in Addresses)
1213                  {
1214                      _worksheet.MergedCells.Add(address, true);
1215                      //SetMerge(value, address._address);
1216                  }
1217              }
1218          }
1219          else
1220          {
1221              _worksheet.MergedCells.Delete(this);
1222                    if (Addresses != null)
1223              {
1224                  foreach (var address in Addresses)
1225                  {
1226                            _worksheet.MergedCells.Delete(address); ;
1227                  }
1228              }
1229             
1230          }
1231      }
1232    }
1233
1234        //private void SetMerge(bool value, string address)
1235        //{
1236        //    if (!value)
1237        //    {
1238        //        if (_worksheet.MergedCells.List.Contains(address))
1239        //        {
1240        //            SetCellMerge(false, address);
1241        //            _worksheet.MergedCells.List.Remove(address);
1242        //        }
1243        //        else if (!CheckMergeDiff(false, address))
1244        //        {
1245        //            throw (new Exception("Range is not fully merged.Specify the exact range"));
1246        //        }
1247        //    }
1248        //    else
1249        //    {
1250        //        if (CheckMergeDiff(false, address))
1251        //        {
1252        //            SetCellMerge(true, address);
1253        //            _worksheet.MergedCells.List.Add(address);
1254        //        }
1255        //        else
1256        //        {
1257        //            if (!_worksheet.MergedCells.List.Contains(address))
1258        //            {
1259        //                throw (new Exception("Cells are already merged"));
1260        //            }
1261        //        }
1262        //    }
1263        //}
1264    /// <summary>
1265    /// Set an autofilter for the range
1266    /// </summary>
1267    public bool AutoFilter
1268    {
1269      get
1270      {
1271        IsRangeValid("autofilter");
1272        ExcelAddressBase address = _worksheet.AutoFilterAddress;
1273        if (address == null) return false;
1274        if (_fromRow >= address.Start.Row
1275            &&
1276            _toRow <= address.End.Row
1277            &&
1278            _fromCol >= address.Start.Column
1279            &&
1280            _toCol <= address.End.Column)
1281        {
1282          return true;
1283        }
1284        return false;
1285      }
1286      set
1287      {
1288        IsRangeValid("autofilter");
1289        _worksheet.AutoFilterAddress = this;
1290        if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase"))
1291        {
1292          _worksheet.Names.Remove("_xlnm._FilterDatabase");
1293        }
1294        var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this);
1295        result.IsNameHidden = true;
1296      }
1297    }
1298    /// <summary>
1299    /// If the value is in richtext format.
1300    /// </summary>
1301    public bool IsRichText
1302    {
1303      get
1304      {
1305        IsRangeValid("richtext");
1306        return _worksheet._flags.GetFlagValue(_fromRow, _fromCol,CellFlags.RichText);
1307      }
1308      set
1309      {
1310        _changePropMethod(Set_IsRichText, value);
1311      }
1312    }
1313    /// <summary>
1314    /// Is the range a part of an Arrayformula
1315    /// </summary>
1316    public bool IsArrayFormula
1317    {
1318      get
1319      {
1320        IsRangeValid("arrayformulas");
1321                return _worksheet._flags.GetFlagValue(_fromRow, _fromCol, CellFlags.ArrayFormula);
1322      }
1323    }
1324    ExcelRichTextCollection _rtc = null;
1325    /// <summary>
1326    /// Cell value is richtext formated.
1327    /// </summary>
1328    public ExcelRichTextCollection RichText
1329    {
1330      get
1331      {
1332        IsRangeValid("richtext");
1333        if (_rtc == null)
1334        {
1335          _rtc = GetRichText(_fromRow, _fromCol);
1336        }
1337        return _rtc;
1338      }
1339    }
1340
1341    private ExcelRichTextCollection GetRichText(int row, int col)
1342    {
1343      XmlDocument xml = new XmlDocument();
1344            var v = _worksheet._values.GetValue(row, col);
1345            var isRt = _worksheet._flags.GetFlagValue(row, col, CellFlags.RichText);
1346            if (v != null)
1347      {
1348        if (isRt)
1349        {
1350                    XmlHelper.LoadXmlSafe(xml, "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >" + v.ToString() + "</d:si>", Encoding.UTF8);
1351        }
1352        else
1353        {
1354          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>");
1355        }
1356      }
1357      else
1358      {
1359        xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />");
1360      }
1361      var rtc = new ExcelRichTextCollection(_worksheet.NameSpaceManager, xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager), this);
1362            if (rtc.Count == 1 && isRt == false)
1363      {
1364        IsRichText = true;
1365                var s = _worksheet._styles.GetValue(row, col);
1366                //var fnt = cell.Style.Font;
1367                var fnt = _worksheet.Workbook.Styles.GetStyleObject(s, _worksheet.PositionID, ExcelAddressBase.GetAddress(row, col)).Font;
1368        rtc[0].PreserveSpace = true;
1369        rtc[0].Bold = fnt.Bold;
1370        rtc[0].FontName = fnt.Name;
1371        rtc[0].Italic = fnt.Italic;
1372        rtc[0].Size = fnt.Size;
1373        rtc[0].UnderLine = fnt.UnderLine;
1374
1375        int hex;
1376        if (fnt.Color.Rgb != "" && int.TryParse(fnt.Color.Rgb, NumberStyles.HexNumber, null, out hex))
1377        {
1378          rtc[0].Color = Color.FromArgb(hex);
1379        }
1380
1381      }
1382      return rtc;
1383    }
1384    /// <summary>
1385    /// returns the comment object of the first cell in the range
1386    /// </summary>
1387    public ExcelComment Comment
1388    {
1389      get
1390      {
1391        IsRangeValid("comments");
1392        ulong cellID = GetCellID(_worksheet.SheetID, _fromRow, _fromCol);
1393        if (_worksheet.Comments._comments.ContainsKey(cellID))
1394        {
1395          return _worksheet._comments._comments[cellID] as ExcelComment;
1396        }
1397        return null;
1398      }
1399    }
1400    /// <summary>
1401    /// WorkSheet object
1402    /// </summary>
1403    public ExcelWorksheet Worksheet
1404    {
1405      get
1406      {
1407        return _worksheet;
1408      }
1409    }
1410    /// <summary>
1411    /// Address including sheetname
1412    /// </summary>
1413    public string FullAddress
1414    {
1415      get
1416      {
1417        string fullAddress = GetFullAddress(_worksheet.Name, _address);
1418        if (Addresses != null)
1419        {
1420          foreach (var a in Addresses)
1421          {
1422            fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address); ;
1423          }
1424        }
1425        return fullAddress;
1426      }
1427    }
1428    /// <summary>
1429    /// Address including sheetname
1430    /// </summary>
1431    public string FullAddressAbsolute
1432    {
1433      get
1434      {
1435        string wbwsRef = string.IsNullOrEmpty(base._wb) ? base._ws : "[" + base._wb.Replace("'", "''") + "]" + _ws;
1436        string fullAddress = GetFullAddress(wbwsRef, GetAddress(_fromRow, _fromCol, _toRow, _toCol, true));
1437        if (Addresses != null)
1438        {
1439          foreach (var a in Addresses)
1440          {
1441            fullAddress += "," + GetFullAddress(wbwsRef, GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true)); ;
1442          }
1443        }
1444        return fullAddress;
1445      }
1446    }
1447        /// <summary>
1448        /// Address including sheetname
1449        /// </summary>
1450        internal string FullAddressAbsoluteNoFullRowCol
1451        {
1452            get
1453            {
1454                string wbwsRef = string.IsNullOrEmpty(base._wb) ? base._ws : "[" + base._wb.Replace("'", "''") + "]" + _ws;
1455                string fullAddress = GetFullAddress(wbwsRef, GetAddress(_fromRow, _fromCol, _toRow, _toCol, true), false);
1456                if (Addresses != null)
1457                {
1458                    foreach (var a in Addresses)
1459                    {
1460                        fullAddress += "," + GetFullAddress(wbwsRef, GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true),false); ;
1461                    }
1462                }
1463                return fullAddress;
1464            }
1465        }
1466    #endregion
1467    #region Private Methods
1468        ///// <summary>
1469        ///// Check if the range is partly merged
1470        ///// </summary>
1471        ///// <param name="startValue">the starting value</param>
1472        ///// <param name="address">the address</param>
1473        ///// <returns></returns>
1474        //private bool CheckMergeDiff(bool startValue, string address)
1475        //{
1476        //    ExcelAddress a = new ExcelAddress(address);
1477        //    for (int col = a.column; col <= a._toCol; col++)
1478        //    {
1479        //        for (int row = a._fromRow; row <= a._toRow; row++)
1480        //        {
1481        //            if (_worksheet._flags.GetFlagValue(row, col, CellFlags.Merged) != startValue)
1482        //            {
1483        //                return false;
1484        //            }
1485        //        }
1486        //    }
1487        //    return true;
1488        //}
1489        ///// <summary>
1490        ///// Set the merge flag for the range
1491        ///// </summary>
1492        ///// <param name="value"></param>
1493        ///// <param name="address"></param>
1494        //internal void SetCellMerge(bool value, string address)
1495        //{
1496        //    ExcelAddress a = new ExcelAddress(address);
1497        //    for (int col = a.column; col <= a._toCol; col++)
1498        //    {
1499        //        for (int row = a._fromRow; row <= a._toRow; row++)
1500        //        {
1501        //            _worksheet._flags.SetFlagValue(row, col,value,CellFlags.Merged);
1502        //        }
1503        //    }
1504        //}
1505    /// <summary>
1506    /// Set the value without altering the richtext property
1507    /// </summary>
1508    /// <param name="value">the value</param>
1509    internal void SetValueRichText(object value)
1510    {
1511      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
1512      {
1513        //_worksheet.Cell(1, 1).SetValueRichText(value);
1514                SetValue(value, 1, 1);
1515      }
1516      else
1517      {
1518        for (int col = _fromCol; col <= _toCol; col++)
1519        {
1520          for (int row = _fromRow; row <= _toRow; row++)
1521          {
1522            //_worksheet.Cell(row, col).SetValueRichText(value);
1523                        SetValue(value, row,col);
1524          }
1525        }
1526      }
1527    }
1528
1529        private void SetValue(object value, int row, int col)
1530        {
1531            _worksheet.SetValue(row, col, value);
1532           // if (value is string) _worksheet._types.SetValue(row, col, "S"); else _worksheet._types.SetValue(row, col, "");
1533            _worksheet._formulas.SetValue(row, col, "");
1534        }
1535    /// <summary>
1536    /// Removes a shared formula
1537    /// </summary>
1538        //private void RemoveFormuls(ExcelAddress address)
1539        //{
1540        //    List<int> removed = new List<int>();
1541        //    int fFromRow, fFromCol, fToRow, fToCol;
1542        //    foreach (int index in _worksheet._sharedFormulas.Keys)
1543        //    {
1544        //        ExcelWorksheet.Formulas f = _worksheet._sharedFormulas[index];
1545        //        ExcelCellBase.GetRowColFromAddress(f.Address, out fFromRow, out fFromCol, out fToRow, out fToCol);
1546        //        if (((fFromCol >= address.Start.Column && fFromCol <= address.End.Column) ||
1547        //             (fToCol >= address.Start.Column && fToCol <= address.End.Column)) &&
1548        //             ((fFromRow >= address.Start.Row && fFromRow <= address.End.Row) ||
1549        //             (fToRow >= address.Start.Row && fToRow <= address.End.Row)))
1550        //        {
1551        //            for (int col = fFromCol; col <= fToCol; col++)
1552        //            {
1553        //                for (int row = fFromRow; row <= fToRow; row++)
1554        //                {
1555        //                    _worksheet._formulas.SetValue(row, col, int.MinValue);
1556        //                }
1557        //            }
1558        //            removed.Add(index);
1559        //        }
1560        //    }
1561        //    foreach (int index in removed)
1562        //    {
1563        //        _worksheet._sharedFormulas.Remove(index);
1564        //    }
1565        //}
1566    internal void SetSharedFormulaID(int id)
1567    {
1568      for (int col = _fromCol; col <= _toCol; col++)
1569      {
1570        for (int row = _fromRow; row <= _toRow; row++)
1571        {
1572                    _worksheet._formulas.SetValue(row, col, id);
1573        }
1574      }
1575    }
1576    private void CheckAndSplitSharedFormula(ExcelAddressBase address)
1577    {
1578            for (int col = address._fromCol; col <= address._toCol; col++)
1579      {
1580                for (int row = address._fromRow; row <= address._toRow; row++)
1581        {
1582                    var f = _worksheet._formulas.GetValue(row, col);
1583                    if (f is int && (int)f >= 0)
1584          {
1585            SplitFormulas(address);
1586            return;
1587          }
1588        }
1589      }
1590    }
1591
1592    private void SplitFormulas(ExcelAddressBase address)
1593    {
1594      List<int> formulas = new List<int>();
1595            for (int col = address._fromCol; col <= address._toCol; col++)
1596      {
1597                for (int row = address._fromRow; row <= address._toRow; row++)
1598        {
1599          var f = _worksheet._formulas.GetValue(row, col);
1600                    if (f is int)
1601                    {
1602                        int id = (int)f;
1603                        if (id >= 0 && !formulas.Contains(id))
1604                        {
1605                            if (_worksheet._sharedFormulas[id].IsArray &&
1606                                    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
1607                            {
1608                                throw (new InvalidOperationException("Can not overwrite a part of an array-formula"));
1609                            }
1610                            formulas.Add(id);
1611                        }
1612                    }                   
1613        }
1614      }
1615
1616      foreach (int ix in formulas)
1617      {
1618                SplitFormula(address, ix);
1619      }
1620       
1621            ////Delete any formula references inside the refered range
1622            //_worksheet._formulas.Delete(address._fromRow, address._toRow, address._toRow - address._fromRow + 1, address._toCol - address.column + 1);
1623        }
1624
1625    private void SplitFormula(ExcelAddressBase address, int ix)
1626    {
1627      var f = _worksheet._sharedFormulas[ix];
1628      var fRange = _worksheet.Cells[f.Address];
1629            var collide = address.Collide(fRange);
1630
1631            //The formula is inside the currenct range, remove it
1632      if (collide == eAddressCollition.Equal || collide == eAddressCollition.Inside)
1633      {
1634        _worksheet._sharedFormulas.Remove(ix);
1635                return;
1636        //fRange.SetSharedFormulaID(int.MinValue);
1637      }
1638            var firstCellCollide = address.Collide(new ExcelAddressBase(fRange._fromRow, fRange._fromCol, fRange._fromRow, fRange._fromCol));
1639            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.
1640            {
1641                //The formula partly collides with the current range
1642                bool fIsSet = false;
1643                string formulaR1C1 = fRange.FormulaR1C1;
1644                //Top Range
1645                if (fRange._fromRow < _fromRow)
1646                {
1647                    f.Address = ExcelCellBase.GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol);
1648                    fIsSet = true;
1649                }
1650                //Left Range
1651                if (fRange._fromCol < address._fromCol)
1652                {
1653                    if (fIsSet)
1654                    {
1655                        f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default);
1656                        f.Index = _worksheet.GetMaxShareFunctionIndex(false);
1657                        f.StartCol = fRange._fromCol;
1658                        f.IsArray = false;
1659                        _worksheet._sharedFormulas.Add(f.Index, f);
1660                    }
1661                    else
1662                    {
1663                        fIsSet = true;
1664                    }
1665                    if (fRange._fromRow < address._fromRow)
1666                        f.StartRow = address._fromRow;
1667                    else
1668                    {
1669                        f.StartRow = fRange._fromRow;
1670                    }
1671                    if (fRange._toRow < address._toRow)
1672                    {
1673                        f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol,
1674                                fRange._toRow, address._fromCol - 1);
1675                    }
1676                    else
1677                    {
1678                        f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol,
1679                             address._toRow, address._fromCol - 1);
1680                    }
1681                    f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
1682                    _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index);
1683                }
1684                //Right Range
1685                if (fRange._toCol > address._toCol)
1686                {
1687                    if (fIsSet)
1688                    {
1689                        f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default);
1690                        f.Index = _worksheet.GetMaxShareFunctionIndex(false);
1691                        f.IsArray = false;
1692                        _worksheet._sharedFormulas.Add(f.Index, f);
1693                    }
1694                    else
1695                    {
1696                        fIsSet = true;
1697                    }
1698                    f.StartCol = address._toCol + 1;
1699                    if (address._fromRow < fRange._fromRow)
1700                        f.StartRow = fRange._fromRow;
1701                    else
1702                    {
1703                        f.StartRow = address._fromRow;
1704                    }
1705
1706                    if (fRange._toRow < address._toRow)
1707                    {
1708                        f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol,
1709                                fRange._toRow, fRange._toCol);
1710                    }
1711                    else
1712                    {
1713                        f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol,
1714                                address._toRow, fRange._toCol);
1715                    }
1716                    f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
1717                    _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index);
1718                }
1719                //Bottom Range
1720                if (fRange._toRow > address._toRow)
1721                {
1722                    if (fIsSet)
1723                    {
1724                        f = new ExcelWorksheet.Formulas(SourceCodeTokenizer.Default);
1725                        f.Index = _worksheet.GetMaxShareFunctionIndex(false);
1726                        f.IsArray = false;
1727                        _worksheet._sharedFormulas.Add(f.Index, f);
1728                    }
1729
1730                    f.StartCol = fRange._fromCol;
1731                    f.StartRow = _toRow + 1;
1732
1733                    f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
1734
1735                    f.Address = ExcelCellBase.GetAddress(f.StartRow, f.StartCol,
1736                            fRange._toRow, fRange._toCol);
1737                    _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index);
1738
1739                }
1740            }
1741    }
1742    private object ConvertData(ExcelTextFormat Format, string v, int col, bool isText)
1743    {
1744      if (isText && (Format.DataTypes == null || Format.DataTypes.Length < col)) return v;
1745
1746      double d;
1747      DateTime dt;
1748      if (Format.DataTypes == null || Format.DataTypes.Length <= col || Format.DataTypes[col] == eDataTypes.Unknown)
1749      {
1750        string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
1751        if (double.TryParse(v2, NumberStyles.Any, Format.Culture, out d))
1752        {
1753          if (v2 == v)
1754          {
1755            return d;
1756          }
1757          else
1758          {
1759            return d / 100;
1760          }
1761        }
1762        if (DateTime.TryParse(v, Format.Culture, DateTimeStyles.None, out dt))
1763        {
1764          return dt;
1765        }
1766        else
1767        {
1768          return v;
1769        }
1770      }
1771      else
1772      {
1773        switch (Format.DataTypes[col])
1774        {
1775          case eDataTypes.Number:
1776            if (double.TryParse(v, NumberStyles.Any, Format.Culture, out d))
1777            {
1778              return d;
1779            }
1780            else
1781            {
1782              return v;
1783            }
1784          case eDataTypes.DateTime:
1785            if (DateTime.TryParse(v, Format.Culture, DateTimeStyles.None, out dt))
1786            {
1787              return dt;
1788            }
1789            else
1790            {
1791              return v;
1792            }
1793          case eDataTypes.Percent:
1794            string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
1795            if (double.TryParse(v2, NumberStyles.Any, Format.Culture, out d))
1796            {
1797              return d / 100;
1798            }
1799            else
1800            {
1801              return v;
1802            }
1803
1804          default:
1805            return v;
1806
1807        }
1808      }
1809    }
1810    #endregion
1811    #region Public Methods
1812    #region ConditionalFormatting
1813    /// <summary>
1814    /// Conditional Formatting for this range.
1815    /// </summary>
1816    public IRangeConditionalFormatting ConditionalFormatting
1817    {
1818      get
1819      {
1820        return new RangeConditionalFormatting(_worksheet, new ExcelAddress(Address));
1821      }
1822    }
1823    #endregion
1824    #region DataValidation
1825    /// <summary>
1826    /// Data validation for this range.
1827    /// </summary>
1828    public IRangeDataValidation DataValidation
1829    {
1830      get
1831      {
1832                return new RangeDataValidation(_worksheet, Address);
1833      }
1834    }
1835    #endregion
1836        #region LoadFromDataReader
1837      /// <summary>
1838      /// Load the data from the datareader starting from the top left cell of the range
1839      /// </summary>
1840      /// <param name="Reader">The datareader to loadfrom</param>
1841      /// <param name="PrintHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param>
1842      /// <param name="TableName">The name of the table</param>
1843      /// <param name="TableStyle">The table style to apply to the data</param>
1844      /// <returns>The filled range</returns>
1845      public ExcelRangeBase LoadFromDataReader(IDataReader Reader, bool PrintHeaders, string TableName, TableStyles TableStyle = TableStyles.None)
1846      {
1847          var r = LoadFromDataReader(Reader, PrintHeaders);
1848
1849            int rows = r.Rows - 1;
1850          if (rows >= 0 && r.Columns > 0)
1851          {
1852              var tbl = _worksheet.Tables.Add(new ExcelAddressBase(_fromRow, _fromCol, _fromRow + (rows <= 0 ? 1 : rows), _fromCol + r.Columns - 1), TableName);
1853              tbl.ShowHeader = PrintHeaders;
1854              tbl.TableStyle = TableStyle;
1855          }
1856          return r;
1857      }
1858
1859      /// <summary>
1860      /// Load the data from the datareader starting from the top left cell of the range
1861      /// </summary>
1862      /// <param name="Reader">The datareader to load from</param>
1863      /// <param name="PrintHeaders">Print the caption property (if set) or the columnname property if not, on first row</param>
1864      /// <returns>The filled range</returns>
1865      public ExcelRangeBase LoadFromDataReader(IDataReader Reader, bool PrintHeaders)
1866      {
1867          if (Reader == null)
1868          {
1869              throw (new ArgumentNullException("Reader", "Reader can't be null"));
1870          }
1871          int fieldCount = Reader.FieldCount;
1872   
1873          int col = _fromCol, row = _fromRow;
1874          if (PrintHeaders)
1875          {
1876              for (int i = 0; i < fieldCount; i++)
1877              {
1878                  // If no caption is set, the ColumnName property is called implicitly.
1879                  _worksheet._values.SetValue(row, col++, Reader.GetName(i));
1880              }
1881              row++;
1882              col = _fromCol;
1883          }
1884          while(Reader.Read())
1885          {
1886              for (int i = 0; i < fieldCount; i++)
1887              {
1888                  _worksheet._values.SetValue(row, col++, Reader.GetValue(i));
1889              }
1890              row++;
1891              col = _fromCol;
1892          }
1893          return _worksheet.Cells[_fromRow, _fromCol, row - 1, _fromCol + fieldCount - 1];
1894      }
1895      #endregion
1896    #region LoadFromDataTable
1897    /// <summary>
1898    /// Load the data from the datatable starting from the top left cell of the range
1899    /// </summary>
1900    /// <param name="Table">The datatable to load</param>
1901    /// <param name="PrintHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param>
1902    /// <param name="TableStyle">The table style to apply to the data</param>
1903    /// <returns>The filled range</returns>
1904    public ExcelRangeBase LoadFromDataTable(DataTable Table, bool PrintHeaders, TableStyles TableStyle)
1905    {
1906      var r = LoadFromDataTable(Table, PrintHeaders);
1907
1908            int rows = (Table.Rows.Count == 0 ? 1 : Table.Rows.Count) + (PrintHeaders ? 1 : 0);
1909            if (rows >= 0 && Table.Columns.Count>0)
1910      {
1911                var tbl = _worksheet.Tables.Add(new ExcelAddressBase(_fromRow, _fromCol, _fromRow + rows - 1, _fromCol + Table.Columns.Count-1), Table.TableName);
1912        tbl.ShowHeader = PrintHeaders;
1913        tbl.TableStyle = TableStyle;
1914      }
1915        return r;
1916    }
1917    /// <summary>
1918    /// Load the data from the datatable starting from the top left cell of the range
1919    /// </summary>
1920    /// <param name="Table">The datatable to load</param>
1921    /// <param name="PrintHeaders">Print the caption property (if set) or the columnname property if not, on first row</param>
1922    /// <returns>The filled range</returns>
1923    public ExcelRangeBase LoadFromDataTable(DataTable Table, bool PrintHeaders)
1924    {
1925      if (Table == null)
1926      {
1927        throw (new ArgumentNullException("Table can't be null"));
1928      }
1929
1930      int col = _fromCol, row = _fromRow;
1931      if (PrintHeaders)
1932      {
1933        foreach (DataColumn dc in Table.Columns)
1934        {
1935                    // If no caption is set, the ColumnName property is called implicitly.
1936          _worksheet._values.SetValue(row, col++, dc.Caption);
1937        }
1938        row++;
1939        col = _fromCol;
1940      }
1941      foreach (DataRow dr in Table.Rows)
1942      {
1943        foreach (object value in dr.ItemArray)
1944        {
1945                    if (value != null && value != DBNull.Value && !string.IsNullOrEmpty(value.ToString()))
1946                    {
1947                        _worksheet._values.SetValue(row, col++, value);
1948                    }
1949                    else
1950                    {
1951                        col++;
1952                    }
1953                }
1954        row++;
1955        col = _fromCol;
1956      }
1957            return _worksheet.Cells[_fromRow, _fromCol, (row == _fromRow ? _fromRow : row - 1), _fromCol + Table.Columns.Count - 1];
1958    }
1959    #endregion
1960    #region LoadFromArrays
1961    /// <summary>
1962    /// Loads data from the collection of arrays of objects into the range, starting from
1963    /// the top-left cell.
1964    /// </summary>
1965    /// <param name="Data">The data.</param>
1966    public ExcelRangeBase LoadFromArrays(IEnumerable<object[]> Data)
1967    {
1968      //thanx to Abdullin for the code contribution
1969      if (Data == null) throw new ArgumentNullException("data");
1970
1971      int column = _fromCol, row = _fromRow;
1972
1973      foreach (var rowData in Data)
1974      {
1975        column = _fromCol;
1976        foreach (var cellData in rowData)
1977        {
1978          _worksheet._values.SetValue(row, column, cellData);
1979          column += 1;
1980        }
1981        row += 1;
1982      }
1983      return _worksheet.Cells[_fromRow, _fromCol, row - 1, column - 1];
1984    }
1985    #endregion
1986    #region LoadFromCollection
1987    /// <summary>
1988    /// Load a collection into a the worksheet starting from the top left row of the range.
1989    /// </summary>
1990    /// <typeparam name="T">The datatype in the collection</typeparam>
1991    /// <param name="Collection">The collection to load</param>
1992    /// <returns>The filled range</returns>
1993    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection)
1994    {
1995      return LoadFromCollection<T>(Collection, false, TableStyles.None, BindingFlags.Public | BindingFlags.Instance, null);
1996    }
1997    /// <summary>
1998    /// Load a collection of T into the worksheet starting from the top left row of the range.
1999    /// Default option will load all public instance properties of T
2000    /// </summary>
2001    /// <typeparam name="T">The datatype in the collection</typeparam>
2002    /// <param name="Collection">The collection to load</param>
2003        /// <param name="PrintHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param>
2004    /// <returns>The filled range</returns>
2005    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders)
2006    {
2007      return LoadFromCollection<T>(Collection, PrintHeaders, TableStyles.None, BindingFlags.Public | BindingFlags.Instance, null);
2008    }
2009    /// <summary>
2010    /// Load a collection of T into the worksheet starting from the top left row of the range.
2011    /// Default option will load all public instance properties of T
2012    /// </summary>
2013    /// <typeparam name="T">The datatype in the collection</typeparam>
2014    /// <param name="Collection">The collection to load</param>
2015        /// <param name="PrintHeaders">Print the property names on the first row. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param>
2016    /// <param name="TableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param>
2017    /// <returns>The filled range</returns>
2018    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders, TableStyles TableStyle)
2019    {
2020      return LoadFromCollection<T>(Collection, PrintHeaders, TableStyle, BindingFlags.Public | BindingFlags.Instance, null);
2021    }
2022    /// <summary>
2023    /// Load a collection into the worksheet starting from the top left row of the range.
2024    /// </summary>
2025    /// <typeparam name="T">The datatype in the collection</typeparam>
2026    /// <param name="Collection">The collection to load</param>
2027    /// <param name="PrintHeaders">Print the property names on the first row. Any underscore in the property name will be converted to a space. If the property is decorated with a <see cref="DisplayNameAttribute"/> or a <see cref="DescriptionAttribute"/> that attribute will be used instead of the reflected member name.</param>
2028    /// <param name="TableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param>
2029    /// <param name="memberFlags">Property flags to use</param>
2030    /// <param name="Members">The properties to output. Must be of type T</param>
2031    /// <returns>The filled range</returns>
2032    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders, TableStyles TableStyle, BindingFlags memberFlags, MemberInfo[] Members)
2033    {
2034      var type = typeof(T);
2035      if (Members == null)
2036      {
2037        Members = type.GetProperties(memberFlags);
2038      }
2039      else
2040      {
2041        foreach (var t in Members)
2042        {
2043                    if (t.DeclaringType!=null && t.DeclaringType != type && !t.DeclaringType.IsSubclassOf(type))
2044          {
2045            throw new InvalidCastException("Supplied properties in parameter Properties must be of the same type as T (or an assignable type from T");
2046          }
2047        }
2048      }
2049
2050      int col = _fromCol, row = _fromRow;
2051      if (Members.Length > 0 && PrintHeaders)
2052      {
2053        foreach (var t in Members)
2054        {
2055                    var descriptionAttribute = t.GetCustomAttributes(typeof(DescriptionAttribute), false).FirstOrDefault() as DescriptionAttribute;
2056            var header = string.Empty;
2057                    if (descriptionAttribute != null)
2058                    {
2059                        header = descriptionAttribute.Description;
2060                    }
2061                    else
2062                    {
2063                        var displayNameAttribute =
2064                            t.GetCustomAttributes(typeof (DisplayNameAttribute), false).FirstOrDefault() as
2065                            DisplayNameAttribute;
2066                        if (displayNameAttribute != null)
2067                        {
2068                            header = displayNameAttribute.DisplayName;
2069                        }
2070                        else
2071                        {
2072                            header = t.Name.Replace('_', ' ');
2073                        }
2074                    }
2075                    _worksheet._values.SetValue(row, col++, header);
2076        }
2077        row++;
2078      }
2079
2080      if (Members.Length == 0)
2081      {
2082        foreach (var item in Collection)
2083        {
2084          _worksheet.Cells[row++, col].Value = item;
2085        }
2086      }
2087      else
2088      {
2089        foreach (var item in Collection)
2090        {
2091          col = _fromCol;
2092                    if (item is string || item is decimal || item is DateTime || item.GetType().IsPrimitive)
2093                    {
2094                        _worksheet.Cells[row, col++].Value = item;
2095                    }
2096                    else
2097                    {
2098                        foreach (var t in Members)
2099                        {
2100                            if (t is PropertyInfo)
2101                            {
2102                                _worksheet.Cells[row, col++].Value = ((PropertyInfo)t).GetValue(item, null);
2103                            }
2104                            else if (t is FieldInfo)
2105                            {
2106                                _worksheet.Cells[row, col++].Value = ((FieldInfo)t).GetValue(item);
2107                            }
2108                            else if (t is MethodInfo)
2109                            {
2110                                _worksheet.Cells[row, col++].Value = ((MethodInfo)t).Invoke(item, null);
2111                            }
2112                        }
2113                    }
2114          row++;
2115        }
2116      }
2117
2118            if (_fromRow == row-1 && PrintHeaders)
2119            {
2120                row++;
2121            }
2122
2123            var r = _worksheet.Cells[_fromRow, _fromCol, row - 1, Members.Length==0 ? col : col - 1];
2124
2125      if (TableStyle != TableStyles.None)
2126      {
2127        var tbl = _worksheet.Tables.Add(r, "");
2128        tbl.ShowHeader = PrintHeaders;
2129        tbl.TableStyle = TableStyle;
2130      }
2131      return r;
2132    }
2133    #endregion
2134    #region LoadFromText
2135    /// <summary>
2136    /// Loads a CSV text into a range starting from the top left cell.
2137    /// Default settings is Comma separation
2138    /// </summary>
2139    /// <param name="Text">The Text</param>
2140    /// <returns>The range containing the data</returns>
2141    public ExcelRangeBase LoadFromText(string Text)
2142    {
2143      return LoadFromText(Text, new ExcelTextFormat());
2144    }
2145    /// <summary>
2146    /// Loads a CSV text into a range starting from the top left cell.
2147    /// </summary>
2148    /// <param name="Text">The Text</param>
2149    /// <param name="Format">Information how to load the text</param>
2150    /// <returns>The range containing the data</returns>
2151    public ExcelRangeBase LoadFromText(string Text, ExcelTextFormat Format)
2152    {
2153            if (string.IsNullOrEmpty(Text))
2154            {
2155                var r = _worksheet.Cells[_fromRow, _fromCol];
2156                r.Value = "";
2157                return r;
2158            }
2159           
2160            if (Format == null) Format = new ExcelTextFormat();
2161
2162            string[] lines = Regex.Split(Text, Format.EOL);
2163      int row = _fromRow;
2164      int col = _fromCol;
2165      int maxCol = col;
2166      int lineNo = 1;
2167      foreach (string line in lines)
2168      {
2169        if (lineNo > Format.SkipLinesBeginning && lineNo <= lines.Length - Format.SkipLinesEnd)
2170        {
2171          col = _fromCol;
2172          string v = "";
2173          bool isText = false, isQualifier = false;
2174          int QCount = 0;
2175          foreach (char c in line)
2176          {
2177            if (Format.TextQualifier != 0 && c == Format.TextQualifier)
2178            {
2179              if (!isText && v != "")
2180              {
2181                throw (new Exception(string.Format("Invalid Text Qualifier in line : {0}", line)));
2182              }
2183              isQualifier = !isQualifier;
2184              QCount += 1;
2185              isText = true;
2186            }
2187            else
2188            {
2189                            if (QCount > 1 && !string.IsNullOrEmpty(v))
2190              {
2191                v += new string(Format.TextQualifier, QCount / 2);
2192              }
2193                            else if(QCount>2 && string.IsNullOrEmpty(v))
2194                            {
2195                                v += new string(Format.TextQualifier, (QCount-1) / 2);
2196                            }
2197
2198              if (isQualifier)
2199              {
2200                v += c;
2201              }
2202              else
2203              {
2204                if (c == Format.Delimiter)
2205                {
2206                    _worksheet.SetValue(row, col, ConvertData(Format, v, col - _fromCol, isText));
2207                  v = "";
2208                  isText = false;
2209                  col++;
2210                }
2211                else
2212                {
2213                  if (QCount % 2 == 1)
2214                  {
2215                    throw (new Exception(string.Format("Text delimiter is not closed in line : {0}", line)));
2216                  }
2217                  v += c;
2218                }
2219              }
2220              QCount = 0;
2221            }
2222          }
2223          if (QCount > 1)
2224          {
2225            v += new string(Format.TextQualifier, QCount / 2);
2226          }
2227
2228            _worksheet._values.SetValue(row, col, ConvertData(Format, v, col - _fromCol, isText));
2229          if (col > maxCol) maxCol = col;
2230          row++;
2231        }
2232        lineNo++;
2233      }
2234      return _worksheet.Cells[_fromRow, _fromCol, row - 1, maxCol];
2235    }
2236    /// <summary>
2237    /// Loads a CSV text into a range starting from the top left cell.
2238    /// </summary>
2239    /// <param name="Text">The Text</param>
2240    /// <param name="Format">Information how to load the text</param>
2241    /// <param name="TableStyle">Create a table with this style</param>
2242    /// <param name="FirstRowIsHeader">Use the first row as header</param>
2243    /// <returns></returns>
2244    public ExcelRangeBase LoadFromText(string Text, ExcelTextFormat Format, TableStyles TableStyle, bool FirstRowIsHeader)
2245    {
2246      var r = LoadFromText(Text, Format);
2247
2248      var tbl = _worksheet.Tables.Add(r, "");
2249      tbl.ShowHeader = FirstRowIsHeader;
2250      tbl.TableStyle = TableStyle;
2251
2252      return r;
2253    }
2254    /// <summary>
2255    /// Loads a CSV file into a range starting from the top left cell.
2256    /// </summary>
2257    /// <param name="TextFile">The Textfile</param>
2258    /// <returns></returns>
2259    public ExcelRangeBase LoadFromText(FileInfo TextFile)
2260    {
2261      return LoadFromText(File.ReadAllText(TextFile.FullName, Encoding.ASCII));
2262    }
2263    /// <summary>
2264    /// Loads a CSV file into a range starting from the top left cell.
2265    /// </summary>
2266    /// <param name="TextFile">The Textfile</param>
2267    /// <param name="Format">Information how to load the text</param>
2268    /// <returns></returns>
2269    public ExcelRangeBase LoadFromText(FileInfo TextFile, ExcelTextFormat Format)
2270    {
2271      return LoadFromText(File.ReadAllText(TextFile.FullName, Format.Encoding), Format);
2272    }
2273    /// <summary>
2274    /// Loads a CSV file into a range starting from the top left cell.
2275    /// </summary>
2276    /// <param name="TextFile">The Textfile</param>
2277    /// <param name="Format">Information how to load the text</param>
2278    /// <param name="TableStyle">Create a table with this style</param>
2279    /// <param name="FirstRowIsHeader">Use the first row as header</param>
2280    /// <returns></returns>
2281    public ExcelRangeBase LoadFromText(FileInfo TextFile, ExcelTextFormat Format, TableStyles TableStyle, bool FirstRowIsHeader)
2282    {
2283      return LoadFromText(File.ReadAllText(TextFile.FullName, Format.Encoding), Format, TableStyle, FirstRowIsHeader);
2284    }
2285    #endregion
2286    #region GetValue
2287    /// <summary>
2288    /// Get the strongly typed value of the cell.
2289    /// </summary>
2290    /// <typeparam name="T">The type</typeparam>
2291    /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns>
2292    public T GetValue<T>()
2293    {
2294      return _worksheet.GetTypedValue<T>(Value);
2295    }
2296    #endregion
2297    /// <summary>
2298    /// Get a range with an offset from the top left cell.
2299    /// The new range has the same dimensions as the current range
2300    /// </summary>
2301    /// <param name="RowOffset">Row Offset</param>
2302    /// <param name="ColumnOffset">Column Offset</param>
2303    /// <returns></returns>
2304    public ExcelRangeBase Offset(int RowOffset, int ColumnOffset)
2305    {
2306      if (_fromRow + RowOffset < 1 || _fromCol + ColumnOffset < 1 || _fromRow + RowOffset > ExcelPackage.MaxRows || _fromCol + ColumnOffset > ExcelPackage.MaxColumns)
2307      {
2308        throw (new ArgumentOutOfRangeException("Offset value out of range"));
2309      }
2310      string address = GetAddress(_fromRow + RowOffset, _fromCol + ColumnOffset, _toRow + RowOffset, _toCol + ColumnOffset);
2311      return new ExcelRangeBase(_worksheet, address);
2312    }
2313    /// <summary>
2314    /// Get a range with an offset from the top left cell.
2315    /// </summary>
2316    /// <param name="RowOffset">Row Offset</param>
2317    /// <param name="ColumnOffset">Column Offset</param>
2318    /// <param name="NumberOfRows">Number of rows. Minimum 1</param>
2319    /// <param name="NumberOfColumns">Number of colums. Minimum 1</param>
2320    /// <returns></returns>
2321    public ExcelRangeBase Offset(int RowOffset, int ColumnOffset, int NumberOfRows, int NumberOfColumns)
2322    {
2323      if (NumberOfRows < 1 || NumberOfColumns < 1)
2324      {
2325        throw (new Exception("Number of rows/columns must be greater than 0"));
2326      }
2327      NumberOfRows--;
2328      NumberOfColumns--;
2329      if (_fromRow + RowOffset < 1 || _fromCol + ColumnOffset < 1 || _fromRow + RowOffset > ExcelPackage.MaxRows || _fromCol + ColumnOffset > ExcelPackage.MaxColumns ||
2330         _fromRow + RowOffset + NumberOfRows < 1 || _fromCol + ColumnOffset + NumberOfColumns < 1 || _fromRow + RowOffset + NumberOfRows > ExcelPackage.MaxRows || _fromCol + ColumnOffset + NumberOfColumns > ExcelPackage.MaxColumns)
2331      {
2332        throw (new ArgumentOutOfRangeException("Offset value out of range"));
2333      }
2334      string address = GetAddress(_fromRow + RowOffset, _fromCol + ColumnOffset, _fromRow + RowOffset + NumberOfRows, _fromCol + ColumnOffset + NumberOfColumns);
2335      return new ExcelRangeBase(_worksheet, address);
2336    }
2337    /// <summary>
2338    /// Adds a new comment for the range.
2339    /// If this range contains more than one cell, the top left comment is returned by the method.
2340    /// </summary>
2341    /// <param name="Text"></param>
2342    /// <param name="Author"></param>
2343    /// <returns>A reference comment of the top left cell</returns>
2344    public ExcelComment AddComment(string Text, string Author)
2345    {
2346      //Check if any comments exists in the range and throw an exception
2347      _changePropMethod(Exists_Comment, null);
2348      //Create the comments
2349      _changePropMethod(Set_Comment, new string[] { Text, Author });
2350
2351      return _worksheet.Comments[new ExcelCellAddress(_fromRow, _fromCol)];
2352    }
2353
2354        ///// <summary>
2355        ///// Copies the range of cells to an other range
2356        ///// </summary>
2357        ///// <param name="Destination">The start cell where the range will be copied.</param>
2358        public void Copy(ExcelRangeBase Destination)
2359        {
2360            bool sameWorkbook = Destination._worksheet.Workbook == _worksheet.Workbook;
2361            ExcelStyles sourceStyles = _worksheet.Workbook.Styles,
2362                        styles = Destination._worksheet.Workbook.Styles;
2363            Dictionary<int, int> styleCashe = new Dictionary<int, int>();
2364
2365            //Delete all existing cells;
2366            int toRow = _toRow - _fromRow + 1,
2367                toCol = _toCol - _fromCol + 1;
2368
2369            string s = "";
2370            int i=0;
2371            object o = null;
2372            byte flag=0;
2373            Uri hl = null;
2374            ExcelComment comment=null;
2375
2376            var cse = new CellsStoreEnumerator<object>(_worksheet._values, _fromRow, _fromCol, _toRow, _toCol);
2377            var copiedValue = new List<CopiedCell>();
2378            while (cse.Next())
2379            {
2380                var row=cse.Row;
2381                var col = cse.Column;       //Issue 15070
2382                var cell = new CopiedCell
2383                {
2384                    Row = Destination._fromRow + (row - _fromRow),
2385                    Column = Destination._fromCol + (col - _fromCol),
2386                    Value=cse.Value
2387                };
2388
2389                //Destination._worksheet._values.SetValue(row, col, cse.Value);
2390
2391                if (_worksheet._types.Exists(row, col, ref s))
2392                {
2393                    //Destination._worksheet._types.SetValue(row, col,s);
2394                    cell.Type=s;
2395                }
2396
2397                if (_worksheet._formulas.Exists(row, col, ref o))
2398                {
2399                    if (o is int)
2400                    {
2401                       // Destination._worksheet._formulas.SetValue(row, col, _worksheet.GetFormula(cse.Row, cse.Column));    //Shared formulas, set the formula per cell to simplify
2402                        cell.Formula=_worksheet.GetFormula(cse.Row, cse.Column);
2403                    }
2404                    else
2405                    {
2406                        //Destination._worksheet._formulas.SetValue(row, col, o);
2407                        cell.Formula=o;
2408                    }
2409                }
2410                if(_worksheet._styles.Exists(row, col, ref i))
2411                {
2412                    if (sameWorkbook)
2413                    {
2414                        //Destination._worksheet._styles.SetValue(row, col, i);
2415                        cell.StyleID=i;
2416                    }
2417                    else
2418                    {
2419                        if (styleCashe.ContainsKey(i))
2420                        {
2421                            i = styleCashe[i];
2422                        }
2423                        else
2424                        {
2425                            var oldStyleID = i;
2426                            i = styles.CloneStyle(sourceStyles, i);
2427                            styleCashe.Add(oldStyleID, i);
2428                        }
2429                        //Destination._worksheet._styles.SetValue(row, col, i);
2430                        cell.StyleID=i;
2431                    }
2432                }
2433               
2434                if (_worksheet._hyperLinks.Exists(row, col, ref hl))
2435                {
2436                    //Destination._worksheet._hyperLinks.SetValue(row, col, hl);
2437                    cell.HyperLink=hl;
2438                }
2439
2440                if(_worksheet._commentsStore.Exists(row, col, ref comment))
2441                {
2442                    cell.Comment=comment;
2443                }
2444
2445                if (_worksheet._flags.Exists(row, col, ref flag))
2446                {
2447                    cell.Flag = flag;
2448                }
2449                copiedValue.Add(cell);
2450            }
2451
2452            //Copy styles with no cell value
2453            var cses = new CellsStoreEnumerator<int>(_worksheet._styles, _fromRow, _fromCol, _toRow, _toCol);
2454            while (cses.Next())
2455            {
2456                if (!_worksheet._values.Exists(cses.Row, cses.Column))
2457                {
2458                    var row = Destination._fromRow + (cses.Row - _fromRow);
2459                    var col = Destination._fromCol + (cses.Column - _fromCol);
2460                    var cell = new CopiedCell
2461                    {
2462                        Row = row,
2463                        Column = col,
2464                        Value = null
2465                    };
2466
2467                    i = cses.Value;
2468                    if (sameWorkbook)
2469                    {
2470                        cell.StyleID = i;
2471                    }
2472                    else
2473                    {
2474                        if (styleCashe.ContainsKey(i))
2475                        {
2476                            i = styleCashe[i];
2477                        }
2478                        else
2479                        {
2480                            var oldStyleID = i;
2481                            i = styles.CloneStyle(sourceStyles, i);
2482                            styleCashe.Add(oldStyleID, i);
2483                        }
2484                        //Destination._worksheet._styles.SetValue(row, col, i);
2485                        cell.StyleID = i;
2486                    }
2487                    copiedValue.Add(cell);
2488                }
2489            }
2490            var copiedMergedCells = new Dictionary<int, ExcelAddress>();
2491            //Merged cells
2492            var csem = new CellsStoreEnumerator<int>(_worksheet.MergedCells._cells, _fromRow, _fromCol, _toRow, _toCol);
2493            while (csem.Next())
2494            {
2495                if(!copiedMergedCells.ContainsKey(csem.Value))
2496                {
2497                    var adr = new ExcelAddress(_worksheet.Name, _worksheet.MergedCells.List[csem.Value]);
2498                    if(this.Collide(adr)==eAddressCollition.Inside)
2499                    {                       
2500                        copiedMergedCells.Add(csem.Value, new ExcelAddress(
2501                            Destination._fromRow + (adr.Start.Row - _fromRow),
2502                            Destination._fromCol + (adr.Start.Column - _fromCol),
2503                            Destination._toRow + (adr.End.Row - _fromRow),
2504                            Destination._toCol + (adr.End.Column - _fromCol)));
2505                    }
2506                    else
2507                    {
2508                        //Partial merge of the address ignore.
2509                        copiedMergedCells.Add(csem.Value, null);
2510                    }
2511                }
2512            }
2513
2514            Destination._worksheet.MergedCells.Delete(new ExcelAddressBase(Destination._fromRow, Destination._fromCol, Destination._fromRow+toRow, Destination._fromCol+toCol));
2515
2516            Destination._worksheet._values.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
2517            Destination._worksheet._formulas.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
2518            Destination._worksheet._styles.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
2519            Destination._worksheet._types.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
2520            Destination._worksheet._hyperLinks.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
2521            Destination._worksheet._flags.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
2522            Destination._worksheet._commentsStore.Clear(Destination._fromRow, Destination._fromCol, toRow, toCol);
2523           
2524            foreach(var cell in copiedValue)
2525            {
2526                Destination._worksheet._values.SetValue(cell.Row, cell.Column, cell.Value);
2527
2528                if(cell.Type!=null)
2529                {
2530                    Destination._worksheet._types.SetValue(cell.Row, cell.Column, cell.Type);
2531                }
2532
2533                if(cell.StyleID!=null)
2534                {
2535                    Destination._worksheet._styles.SetValue(cell.Row, cell.Column, cell.StyleID.Value);
2536                }
2537
2538                if(cell.Formula!=null)
2539                {
2540                    cell.Formula = UpdateFormulaReferences(cell.Formula.ToString(), Destination._fromRow - _fromRow, Destination._fromCol - _fromCol, 0, 0, true);
2541                    Destination._worksheet._formulas.SetValue(cell.Row, cell.Column, cell.Formula);
2542                }
2543                if(cell.HyperLink!=null)
2544                {
2545                    Destination._worksheet._hyperLinks.SetValue(cell.Row, cell.Column, cell.HyperLink);
2546                }
2547
2548                if (cell.Comment != null)
2549                {
2550                    //Destination._worksheet._commentsStore.SetValue(cell.Row, cell.Column, cell.Comment);
2551                }
2552            }
2553
2554            //Add merged cells
2555            foreach(var m in copiedMergedCells.Values)
2556            {
2557                if(m!=null)
2558                {
2559                    Destination._worksheet.MergedCells.Add(m, true);
2560                }
2561            }
2562
2563
2564            //Clone the cell
2565                //var copiedCell = (_worksheet._cells[GetCellID(_worksheet.SheetID, cell._fromRow, cell.column)] as ExcelCell);
2566
2567                //var newCell = copiedCell.Clone(Destination._worksheet,
2568                //        Destination._fromRow + (copiedCell.Row - _fromRow),
2569                //        Destination.column + (copiedCell.Column - column));
2570
2571        //        newCell.MergeId = _worksheet.GetMergeCellId(copiedCell.Row, copiedCell.Column);
2572
2573
2574        //        if (!string.IsNullOrEmpty(newCell.Formula))
2575        //        {
2576        //            newCell.Formula = ExcelCell.UpdateFormulaReferences(newCell.Formula, newCell.Row - copiedCell.Row, (newCell.Column - copiedCell.Column), 1, 1);
2577        //        }
2578
2579        //        //If its not the same workbook we must copy the styles to the new workbook.
2580        //        if (!sameWorkbook)
2581        //        {
2582        //            if (styleCashe.ContainsKey(cell.StyleID))
2583        //            {
2584        //                newCell.StyleID = styleCashe[cell.StyleID];
2585        //            }
2586        //            else
2587        //            {
2588        //                newCell.StyleID = styles.CloneStyle(sourceStyles, cell.StyleID);
2589        //                styleCashe.Add(cell.StyleID, newCell.StyleID);
2590        //            }
2591        //        }
2592        //        newCells.Add(newCell);
2593        //        if (newCell.Merge) mergedCells.Add(newCell.CellID, newCell);
2594        //    }
2595
2596        //    //Now clear the destination.
2597        //    Destination.Offset(0, 0, (_toRow - _fromRow) + 1, (_toCol - column) + 1).Clear();
2598
2599        //    //And last add the new cells to the worksheet
2600        //    foreach (var cell in newCells)
2601        //    {
2602        //        Destination.Worksheet._cells.Add(cell);
2603        //    }
2604        //    //Add merged cells
2605        //    if (mergedCells.Count > 0)
2606        //    {
2607        //        List<ExcelAddressBase> mergedAddresses = new List<ExcelAddressBase>();
2608        //        foreach (var cell in mergedCells.Values)
2609        //        {
2610        //            if (!IsAdded(cell, mergedAddresses))
2611        //            {
2612        //                int startRow = cell.Row, startCol = cell.Column, endRow = cell.Row, endCol = cell.Column + 1;
2613        //                while (mergedCells.ContainsKey(ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)))
2614        //                {
2615        //                    ExcelCell next = mergedCells[ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)];
2616        //                    if (cell.MergeId != next.MergeId)
2617        //                    {
2618        //                        break;
2619        //                    }
2620        //                    endCol++;
2621        //                }
2622
2623        //                while (IsMerged(mergedCells, Destination.Worksheet, endRow, startCol, endCol - 1, cell))
2624        //                {
2625        //                    endRow++;
2626        //                }
2627
2628        //                mergedAddresses.Add(new ExcelAddressBase(startRow, startCol, endRow - 1, endCol - 1));
2629        //            }
2630        //        }
2631        //        Destination.Worksheet.MergedCells.List.AddRange((from r in mergedAddresses select r.Address));
2632        //    }
2633        //}
2634
2635        //private bool IsAdded(ExcelCell cell, List<ExcelAddressBase> mergedAddresses)
2636        //{
2637        //    foreach (var address in mergedAddresses)
2638        //    {
2639        //        if (address.Collide(new ExcelAddressBase(cell.CellAddress)) == eAddressCollition.Inside)
2640        //        {
2641        //            return true;
2642        //        }
2643        //    }
2644        //    return false;
2645        //}
2646
2647        //private bool IsMerged(Dictionary<ulong, ExcelCell> mergedCells, ExcelWorksheet worksheet, int row, int startCol, int endCol, ExcelCell cell)
2648        //{
2649        //    for (int col = startCol; col <= endCol; col++)
2650        //    {
2651        //        if (!mergedCells.ContainsKey(ExcelCell.GetCellID(worksheet.SheetID, row, col)))
2652        //        {
2653        //            return false;
2654        //        }
2655        //        else
2656        //        {
2657        //            ExcelCell next = mergedCells[ExcelCell.GetCellID(worksheet.SheetID, row, col)];
2658        //            if (cell.MergeId != next.MergeId)
2659        //            {
2660        //                return false;
2661        //            }
2662        //        }
2663        //    }
2664        //    return true;
2665        }
2666
2667    /// <summary>
2668    /// Clear all cells
2669    /// </summary>
2670    public void Clear()
2671    {
2672      Delete(this, false);
2673    }
2674    /// <summary>
2675    /// Creates an array-formula.
2676    /// </summary>
2677    /// <param name="ArrayFormula">The formula</param>
2678    public void CreateArrayFormula(string ArrayFormula)
2679    {
2680      if (Addresses != null)
2681      {
2682        throw (new Exception("An Arrayformula can not have more than one address"));
2683      }
2684      Set_SharedFormula(ArrayFormula, this, true);
2685    }
2686        //private void Delete(ExcelAddressBase Range)
2687        //{
2688        //    Delete(Range, true);
2689        //}
2690        internal void Delete(ExcelAddressBase Range, bool shift)
2691    {
2692            //DeleteCheckMergedCells(Range);
2693            _worksheet.MergedCells.Delete(Range);
2694      //First find the start cell
2695            var rows=Range._toRow-Range._fromRow+1;
2696            var cols=Range._toCol - Range._fromCol+1;
2697           
2698            _worksheet._values.Delete(Range._fromRow, Range._fromCol, rows, cols, shift);
2699            _worksheet._types.Delete(Range._fromRow, Range._fromCol, rows, cols, shift);
2700            _worksheet._styles.Delete(Range._fromRow, Range._fromCol, rows, cols, shift);
2701            _worksheet._formulas.Delete(Range._fromRow, Range._fromCol, rows, cols, shift);
2702            _worksheet._hyperLinks.Delete(Range._fromRow, Range._fromCol, rows, cols, shift);
2703            _worksheet._flags.Delete(Range._fromRow, Range._fromCol, rows, cols, shift);
2704            _worksheet._commentsStore.Delete(Range._fromRow, Range._fromCol, rows, cols, shift);
2705
2706            //if(shift)
2707            //{
2708            //    _worksheet.AdjustFormulasRow(Range._fromRow, rows);
2709            //}
2710
2711      //Delete multi addresses as well
2712      if (Addresses != null)
2713      {
2714        foreach (var sub in Addresses)
2715        {
2716          Delete(sub, shift);
2717        }
2718            }
2719        }
2720
2721        private void DeleteCheckMergedCells(ExcelAddressBase Range)
2722        {
2723            var removeItems = new List<string>();
2724            foreach (var addr in Worksheet.MergedCells)
2725            {
2726                var addrCol = Range.Collide(new ExcelAddress(Range.WorkSheet, addr));
2727                if (addrCol != eAddressCollition.No)
2728                {
2729                    if (addrCol == eAddressCollition.Inside)
2730                    {
2731                        removeItems.Add(addr);
2732                    }
2733                    else
2734                    {
2735                        throw (new InvalidOperationException("Can't remove/overwrite a part of cells that are merged"));
2736                    }
2737                }
2738            }
2739            foreach (var item in removeItems)
2740            {
2741                Worksheet.MergedCells.Remove(item);
2742      }
2743    }
2744    #endregion
2745    #region IDisposable Members
2746
2747    public void Dispose()
2748    {
2749      //_worksheet = null;           
2750    }
2751
2752    #endregion
2753    #region "Enumerator"
2754        //int _index;
2755        //ulong _toCellId;
2756        //int _enumAddressIx;
2757        CellsStoreEnumerator<object> cellEnum;
2758    public IEnumerator<ExcelRangeBase> GetEnumerator()
2759    {
2760            return new ExcelRangeBaseEnumerator(this);
2761    }
2762
2763    IEnumerator IEnumerable.GetEnumerator()
2764    {
2765            return new ExcelRangeBaseEnumerator(this);
2766    }
2767
2768    /// <summary>
2769    /// The current range when enumerating
2770    /// </summary>
2771        public class ExcelRangeBaseEnumerator : IEnumerator<ExcelRangeBase> {
2772            private CellsStoreEnumerator<object> _cellEnum;
2773            private int _enumAddressIx = -1;
2774            private ExcelRangeBase _range;
2775            private ExcelRangeBase _current;
2776
2777            /// <summary>
2778            /// The current range when enumerating
2779            /// </summary>
2780            public ExcelRangeBase Current {
2781                get {
2782                    return _current;
2783                }
2784            }
2785
2786            /// <summary>
2787            /// The current range when enumerating
2788            /// </summary>
2789            object IEnumerator.Current {
2790                get {
2791                    return _current;
2792                }
2793            }
2794
2795            public ExcelRangeBaseEnumerator(ExcelRangeBase range) {
2796                this._range = range;
2797                Reset();
2798            }
2799            public bool MoveNext() {
2800                if (_cellEnum.Next()) {
2801                    _current._fromCol = _cellEnum.Column;
2802                    _current._fromRow = _cellEnum.Row;
2803                    _current._toCol = _cellEnum.Column;
2804                    _current._toRow = _cellEnum.Row;
2805                    _current.Address = GetAddress(_current._fromRow, _current._fromCol);
2806                    return true;
2807                }
2808                else if (_range._addresses != null) {
2809                    _enumAddressIx++;
2810                    if (_enumAddressIx < _range._addresses.Count) {
2811                        _cellEnum = new CellsStoreEnumerator<object>(_range._worksheet._values,
2812                            _range._addresses[_enumAddressIx]._fromRow,
2813                            _range._addresses[_enumAddressIx]._fromCol,
2814                            _range._addresses[_enumAddressIx]._toRow,
2815                            _range._addresses[_enumAddressIx]._toCol);
2816                        return MoveNext();
2817                    }
2818                    else {
2819                        return false;
2820                    }
2821                }
2822                return false;
2823            }
2824
2825            public void Reset() {
2826                _enumAddressIx = -1;
2827                _cellEnum = new CellsStoreEnumerator<object>(_range._worksheet._values, _range._fromRow, _range._fromCol, _range._toRow, _range._toCol);
2828                _current = new ExcelRangeBase(_range._worksheet, ExcelAddressBase.GetAddress(_cellEnum.Row, _cellEnum.Column));
2829            }
2830
2831            public void Dispose() {
2832                if (_cellEnum != null) {
2833                    _cellEnum.Dispose();
2834                    _cellEnum = null;
2835                }
2836            }
2837
2838        }
2839
2840        //private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
2841        //{
2842        //    if (_index >= _worksheet._cells.Count) return;
2843        //    ExcelCell cell = _worksheet._cells[_index] as ExcelCell;
2844        //    while (cell.Column > toCol || cell.Column < fromCol)
2845        //    {
2846        //        if (cell.Column < fromCol)
2847        //        {
2848        //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol));
2849        //        }
2850        //        else
2851        //        {
2852        //            _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol));
2853        //        }
2854
2855        //        if (_index < 0)
2856        //        {
2857        //            _index = ~_index;
2858        //        }
2859        //        if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId)
2860        //        {
2861        //            break;
2862        //        }
2863        //        cell = _worksheet._cells[_index] as ExcelCell;
2864        //    }
2865        //}
2866
2867        //private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
2868        //{
2869        //    _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol));
2870        //    _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol);
2871        //    if (_index < 0)
2872        //    {
2873        //        _index = ~_index;
2874        //    }
2875        //    _index--;
2876        //}
2877    #endregion
2878    }
2879}
Note: See TracBrowser for help on using the repository browser.