Free cookie consent management tool by TermsFeed Policy Generator

source: branches/gteufl/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/3.1.3/EPPlus-3.1.3/ExcelRangeBase.cs @ 12858

Last change on this file since 12858 was 9580, checked in by sforsten, 12 years ago

#1730:

  • added SymbolicDataAnalysisExpressionExcelFormatter
  • changed modifiers in SymbolicExpressionTreeChart of methods SaveImageAsBitmap and SaveImageAsEmf to public
  • added menu item ExportSymbolicSolutionToExcelMenuItem to export a symbolic solution to an excel file
  • added EPPlus-3.1.3 to ExtLibs
File size: 71.1 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.Text;
36using System.Data;
37using OfficeOpenXml.Style;
38using System.Xml;
39using System.Drawing;
40using System.Globalization;
41using System.Collections;
42using OfficeOpenXml.Table;
43using System.Text.RegularExpressions;
44using System.IO;
45using System.Linq;
46using OfficeOpenXml.DataValidation;
47using OfficeOpenXml.DataValidation.Contracts;
48using System.Reflection;
49using OfficeOpenXml.Style.XmlAccess;
50using System.Security;
51using OfficeOpenXml.ConditionalFormatting;
52using OfficeOpenXml.ConditionalFormatting.Contracts;
53
54namespace OfficeOpenXml
55{
56  /// <summary>
57  /// A range of cells
58  /// </summary>
59  public class ExcelRangeBase : ExcelAddress, IExcelCell, IDisposable, IEnumerable<ExcelRangeBase>, IEnumerator<ExcelRangeBase>
60  {
61    /// <summary>
62    /// Reference to the worksheet
63    /// </summary>
64    protected ExcelWorksheet _worksheet;
65    private ExcelWorkbook _workbook = null;
66    private delegate void _changeProp(_setValue method, object value);
67    private delegate void _setValue(object value, int row, int col);
68    private _changeProp _changePropMethod;
69    private int _styleID;
70    #region Constructors
71    internal ExcelRangeBase(ExcelWorksheet xlWorksheet)
72    {
73      _worksheet = xlWorksheet;
74      _ws = _worksheet.Name;
75            this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange);
76      SetDelegate();
77    }
78
79        void ExcelRangeBase_AddressChange(object sender, EventArgs e)
80        {
81            SetDelegate();
82        }
83    internal ExcelRangeBase(ExcelWorksheet xlWorksheet, string address) :
84      base(xlWorksheet == null ? "" : xlWorksheet.Name, address)
85    {
86      _worksheet = xlWorksheet;
87      if (string.IsNullOrEmpty(_ws)) _ws = _worksheet == null ? "" : _worksheet.Name;
88            this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange);
89            SetDelegate();
90    }
91    internal ExcelRangeBase(ExcelWorkbook wb, ExcelWorksheet xlWorksheet, string address, bool isName) :
92      base(xlWorksheet == null ? "" : xlWorksheet.Name, address, isName)
93    {
94      _worksheet = xlWorksheet;
95      _workbook = wb;
96      if (string.IsNullOrEmpty(_ws)) _ws = (xlWorksheet == null ? null : xlWorksheet.Name);
97            this.AddressChange += new EventHandler(ExcelRangeBase_AddressChange);
98            SetDelegate();
99    }
100        ~ExcelRangeBase()
101        {
102            this.AddressChange -= new EventHandler(ExcelRangeBase_AddressChange);
103        }
104    #endregion
105    #region Set Value Delegates   
106        private void SetDelegate()
107    {
108      if (_fromRow == -1)
109      {
110        _changePropMethod = SetUnknown;
111      }
112      //Single cell
113      else if (_fromRow == _toRow && _fromCol == _toCol && Addresses == null)
114      {
115        _changePropMethod = SetSingle;
116      }
117      //Range (ex A1:A2)
118      else if (Addresses == null)
119      {
120        _changePropMethod = SetRange;
121      }
122      //Multi Range (ex A1:A2,C1:C2)
123      else
124      {
125        _changePropMethod = SetMultiRange;
126      }
127    }
128        /// <summary>
129    /// We dont know the address yet. Set the delegate first time a property is set.
130    /// </summary>
131    /// <param name="valueMethod"></param>
132    /// <param name="value"></param>
133    private void SetUnknown(_setValue valueMethod, object value)
134    {
135      //Address is not set use, selected range
136      if (_fromRow == -1)
137      {
138        SetToSelectedRange();
139      }
140      SetDelegate();
141      _changePropMethod(valueMethod, value);
142    }
143    /// <summary>
144    /// Set a single cell
145    /// </summary>
146    /// <param name="valueMethod"></param>
147    /// <param name="value"></param>
148    private void SetSingle(_setValue valueMethod, object value)
149    {
150      valueMethod(value, _fromRow, _fromCol);
151    }
152    /// <summary>
153    /// Set a range
154    /// </summary>
155    /// <param name="valueMethod"></param>
156    /// <param name="value"></param>
157    private void SetRange(_setValue valueMethod, object value)
158    {
159      SetValueAddress(this, valueMethod, value);
160    }
161    /// <summary>
162    /// Set a multirange (A1:A2,C1:C2)
163    /// </summary>
164    /// <param name="valueMethod"></param>
165    /// <param name="value"></param>
166    private void SetMultiRange(_setValue valueMethod, object value)
167    {
168      SetValueAddress(this, valueMethod, value);
169      foreach (var address in Addresses)
170      {
171        SetValueAddress(address, valueMethod, value);
172      }
173    }
174    /// <summary>
175    /// Set the property for an address
176    /// </summary>
177    /// <param name="address"></param>
178    /// <param name="valueMethod"></param>
179    /// <param name="value"></param>
180    private void SetValueAddress(ExcelAddress address, _setValue valueMethod, object value)
181    {
182      IsRangeValid("");
183      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
184      {
185        throw (new ArgumentException("Can't reference all cells. Please use the indexer to set the range"));
186      }
187      else
188      {
189        for (int col = address.Start.Column; col <= address.End.Column; col++)
190        {
191          for (int row = address.Start.Row; row <= address.End.Row; row++)
192          {
193            valueMethod(value, row, col);
194          }
195        }
196      }
197    }
198    #endregion
199    #region Set property methods
200    private void Set_StyleID(object value, int row, int col)
201    {
202      _worksheet.Cell(row, col).StyleID = (int)value;
203    }
204    private void Set_StyleName(object value, int row, int col)
205    {
206      _worksheet.Cell(row, col).SetNewStyleName(value.ToString(), _styleID);
207    }
208    private void Set_Value(object value, int row, int col)
209    {
210      ExcelCell c = _worksheet.Cell(row, col);
211      if (c._sharedFormulaID > 0) SplitFormulas();
212      _worksheet.Cell(row, col).Value = value;
213    }
214    private void Set_Formula(object value, int row, int col)
215    {
216      ExcelCell c = _worksheet.Cell(row, col);
217      if (c._sharedFormulaID > 0) SplitFormulas();
218
219      string formula = (value == null ? string.Empty : value.ToString());
220      if (formula == string.Empty)
221      {
222        c.Formula = string.Empty;
223      }
224      else
225      {
226        if (formula[0] == '=') value = formula.Substring(1, formula.Length - 1); // remove any starting equalsign.
227        c.Formula = formula;
228      }
229    }
230    /// <summary>
231    /// Handles shared formulas
232    /// </summary>
233    /// <param name="value">The  formula</param>
234    /// <param name="address">The address of the formula</param>
235    /// <param name="IsArray">If the forumla is an array formula.</param>
236    private void Set_SharedFormula(string value, ExcelAddress address, bool IsArray)
237    {
238      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
239      {
240        throw (new InvalidOperationException("Can't set a formula for the entire worksheet"));
241      }
242      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
243      {
244        //Nope, single cell. Set the formula
245        Set_Formula(value, address.Start.Row, address.Start.Column);
246        return;
247      }
248      //RemoveFormuls(address);
249      CheckAndSplitSharedFormula();
250      ExcelWorksheet.Formulas f = new ExcelWorksheet.Formulas();
251      f.Formula = value;
252      f.Index = _worksheet.GetMaxShareFunctionIndex(IsArray);
253      f.Address = address.FirstAddress;
254      f.StartCol = address.Start.Column;
255      f.StartRow = address.Start.Row;
256      f.IsArray = IsArray;
257
258      _worksheet._sharedFormulas.Add(f.Index, f);
259      _worksheet.Cell(address.Start.Row, address.Start.Column).SharedFormulaID = f.Index;
260      _worksheet.Cell(address.Start.Row, address.Start.Column).Formula = value;
261
262      for (int col = address.Start.Column; col <= address.End.Column; col++)
263      {
264        for (int row = address.Start.Row; row <= address.End.Row; row++)
265        {
266          _worksheet.Cell(row, col).SharedFormulaID = f.Index;
267        }
268      }
269    }
270    private void Set_HyperLink(object value, int row, int col)
271    {
272      _worksheet.Cell(row, col).Hyperlink = value as Uri;
273    }
274    private void Set_IsRichText(object value, int row, int col)
275    {
276      _worksheet.Cell(row, col).IsRichText = (bool)value;
277    }
278    private void Exists_Comment(object value, int row, int col)
279    {
280      ulong cellID = GetCellID(_worksheet.SheetID, row, col);
281      if (_worksheet.Comments._comments.ContainsKey(cellID))
282      {
283        throw (new InvalidOperationException(string.Format("Cell {0} already contain a comment.", new ExcelCellAddress(row, col).Address)));
284      }
285
286    }
287    private void Set_Comment(object value, int row, int col)
288    {
289      string[] v = (string[])value;
290      Worksheet.Comments.Add(new ExcelRangeBase(_worksheet, GetAddress(_fromRow, _fromCol)), v[0], v[1]);
291      //   _worksheet.Cell(row, col).Comment = comment;
292    }
293    #endregion
294    private void SetToSelectedRange()
295    {
296      if (_worksheet.View.SelectedRange == "")
297      {
298        Address = "A1";
299      }
300      else
301      {
302        Address = _worksheet.View.SelectedRange;
303      }
304    }
305    private void IsRangeValid(string type)
306    {
307      if (_fromRow <= 0)
308      {
309        if (_address == "")
310        {
311          SetToSelectedRange();
312        }
313        else
314        {
315          if (type == "")
316          {
317            throw (new InvalidOperationException(string.Format("Range is not valid for this operation: {0}", _address)));
318          }
319          else
320          {
321            throw (new InvalidOperationException(string.Format("Range is not valid for {0} : {1}", type, _address)));
322          }
323        }
324      }
325    }
326    #region Public Properties
327    /// <summary>
328    /// The styleobject for the range.
329    /// </summary>
330    public ExcelStyle Style
331    {
332      get
333      {
334        IsRangeValid("styling");
335        return _worksheet.Workbook.Styles.GetStyleObject(_worksheet.Cell(_fromRow, _fromCol).StyleID, _worksheet.PositionID, Address);
336      }
337    }
338    /// <summary>
339    /// The named style
340    /// </summary>
341    public string StyleName
342    {
343      get
344      {
345        IsRangeValid("styling");
346        return _worksheet.Cell(_fromRow, _fromCol).StyleName;
347      }
348      set
349      {
350        _styleID = _worksheet.Workbook.Styles.GetStyleIdFromName(value);
351        if (_fromRow == 1 && _toRow == ExcelPackage.MaxRows)    //Full column
352        {
353          ExcelColumn column;
354          //Get the startcolumn
355          ulong colID = ExcelColumn.GetColumnID(_worksheet.SheetID, _fromCol);
356          if (!_worksheet._columns.ContainsKey(colID))
357          {
358            column = _worksheet.Column(_fromCol);
359          }
360          else
361          {
362            column = _worksheet._columns[colID] as ExcelColumn;
363          }
364
365          var index = _worksheet._columns.IndexOf(colID);
366          while (column.ColumnMin <= _toCol)
367          {
368            if (column.ColumnMax > _toCol)
369            {
370                            var newCol = _worksheet.CopyColumn(column, _toCol + 1, column.ColumnMax);
371              column.ColumnMax = _toCol;
372            }
373
374            column._styleName = value;
375            column._styleID = _styleID;
376
377            index++;
378            if (index >= _worksheet._columns.Count)
379            {
380              break;
381            }
382            else
383            {
384              column = (_worksheet._columns[index] as ExcelColumn);
385            }
386          }
387
388          if (column._columnMax < _toCol)
389          {
390            var newCol = _worksheet.Column(column._columnMax + 1) as ExcelColumn;
391            newCol._columnMax = _toCol;
392
393            newCol._styleID = _styleID;
394            newCol._styleName = value;
395          }
396                    if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) //FullRow
397                    {
398                        foreach(ExcelRow row in _worksheet._rows)
399                        {
400                            row._styleName = value;
401                            row._styleId = _styleID;
402                        }
403                    }
404        }
405                else if (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns) //FullRow
406                {
407                    for (int row = _fromRow; row <= _toRow; row++)
408                    {
409                        _worksheet.Row(row)._styleName = value;
410                        _worksheet.Row(row)._styleId = _styleID;
411                    }
412                }
413
414                if (!((_fromRow == 1 && _toRow == ExcelPackage.MaxRows) || (_fromCol == 1 && _toCol == ExcelPackage.MaxColumns))) //Cell specific
415                {
416                    for (int col = _fromCol; col <= _toCol; col++)
417                    {
418                        for (int row = _fromRow; row <= _toRow; row++)
419                        {
420                            _worksheet.Cell(row, col).StyleName = value;
421                        }
422                    }
423                }
424                else //Only set name on created cells. (uncreated cells is set on full row or full column).
425                {
426                    int tempIndex = _index;
427                    var e = this as IEnumerator;
428                    e.Reset();
429                    while (e.MoveNext())
430                    {
431                        ((ExcelCell)_worksheet._cells[_index]).SetNewStyleName(value, _styleID);
432                    }
433                    _index = tempIndex;
434                }
435                //_changePropMethod(Set_StyleName, value);
436      }
437    }
438    /// <summary>
439    /// The style ID.
440    /// It is not recomended to use this one. Use Named styles as an alternative.
441    /// If you do, make sure that you use the Style.UpdateXml() method to update any new styles added to the workbook.
442    /// </summary>
443    public int StyleID
444    {
445      get
446      {
447        return _worksheet.Cell(_fromRow, _fromCol).StyleID;
448      }
449      set
450      {
451        _changePropMethod(Set_StyleID, value);
452      }
453    }
454    /// <summary>
455    /// Set the range to a specific value
456    /// </summary>
457    public object Value
458    {
459      get
460      {
461        if (IsName)
462        {
463          if (_worksheet == null)
464          {
465            return _workbook._names[_address].NameValue;
466          }
467          else
468          {
469            return _worksheet.Names[_address].NameValue; ;
470          }
471        }
472        else
473        {
474          if (_fromRow == _toRow && _fromCol == _toCol)
475          {
476            return _worksheet.GetValue(_fromRow, _fromCol);
477          }
478          else
479          {
480            return GetValueArray();
481          }
482        }
483      }
484      set
485      {
486        if (IsName)
487        {
488          if (_worksheet == null)
489          {
490            _workbook._names[_address].NameValue = value;
491          }
492          else
493          {
494            _worksheet.Names[_address].NameValue = value;
495          }
496        }
497        else
498        {
499          _changePropMethod(Set_Value, value);
500        }
501      }
502    }
503
504        private bool IsInfinityValue(object value)
505        {
506            double? valueAsDouble = value as double?;
507
508            if(valueAsDouble.HasValue &&
509                (double.IsNegativeInfinity(valueAsDouble.Value) || double.IsPositiveInfinity(valueAsDouble.Value)))
510            {
511                return true;
512            }
513
514            return false;
515        }
516
517    private object GetValueArray()
518    {
519      ExcelAddressBase addr;
520      if (_fromRow == 1 && _fromCol == 1 && _toRow == ExcelPackage.MaxRows && _toCol == ExcelPackage.MaxColumns)
521      {
522        addr = _worksheet.Dimension;
523        if (addr == null) return null;
524      }
525      else
526      {
527        addr = this;
528      }
529      object[,] v = new object[addr._toRow - addr._fromRow + 1, addr._toCol - addr._fromCol + 1];
530
531      for (int col = addr._fromCol; col <= addr._toCol; col++)
532      {
533        for (int row = addr._fromRow; row <= addr._toRow; row++)
534        {
535          if (_worksheet._cells.ContainsKey(GetCellID(_worksheet.SheetID, row, col)))
536          {
537            if (IsRichText)
538            {
539              v[row - addr._fromRow, col - addr._fromCol] = GetRichText(row, col).Text;
540            }
541            else
542            {
543              v[row - addr._fromRow, col - addr._fromCol] = _worksheet.Cell(row, col).Value;
544            }
545          }
546        }
547      }
548      return v;
549    }
550    private ExcelAddressBase GetAddressDim(ExcelRangeBase addr)
551    {
552      int fromRow, fromCol, toRow, toCol;
553      var d = _worksheet.Dimension;
554      fromRow = addr._fromRow < d._fromRow ? d._fromRow : addr._fromRow;
555      fromCol = addr._fromCol < d._fromCol ? d._fromCol : addr._fromCol;
556
557      toRow = addr._toRow > d._toRow ? d._toRow : addr._toRow;
558      toCol = addr._toCol > d._toCol ? d._toCol : addr._toCol;
559
560      if (addr._fromCol == fromRow && addr._fromCol == addr._fromCol && addr._toRow == toRow && addr._toCol == _toCol)
561      {
562        return addr;
563      }
564      else
565      {
566        if (_fromRow > _toRow || _fromCol > _toCol)
567        {
568          return null;
569        }
570        else
571        {
572          return new ExcelAddressBase(fromRow, fromCol, toRow, toCol);
573        }
574      }
575    }
576
577    private object GetSingleValue()
578    {
579      if (IsRichText)
580      {
581        return RichText.Text;
582      }
583      else
584      {
585        return _worksheet.Cell(_fromRow, _fromCol).Value;
586      }
587    }
588    /// <summary>
589    /// Returns the formatted value.
590    /// </summary>
591    public string Text
592    {
593      get
594      {
595        return GetFormatedText(false);
596      }
597    }
598    /// <summary>
599    /// Set the column width from the content of the range. The minimum width is the value of the ExcelWorksheet.defaultColumnWidth property.
600    /// Note: Cells containing formulas are ignored since EPPlus don't have a calculation engine.
601    /// Wrapped and merged cells are also ignored.
602    /// </summary>
603    public void AutoFitColumns()
604    {
605      AutoFitColumns(_worksheet.DefaultColWidth);
606    }
607
608    /// <summary>
609    /// Set the column width from the content of the range.
610    /// Note: Cells containing formulas are ignored since EPPlus don't have a calculation engine.
611    ///       Wrapped and merged cells are also ignored.
612    /// </summary>
613        /// <remarks>This method will not work if you run in an environment that does not support GDI</remarks>
614    /// <param name="MinimumWidth">Minimum column width</param>
615    public void AutoFitColumns(double MinimumWidth)
616    {
617        AutoFitColumns(MinimumWidth, double.MaxValue);
618    }
619
620      /// <summary>
621      /// Set the column width from the content of the range.
622      /// Note: Cells containing formulas are ignored since EPPlus don't have a calculation engine.
623      ///       Wrapped and merged cells are also ignored.
624      /// </summary>
625      /// <param name="MinimumWidth">Minimum column width</param>
626      /// <param name="MaximumWidth">Maximum column width</param>
627      public void AutoFitColumns(double MinimumWidth, double MaximumWidth)
628    {
629      if (_fromCol < 1 || _fromRow < 1)
630      {
631        SetToSelectedRange();
632      }
633      Dictionary<int, Font> fontCache = new Dictionary<int, Font>();
634      Font f;
635
636      bool doAdjust = _worksheet._package.DoAdjustDrawings;
637      _worksheet._package.DoAdjustDrawings = false;
638      var drawWidths = _worksheet.Drawings.GetDrawingWidths();
639
640      int fromCol = _fromCol > _worksheet.Dimension._fromCol ? _fromCol : _worksheet.Dimension._fromCol;
641      int toCol = _toCol < _worksheet.Dimension._toCol ? _toCol : _worksheet.Dimension._toCol;
642      if (Addresses == null)
643      {
644        for (int col = fromCol; col <= toCol; col++)
645        {
646          _worksheet.Column(col).Width = MinimumWidth;
647        }
648      }
649      else
650      {
651        foreach (var addr in Addresses)
652        {
653          fromCol = addr._fromCol > _worksheet.Dimension._fromCol ? addr._fromCol : _worksheet.Dimension._fromCol;
654          toCol = addr._toCol < _worksheet.Dimension._toCol ? addr._toCol : _worksheet.Dimension._toCol;
655          for (int col = fromCol; col <= toCol; col++)
656          {
657            _worksheet.Column(col).Width = MinimumWidth;
658          }
659        }
660      }
661
662      //Get any autofilter to widen these columns
663      List<ExcelAddressBase> afAddr = new List<ExcelAddressBase>();
664      if (_worksheet.AutoFilterAddress != null)
665      {
666        afAddr.Add(new ExcelAddressBase(_worksheet.AutoFilterAddress._fromRow,
667                                        _worksheet.AutoFilterAddress._fromCol,
668                                        _worksheet.AutoFilterAddress._fromRow,
669                                        _worksheet.AutoFilterAddress._toCol));
670        afAddr[afAddr.Count - 1]._ws = WorkSheet;
671      }
672      foreach (var tbl in _worksheet.Tables)
673      {
674        if (tbl.AutoFilterAddress != null)
675        {
676          afAddr.Add(new ExcelAddressBase(tbl.AutoFilterAddress._fromRow,
677                                      tbl.AutoFilterAddress._fromCol,
678                                      tbl.AutoFilterAddress._fromRow,
679                                      tbl.AutoFilterAddress._toCol));
680          afAddr[afAddr.Count - 1]._ws = WorkSheet;
681        }
682      }
683
684      var styles = _worksheet.Workbook.Styles;
685      var nf = styles.Fonts[styles.CellXfs[0].FontId];
686      FontStyle fs = FontStyle.Regular;
687      if (nf.Bold) fs |= FontStyle.Bold;
688      if (nf.UnderLine) fs |= FontStyle.Underline;
689      if (nf.Italic) fs |= FontStyle.Italic;
690      if (nf.Strike) fs |= FontStyle.Strikeout;
691      var nfont = new Font(nf.Name, nf.Size, fs);
692           
693      using (Bitmap b = new Bitmap(1, 1))
694      {
695        using (Graphics g = Graphics.FromImage(b))
696        {
697          float normalSize = (float)Math.Truncate(g.MeasureString("00", nfont).Width - g.MeasureString("0", nfont).Width);
698          g.PageUnit = GraphicsUnit.Pixel;
699          foreach (var cell in this)
700          {
701            if (cell.Merge == true || cell.Style.WrapText) continue;
702            var fntID = styles.CellXfs[cell.StyleID].FontId;
703            if (fontCache.ContainsKey(fntID))
704            {
705              f = fontCache[fntID];
706            }
707            else
708            {
709              var fnt = styles.Fonts[fntID];
710              fs = FontStyle.Regular;
711              if (fnt.Bold) fs |= FontStyle.Bold;
712              if (fnt.UnderLine) fs |= FontStyle.Underline;
713              if (fnt.Italic) fs |= FontStyle.Italic;
714              if (fnt.Strike) fs |= FontStyle.Strikeout;
715              f = new Font(fnt.Name, fnt.Size, fs);
716              fontCache.Add(fntID, f);
717            }
718
719            //Truncate(({pixels}-5)/{Maximum Digit Width} * 100+0.5)/100
720
721                        var size = g.MeasureString(cell.TextForWidth, f);
722                        double width;
723                        double r = styles.CellXfs[cell.StyleID].TextRotation;
724                        if (r <= 0 )
725                        {
726                            width = (size.Width + 5) / normalSize;
727                        }
728                        else
729                        {
730                            r = (r <= 90 ? r : r - 90);
731                            width = (((size.Width - size.Height) * Math.Abs(System.Math.Cos(System.Math.PI * r / 180.0)) + size.Height) + 5) / normalSize;
732                        }
733
734            foreach (var a in afAddr)
735            {
736              if (a.Collide(cell) != eAddressCollition.No)
737              {
738                width += 2.25;
739                break;
740              }
741            }
742
743            if (width > _worksheet.Column(cell._fromCol).Width)
744            {
745              _worksheet.Column(cell._fromCol).Width = width > MaximumWidth ? MaximumWidth : width;
746            }
747          }
748        }
749      }
750      _worksheet.Drawings.AdjustWidth(drawWidths);
751      _worksheet._package.DoAdjustDrawings = doAdjust;
752    }
753
754    internal string TextForWidth
755    {
756      get
757      {
758        return GetFormatedText(true);
759      }
760    }
761    private string GetFormatedText(bool forWidthCalc)
762    {
763      object v = Value;
764      if (v == null) return "";
765      var styles = Worksheet.Workbook.Styles;
766      var nfID = styles.CellXfs[StyleID].NumberFormatId;
767      ExcelNumberFormatXml.ExcelFormatTranslator nf = null;
768      for (int i = 0; i < styles.NumberFormats.Count; i++)
769      {
770        if (nfID == styles.NumberFormats[i].NumFmtId)
771        {
772          nf = styles.NumberFormats[i].FormatTranslator;
773          break;
774        }
775      }
776
777      string format, textFormat;
778      if (forWidthCalc)
779      {
780        format = nf.NetFormatForWidth;
781        textFormat = nf.NetTextFormatForWidth;
782      }
783      else
784      {
785        format = nf.NetFormat;
786        textFormat = nf.NetTextFormat;
787      }
788
789      if (v is decimal || v.GetType().IsPrimitive)
790      {
791        double d;
792        try
793        {
794          d = Convert.ToDouble(v);
795        }
796        catch
797        {
798          return "";
799        }
800
801        if (nf.DataType == ExcelNumberFormatXml.eFormatType.Number)
802        {
803          if (string.IsNullOrEmpty(nf.FractionFormat))
804          {
805            return d.ToString(format, nf.Culture);
806          }
807          else
808          {
809            return nf.FormatFraction(d);
810          }
811        }
812        else if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime)
813        {
814          var date = DateTime.FromOADate(d);
815          return date.ToString(format, nf.Culture);
816        }
817      }
818      else if (v is DateTime)
819      {
820        if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime)
821        {
822          return ((DateTime)v).ToString(format, nf.Culture);
823        }
824        else
825        {
826          double d = ((DateTime)v).ToOADate();
827          if (string.IsNullOrEmpty(nf.FractionFormat))
828          {
829            return d.ToString(format, nf.Culture);
830          }
831          else
832          {
833            return nf.FormatFraction(d);
834          }
835        }
836      }
837      else if (v is TimeSpan)
838      {
839        if (nf.DataType == ExcelNumberFormatXml.eFormatType.DateTime)
840        {
841          return new DateTime(((TimeSpan)v).Ticks).ToString(format, nf.Culture);
842        }
843        else
844        {
845          double d = (new DateTime(((TimeSpan)v).Ticks)).ToOADate();
846          if (string.IsNullOrEmpty(nf.FractionFormat))
847          {
848            return d.ToString(format, nf.Culture);
849          }
850          else
851          {
852            return nf.FormatFraction(d);
853          }
854        }
855      }
856      else
857      {
858        if (textFormat == "")
859        {
860          return v.ToString();
861        }
862        else
863        {
864          return string.Format(textFormat, v);
865        }
866      }
867      return v.ToString();
868    }
869    /// <summary>
870    /// Gets or sets a formula for a range.
871    /// </summary>
872    public string Formula
873    {
874      get
875      {
876        if (IsName)
877        {
878          if (_worksheet == null)
879          {
880            return _workbook._names[_address].NameFormula;
881          }
882          else
883          {
884            return _worksheet.Names[_address].NameFormula;
885          }
886        }
887        else
888        {
889          return _worksheet.Cell(_fromRow, _fromCol).Formula;
890        }
891      }
892      set
893      {
894        if (IsName)
895        {
896          if (_worksheet == null)
897          {
898            _workbook._names[_address].NameFormula = value;
899          }
900          else
901          {
902            _worksheet.Names[_address].NameFormula = value;
903          }
904        }
905        else
906        {
907          if (_fromRow == _toRow && _fromCol == _toCol)
908          {
909            Set_Formula(value, _fromRow, _fromCol);
910          }
911          else
912          {
913            Set_SharedFormula(value, this, false);
914            if (Addresses != null)
915            {
916              foreach (var address in Addresses)
917              {
918                Set_SharedFormula(value, address, false);
919              }
920            }
921          }
922        }
923      }
924    }
925    /// <summary>
926    /// Gets or Set a formula in R1C1 format.
927    /// </summary>
928    public string FormulaR1C1
929    {
930      get
931      {
932        IsRangeValid("FormulaR1C1");
933        return _worksheet.Cell(_fromRow, _fromCol).FormulaR1C1;
934      }
935      set
936      {
937        IsRangeValid("FormulaR1C1");
938        if (value.Length > 0 && value[0] == '=') value = value.Substring(1, value.Length - 1); // remove any starting equalsign.
939
940        if (Addresses == null)
941        {
942          Set_SharedFormula(ExcelCell.TranslateFromR1C1(value, _fromRow, _fromCol), this, false);
943        }
944        else
945        {
946          Set_SharedFormula(ExcelCell.TranslateFromR1C1(value, _fromRow, _fromCol), new ExcelAddress(FirstAddress), false);
947          foreach (var address in Addresses)
948          {
949            Set_SharedFormula(ExcelCell.TranslateFromR1C1(value, address.Start.Row, address.Start.Column), address, false);
950          }
951        }
952      }
953    }
954    /// <summary>
955    /// Set the hyperlink property for a range of cells
956    /// </summary>
957    public Uri Hyperlink
958    {
959      get
960      {
961        IsRangeValid("formulaR1C1");
962        return _worksheet.Cell(_fromRow, _fromCol).Hyperlink;
963      }
964      set
965      {
966        _changePropMethod(Set_HyperLink, value);
967      }
968    }
969    /// <summary>
970    /// If the cells in the range are merged.
971    /// </summary>
972    public bool Merge
973    {
974      get
975      {
976        IsRangeValid("merging");
977        for (int col = _fromCol; col <= _toCol; col++)
978        {
979          for (int row = _fromRow; row <= _toRow; row++)
980          {
981            if (!_worksheet.Cell(row, col).Merge)
982            {
983              return false;
984            }
985          }
986        }
987        return true;
988      }
989      set
990      {
991        IsRangeValid("merging");
992        SetMerge(value, FirstAddress);
993        if (Addresses != null)
994        {
995          foreach (var address in Addresses)
996          {
997            SetMerge(value, address._address);
998          }
999        }
1000      }
1001    }
1002
1003    private void SetMerge(bool value, string address)
1004    {
1005      if (!value)
1006      {
1007        if (_worksheet.MergedCells.List.Contains(address))
1008        {
1009          SetCellMerge(false, address);
1010          _worksheet.MergedCells.List.Remove(address);
1011        }
1012        else if (!CheckMergeDiff(false, address))
1013        {
1014          throw (new Exception("Range is not fully merged.Specify the exact range"));
1015        }
1016      }
1017      else
1018      {
1019        if (CheckMergeDiff(false, address))
1020        {
1021          SetCellMerge(true, address);
1022          _worksheet.MergedCells.List.Add(address);
1023        }
1024        else
1025        {
1026          if (!_worksheet.MergedCells.List.Contains(address))
1027          {
1028            throw (new Exception("Cells are already merged"));
1029          }
1030        }
1031      }
1032    }
1033    /// <summary>
1034    /// Set an autofilter for the range
1035    /// </summary>
1036    public bool AutoFilter
1037    {
1038      get
1039      {
1040        IsRangeValid("autofilter");
1041        ExcelAddressBase address = _worksheet.AutoFilterAddress;
1042        if (address == null) return false;
1043        if (_fromRow >= address.Start.Row
1044            &&
1045            _toRow <= address.End.Row
1046            &&
1047            _fromCol >= address.Start.Column
1048            &&
1049            _toCol <= address.End.Column)
1050        {
1051          return true;
1052        }
1053        return false;
1054      }
1055      set
1056      {
1057        IsRangeValid("autofilter");
1058        _worksheet.AutoFilterAddress = this;
1059        if (_worksheet.Names.ContainsKey("_xlnm._FilterDatabase"))
1060        {
1061          _worksheet.Names.Remove("_xlnm._FilterDatabase");
1062        }
1063        var result = _worksheet.Names.Add("_xlnm._FilterDatabase", this);
1064        result.IsNameHidden = true;
1065      }
1066    }
1067    /// <summary>
1068    /// If the value is in richtext format.
1069    /// </summary>
1070    public bool IsRichText
1071    {
1072      get
1073      {
1074        IsRangeValid("richtext");
1075        return _worksheet.Cell(_fromRow, _fromCol).IsRichText;
1076      }
1077      set
1078      {
1079        _changePropMethod(Set_IsRichText, value);
1080      }
1081    }
1082    /// <summary>
1083    /// Is the range a part of an Arrayformula
1084    /// </summary>
1085    public bool IsArrayFormula
1086    {
1087      get
1088      {
1089        IsRangeValid("arrayformulas");
1090        return _worksheet.Cell(_fromRow, _fromCol).IsArrayFormula;
1091      }
1092    }
1093    ExcelRichTextCollection _rtc = null;
1094    /// <summary>
1095    /// Cell value is richtext formated.
1096    /// </summary>
1097    public ExcelRichTextCollection RichText
1098    {
1099      get
1100      {
1101        IsRangeValid("richtext");
1102        if (_rtc == null)
1103        {
1104          _rtc = GetRichText(_fromRow, _fromCol);
1105        }
1106        return _rtc;
1107      }
1108    }
1109
1110    private ExcelRichTextCollection GetRichText(int row, int col)
1111    {
1112      XmlDocument xml = new XmlDocument();
1113      var cell = _worksheet.Cell(row, col);
1114      if (cell.Value != null)
1115      {
1116        if (cell.IsRichText)
1117        {
1118                    XmlHelper.LoadXmlSafe(xml, "<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" >" + cell.Value.ToString() + "</d:si>", Encoding.UTF8);
1119        }
1120        else
1121        {
1122          xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" ><d:r><d:t>" + SecurityElement.Escape(cell.Value.ToString()) + "</d:t></d:r></d:si>");
1123        }
1124      }
1125      else
1126      {
1127        xml.LoadXml("<d:si xmlns:d=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" />");
1128      }
1129      var rtc = new ExcelRichTextCollection(_worksheet.NameSpaceManager, xml.SelectSingleNode("d:si", _worksheet.NameSpaceManager), this);
1130      if (rtc.Count == 1 && cell.IsRichText == false)
1131      {
1132        IsRichText = true;
1133        var fnt = cell.Style.Font;
1134        rtc[0].PreserveSpace = true;
1135        rtc[0].Bold = fnt.Bold;
1136        rtc[0].FontName = fnt.Name;
1137        rtc[0].Italic = fnt.Italic;
1138        rtc[0].Size = fnt.Size;
1139        rtc[0].UnderLine = fnt.UnderLine;
1140
1141        int hex;
1142        if (fnt.Color.Rgb != "" && int.TryParse(fnt.Color.Rgb, NumberStyles.HexNumber, null, out hex))
1143        {
1144          rtc[0].Color = Color.FromArgb(hex);
1145        }
1146
1147      }
1148      return rtc;
1149    }
1150    /// <summary>
1151    /// returns the comment object of the first cell in the range
1152    /// </summary>
1153    public ExcelComment Comment
1154    {
1155      get
1156      {
1157        IsRangeValid("comments");
1158        ulong cellID = GetCellID(_worksheet.SheetID, _fromRow, _fromCol);
1159        if (_worksheet.Comments._comments.ContainsKey(cellID))
1160        {
1161          return _worksheet._comments._comments[cellID] as ExcelComment;
1162        }
1163        return null;
1164      }
1165    }
1166    /// <summary>
1167    /// WorkSheet object
1168    /// </summary>
1169    public ExcelWorksheet Worksheet
1170    {
1171      get
1172      {
1173        return _worksheet;
1174      }
1175    }
1176    /// <summary>
1177    /// Address including sheetname
1178    /// </summary>
1179    public string FullAddress
1180    {
1181      get
1182      {
1183        string fullAddress = GetFullAddress(_worksheet.Name, _address);
1184        if (Addresses != null)
1185        {
1186          foreach (var a in Addresses)
1187          {
1188            fullAddress += "," + GetFullAddress(_worksheet.Name, a.Address); ;
1189          }
1190        }
1191        return fullAddress;
1192      }
1193    }
1194    /// <summary>
1195    /// Address including sheetname
1196    /// </summary>
1197    public string FullAddressAbsolute
1198    {
1199      get
1200      {
1201        string wbwsRef = string.IsNullOrEmpty(base._wb) ? base._ws : "[" + base._wb.Replace("'", "''") + "]" + _ws;
1202        string fullAddress = GetFullAddress(wbwsRef, GetAddress(_fromRow, _fromCol, _toRow, _toCol, true));
1203        if (Addresses != null)
1204        {
1205          foreach (var a in Addresses)
1206          {
1207            fullAddress += "," + GetFullAddress(wbwsRef, GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true)); ;
1208          }
1209        }
1210        return fullAddress;
1211      }
1212    }
1213        /// <summary>
1214        /// Address including sheetname
1215        /// </summary>
1216        internal string FullAddressAbsoluteNoFullRowCol
1217        {
1218            get
1219            {
1220                string wbwsRef = string.IsNullOrEmpty(base._wb) ? base._ws : "[" + base._wb.Replace("'", "''") + "]" + _ws;
1221                string fullAddress = GetFullAddress(wbwsRef, GetAddress(_fromRow, _fromCol, _toRow, _toCol, true), false);
1222                if (Addresses != null)
1223                {
1224                    foreach (var a in Addresses)
1225                    {
1226                        fullAddress += "," + GetFullAddress(wbwsRef, GetAddress(a.Start.Row, a.Start.Column, a.End.Row, a.End.Column, true),false); ;
1227                    }
1228                }
1229                return fullAddress;
1230            }
1231        }
1232    #endregion
1233    #region Private Methods
1234    /// <summary>
1235    /// Check if the range is partly merged
1236    /// </summary>
1237    /// <param name="startValue">the starting value</param>
1238    /// <param name="address">the address</param>
1239    /// <returns></returns>
1240    private bool CheckMergeDiff(bool startValue, string address)
1241    {
1242      ExcelAddress a = new ExcelAddress(address);
1243      for (int col = a._fromCol; col <= a._toCol; col++)
1244      {
1245        for (int row = a._fromRow; row <= a._toRow; row++)
1246        {
1247          if (_worksheet.Cell(row, col).Merge != startValue)
1248          {
1249            return false;
1250          }
1251        }
1252      }
1253      return true;
1254    }
1255    /// <summary>
1256    /// Set the merge flag for the range
1257    /// </summary>
1258    /// <param name="value"></param>
1259    /// <param name="address"></param>
1260    internal void SetCellMerge(bool value, string address)
1261    {
1262      ExcelAddress a = new ExcelAddress(address);
1263      for (int col = a._fromCol; col <= a._toCol; col++)
1264      {
1265        for (int row = a._fromRow; row <= a._toRow; row++)
1266        {
1267          _worksheet.Cell(row, col).Merge = value;
1268        }
1269      }
1270    }
1271    /// <summary>
1272    /// Set the value without altering the richtext property
1273    /// </summary>
1274    /// <param name="value">the value</param>
1275    internal void SetValueRichText(object value)
1276    {
1277      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
1278      {
1279        _worksheet.Cell(1, 1).SetValueRichText(value);
1280      }
1281      else
1282      {
1283        for (int col = _fromCol; col <= _toCol; col++)
1284        {
1285          for (int row = _fromRow; row <= _toRow; row++)
1286          {
1287            _worksheet.Cell(row, col).SetValueRichText(value);
1288          }
1289        }
1290      }
1291    }
1292    /// <summary>
1293    /// Removes a shared formula
1294    /// </summary>
1295    private void RemoveFormuls(ExcelAddress address)
1296    {
1297      List<int> removed = new List<int>();
1298      int fFromRow, fFromCol, fToRow, fToCol;
1299      foreach (int index in _worksheet._sharedFormulas.Keys)
1300      {
1301        ExcelWorksheet.Formulas f = _worksheet._sharedFormulas[index];
1302        ExcelCell.GetRowColFromAddress(f.Address, out fFromRow, out fFromCol, out fToRow, out fToCol);
1303        if (((fFromCol >= address.Start.Column && fFromCol <= address.End.Column) ||
1304           (fToCol >= address.Start.Column && fToCol <= address.End.Column)) &&
1305           ((fFromRow >= address.Start.Row && fFromRow <= address.End.Row) ||
1306           (fToRow >= address.Start.Row && fToRow <= address.End.Row)))
1307        {
1308          for (int col = fFromCol; col <= fToCol; col++)
1309          {
1310            for (int row = fFromRow; row <= fToRow; row++)
1311            {
1312              _worksheet.Cell(row, col).SharedFormulaID = int.MinValue;
1313            }
1314          }
1315          removed.Add(index);
1316        }
1317      }
1318      foreach (int index in removed)
1319      {
1320        _worksheet._sharedFormulas.Remove(index);
1321      }
1322    }
1323    internal void SetSharedFormulaID(int id)
1324    {
1325      for (int col = _fromCol; col <= _toCol; col++)
1326      {
1327        for (int row = _fromRow; row <= _toRow; row++)
1328        {
1329          _worksheet.Cell(row, col).SharedFormulaID = id;
1330        }
1331      }
1332    }
1333    private void CheckAndSplitSharedFormula()
1334    {
1335      for (int col = _fromCol; col <= _toCol; col++)
1336      {
1337        for (int row = _fromRow; row <= _toRow; row++)
1338        {
1339          if (_worksheet.Cell(row, col).SharedFormulaID >= 0)
1340          {
1341            SplitFormulas();
1342            return;
1343          }
1344        }
1345      }
1346    }
1347
1348    private void SplitFormulas()
1349    {
1350      List<int> formulas = new List<int>();
1351      for (int col = _fromCol; col <= _toCol; col++)
1352      {
1353        for (int row = _fromRow; row <= _toRow; row++)
1354        {
1355          int id = _worksheet.Cell(row, col).SharedFormulaID;
1356          if (id >= 0 && !formulas.Contains(id))
1357          {
1358            if (_worksheet._sharedFormulas[id].IsArray &&
1359                Collide(_worksheet.Cells[_worksheet._sharedFormulas[id].Address]) == eAddressCollition.Partly) // If the formula is an array formula and its on inside the overwriting range throw an exception
1360            {
1361              throw (new Exception("Can not overwrite a part of an array-formula"));
1362            }
1363            formulas.Add(_worksheet.Cell(row, col).SharedFormulaID);
1364          }
1365        }
1366      }
1367
1368      foreach (int ix in formulas)
1369      {
1370        SplitFormula(ix);
1371      }
1372    }
1373
1374    private void SplitFormula(int ix)
1375    {
1376      var f = _worksheet._sharedFormulas[ix];
1377      var fRange = _worksheet.Cells[f.Address];
1378      var collide = Collide(fRange);
1379
1380      //The formula is inside the currenct range, remove it
1381      if (collide == eAddressCollition.Inside)
1382      {
1383        _worksheet._sharedFormulas.Remove(ix);
1384        fRange.SetSharedFormulaID(int.MinValue);
1385      }
1386      else if (collide == eAddressCollition.Partly)
1387      {
1388        //The formula partly collides with the current range
1389        bool fIsSet = false;
1390        string formulaR1C1 = fRange.FormulaR1C1;
1391        //Top Range
1392        if (fRange._fromRow < _fromRow)
1393        {
1394          f.Address = ExcelCell.GetAddress(fRange._fromRow, fRange._fromCol, _fromRow - 1, fRange._toCol);
1395          fIsSet = true;
1396        }
1397        //Left Range
1398        if (fRange._fromCol < _fromCol)
1399        {
1400          if (fIsSet)
1401          {
1402            f = new ExcelWorksheet.Formulas();
1403            f.Index = _worksheet.GetMaxShareFunctionIndex(false);
1404            f.StartCol = fRange._fromCol;
1405            f.IsArray = false;
1406            _worksheet._sharedFormulas.Add(f.Index, f);
1407          }
1408          else
1409          {
1410            fIsSet = true;
1411          }
1412          if (fRange._fromRow < _fromRow)
1413            f.StartRow = _fromRow;
1414          else
1415          {
1416            f.StartRow = fRange._fromRow;
1417          }
1418          if (fRange._toRow < _toRow)
1419          {
1420            f.Address = ExcelCell.GetAddress(f.StartRow, f.StartCol,
1421                fRange._toRow, _fromCol - 1);
1422          }
1423          else
1424          {
1425            f.Address = ExcelCell.GetAddress(f.StartRow, f.StartCol,
1426               _toRow, _fromCol - 1);
1427          }
1428          f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
1429          _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index);
1430        }
1431        //Right Range
1432        if (fRange._toCol > _toCol)
1433        {
1434          if (fIsSet)
1435          {
1436            f = new ExcelWorksheet.Formulas();
1437            f.Index = _worksheet.GetMaxShareFunctionIndex(false);
1438            f.IsArray = false;
1439            _worksheet._sharedFormulas.Add(f.Index, f);
1440          }
1441          else
1442          {
1443            fIsSet = true;
1444          }
1445          f.StartCol = _toCol + 1;
1446          if (_fromRow < fRange._fromRow)
1447            f.StartRow = fRange._fromRow;
1448          else
1449          {
1450            f.StartRow = _fromRow;
1451          }
1452
1453          if (fRange._toRow < _toRow)
1454          {
1455            f.Address = ExcelCell.GetAddress(f.StartRow, f.StartCol,
1456                fRange._toRow, fRange._toCol);
1457          }
1458          else
1459          {
1460            f.Address = ExcelCell.GetAddress(f.StartRow, f.StartCol,
1461                _toRow, fRange._toCol);
1462          }
1463          f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
1464          _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index);
1465        }
1466        //Bottom Range
1467        if (fRange._toRow > _toRow)
1468        {
1469          if (fIsSet)
1470          {
1471            f = new ExcelWorksheet.Formulas();
1472            f.Index = _worksheet.GetMaxShareFunctionIndex(false);
1473            f.IsArray = false;
1474            _worksheet._sharedFormulas.Add(f.Index, f);
1475          }
1476
1477          f.StartCol = fRange._fromCol;
1478          f.StartRow = _toRow + 1;
1479
1480          f.Formula = TranslateFromR1C1(formulaR1C1, f.StartRow, f.StartCol);
1481
1482          f.Address = ExcelCell.GetAddress(f.StartRow, f.StartCol,
1483              fRange._toRow, fRange._toCol);
1484          _worksheet.Cells[f.Address].SetSharedFormulaID(f.Index);
1485
1486        }
1487      }
1488    }
1489    private object ConvertData(ExcelTextFormat Format, string v, int col, bool isText)
1490    {
1491      if (isText && (Format.DataTypes == null || Format.DataTypes.Length < col)) return v;
1492
1493      double d;
1494      DateTime dt;
1495      if (Format.DataTypes == null || Format.DataTypes.Length < col || Format.DataTypes[col] == eDataTypes.Unknown)
1496      {
1497        string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
1498        if (double.TryParse(v2, NumberStyles.Any, Format.Culture, out d))
1499        {
1500          if (v2 == v)
1501          {
1502            return d;
1503          }
1504          else
1505          {
1506            return d / 100;
1507          }
1508        }
1509        if (DateTime.TryParse(v, Format.Culture, DateTimeStyles.None, out dt))
1510        {
1511          return dt;
1512        }
1513        else
1514        {
1515          return v;
1516        }
1517      }
1518      else
1519      {
1520        switch (Format.DataTypes[col])
1521        {
1522          case eDataTypes.Number:
1523            if (double.TryParse(v, NumberStyles.Any, Format.Culture, out d))
1524            {
1525              return d;
1526            }
1527            else
1528            {
1529              return v;
1530            }
1531          case eDataTypes.DateTime:
1532            if (DateTime.TryParse(v, Format.Culture, DateTimeStyles.None, out dt))
1533            {
1534              return dt;
1535            }
1536            else
1537            {
1538              return v;
1539            }
1540          case eDataTypes.Percent:
1541            string v2 = v.EndsWith("%") ? v.Substring(0, v.Length - 1) : v;
1542            if (double.TryParse(v2, NumberStyles.Any, Format.Culture, out d))
1543            {
1544              return d / 100;
1545            }
1546            else
1547            {
1548              return v;
1549            }
1550
1551          default:
1552            return v;
1553
1554        }
1555      }
1556    }
1557    #endregion
1558    #region Public Methods
1559    #region ConditionalFormatting
1560    /// <summary>
1561    /// Conditional Formatting for this range.
1562    /// </summary>
1563    public IRangeConditionalFormatting ConditionalFormatting
1564    {
1565      get
1566      {
1567        return new RangeConditionalFormatting(_worksheet, new ExcelAddress(Address));
1568      }
1569    }
1570    #endregion
1571    #region DataValidation
1572    /// <summary>
1573    /// Data validation for this range.
1574    /// </summary>
1575    public IRangeDataValidation DataValidation
1576    {
1577      get
1578      {
1579                return new RangeDataValidation(_worksheet, Address);
1580      }
1581    }
1582    #endregion
1583    #region LoadFromDataTable
1584    /// <summary>
1585    /// Load the data from the datatable starting from the top left cell of the range
1586    /// </summary>
1587    /// <param name="Table">The datatable to load</param>
1588    /// <param name="PrintHeaders">Print the column caption property (if set) or the columnname property if not, on first row</param>
1589    /// <param name="TableStyle">The table style to apply to the data</param>
1590    /// <returns>The filled range</returns>
1591    public ExcelRangeBase LoadFromDataTable(DataTable Table, bool PrintHeaders, TableStyles TableStyle)
1592    {
1593      var r = LoadFromDataTable(Table, PrintHeaders);
1594
1595      int rows = Table.Rows.Count + (PrintHeaders ? 1 : 0) - 1;
1596            if (rows >= 0 && Table.Columns.Count>0)
1597      {
1598                var tbl = _worksheet.Tables.Add(new ExcelAddressBase(_fromRow, _fromCol, _fromRow + (rows==0 ? 1 : rows), _fromCol + Table.Columns.Count-1), Table.TableName);
1599        tbl.ShowHeader = PrintHeaders;
1600        tbl.TableStyle = TableStyle;
1601      }
1602        return r;
1603    }
1604    /// <summary>
1605    /// Load the data from the datatable starting from the top left cell of the range
1606    /// </summary>
1607    /// <param name="Table">The datatable to load</param>
1608    /// <param name="PrintHeaders">Print the caption property (if set) or the columnname property if not, on first row</param>
1609    /// <returns>The filled range</returns>
1610    public ExcelRangeBase LoadFromDataTable(DataTable Table, bool PrintHeaders)
1611    {
1612      if (Table == null)
1613      {
1614        throw (new ArgumentNullException("Table can't be null"));
1615      }
1616
1617      int col = _fromCol, row = _fromRow;
1618      if (PrintHeaders)
1619      {
1620        foreach (DataColumn dc in Table.Columns)
1621        {
1622                    // If no caption is set, the ColumnName property is called implicitly.
1623          _worksheet.Cell(row, col++).Value = dc.Caption;
1624        }
1625        row++;
1626        col = _fromCol;
1627      }
1628      foreach (DataRow dr in Table.Rows)
1629      {
1630        foreach (object value in dr.ItemArray)
1631        {
1632          _worksheet.Cell(row, col++).Value = value;
1633        }
1634        row++;
1635        col = _fromCol;
1636      }
1637            return _worksheet.Cells[_fromRow, _fromCol, row - 1, _fromCol + Table.Columns.Count - 1];
1638    }
1639    #endregion
1640    #region LoadFromArrays
1641    /// <summary>
1642    /// Loads data from the collection of arrays of objects into the range, starting from
1643    /// the top-left cell.
1644    /// </summary>
1645    /// <param name="Data">The data.</param>
1646    public ExcelRangeBase LoadFromArrays(IEnumerable<object[]> Data)
1647    {
1648      //thanx to Abdullin for the code contribution
1649      if (Data == null) throw new ArgumentNullException("data");
1650
1651      int column = _fromCol, row = _fromRow;
1652
1653      foreach (var rowData in Data)
1654      {
1655        column = _fromCol;
1656        foreach (var cellData in rowData)
1657        {
1658          _worksheet.Cell(row, column).Value = cellData;
1659          column += 1;
1660        }
1661        row += 1;
1662      }
1663      return _worksheet.Cells[_fromRow, _fromCol, row - 1, column - 1];
1664    }
1665    #endregion
1666    #region LoadFromCollection
1667    /// <summary>
1668    /// Load a collection into a the worksheet starting from the top left row of the range.
1669    /// </summary>
1670    /// <typeparam name="T">The datatype in the collection</typeparam>
1671    /// <param name="Collection">The collection to load</param>
1672    /// <returns>The filled range</returns>
1673    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection)
1674    {
1675      return LoadFromCollection<T>(Collection, false, TableStyles.None, BindingFlags.Public | BindingFlags.Instance, null);
1676    }
1677    /// <summary>
1678    /// Load a collection of T into the worksheet starting from the top left row of the range.
1679    /// Default option will load all public instance properties of T
1680    /// </summary>
1681    /// <typeparam name="T">The datatype in the collection</typeparam>
1682    /// <param name="Collection">The collection to load</param>
1683    /// <param name="PrintHeaders">Print the property names on the first row</param>
1684    /// <returns>The filled range</returns>
1685    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders)
1686    {
1687      return LoadFromCollection<T>(Collection, PrintHeaders, TableStyles.None, BindingFlags.Public | BindingFlags.Instance, null);
1688    }
1689    /// <summary>
1690    /// Load a collection of T into the worksheet starting from the top left row of the range.
1691    /// Default option will load all public instance properties of T
1692    /// </summary>
1693    /// <typeparam name="T">The datatype in the collection</typeparam>
1694    /// <param name="Collection">The collection to load</param>
1695    /// <param name="PrintHeaders">Print the property names on the first row</param>
1696    /// <param name="TableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param>
1697    /// <returns>The filled range</returns>
1698    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders, TableStyles TableStyle)
1699    {
1700      return LoadFromCollection<T>(Collection, PrintHeaders, TableStyle, BindingFlags.Public | BindingFlags.Instance, null);
1701    }
1702    /// <summary>
1703    /// Load a collection into the worksheet starting from the top left row of the range.
1704    /// </summary>
1705    /// <typeparam name="T">The datatype in the collection</typeparam>
1706    /// <param name="Collection">The collection to load</param>
1707    /// <param name="PrintHeaders">Print the property names on the first row. Any underscore in the property name will be converted to a space.</param>
1708    /// <param name="TableStyle">Will create a table with this style. If set to TableStyles.None no table will be created</param>
1709    /// <param name="memberFlags">Property flags to use</param>
1710    /// <param name="Members">The properties to output. Must be of type T</param>
1711    /// <returns>The filled range</returns>
1712    public ExcelRangeBase LoadFromCollection<T>(IEnumerable<T> Collection, bool PrintHeaders, TableStyles TableStyle, BindingFlags memberFlags, MemberInfo[] Members)
1713    {
1714      var type = typeof(T);
1715      if (Members == null)
1716      {
1717        Members = type.GetProperties(memberFlags);
1718      }
1719      else
1720      {
1721        foreach (var t in Members)
1722        {
1723          if (t.DeclaringType != type)
1724          {
1725            throw (new Exception("Supplied properties in parameter Properties must be of the same type as T"));
1726          }
1727        }
1728      }
1729
1730      int col = _fromCol, row = _fromRow;
1731      if (Members.Length > 0 && PrintHeaders)
1732      {
1733        foreach (var t in Members)
1734        {
1735          _worksheet.Cell(row, col++).Value = t.Name.Replace('_', ' ');
1736        }
1737        row++;
1738      }
1739
1740      if (Members.Length == 0)
1741      {
1742        foreach (var item in Collection)
1743        {
1744          _worksheet.Cells[row++, col].Value = item;
1745        }
1746      }
1747      else
1748      {
1749        foreach (var item in Collection)
1750        {
1751          col = _fromCol;
1752                    if (item is string || item is decimal || item is DateTime || item.GetType().IsPrimitive)
1753                    {
1754                        _worksheet.Cells[row, col++].Value = item;
1755                    }
1756                    else
1757                    {
1758                        foreach (var t in Members)
1759                        {
1760                            if (t is PropertyInfo)
1761                            {
1762                                _worksheet.Cells[row, col++].Value = ((PropertyInfo)t).GetValue(item, null);
1763                            }
1764                            else if (t is FieldInfo)
1765                            {
1766                                _worksheet.Cells[row, col++].Value = ((FieldInfo)t).GetValue(item);
1767                            }
1768                            else if (t is MethodInfo)
1769                            {
1770                                _worksheet.Cells[row, col++].Value = ((MethodInfo)t).Invoke(item, null);
1771                            }
1772                        }
1773                    }
1774          row++;
1775        }
1776      }
1777
1778            var r = _worksheet.Cells[_fromRow, _fromCol, row - 1, Members.Length==0 ? col : col - 1];
1779
1780      if (TableStyle != TableStyles.None)
1781      {
1782        var tbl = _worksheet.Tables.Add(r, "");
1783        tbl.ShowHeader = PrintHeaders;
1784        tbl.TableStyle = TableStyle;
1785      }
1786      return r;
1787    }
1788    #endregion
1789    #region LoadFromText
1790    /// <summary>
1791    /// Loads a CSV text into a range starting from the top left cell.
1792    /// Default settings is Comma separation
1793    /// </summary>
1794    /// <param name="Text">The Text</param>
1795    /// <returns>The range containing the data</returns>
1796    public ExcelRangeBase LoadFromText(string Text)
1797    {
1798      return LoadFromText(Text, new ExcelTextFormat());
1799    }
1800    /// <summary>
1801    /// Loads a CSV text into a range starting from the top left cell.
1802    /// </summary>
1803    /// <param name="Text">The Text</param>
1804    /// <param name="Format">Information how to load the text</param>
1805    /// <returns>The range containing the data</returns>
1806    public ExcelRangeBase LoadFromText(string Text, ExcelTextFormat Format)
1807    {
1808            if (string.IsNullOrEmpty(Text))
1809            {
1810                var r = _worksheet.Cells[_fromRow, _fromCol];
1811                r.Value = "";
1812                return r;
1813            }
1814           
1815            if (Format == null) Format = new ExcelTextFormat();
1816
1817            string[] lines = Regex.Split(Text, Format.EOL);
1818      int row = _fromRow;
1819      int col = _fromCol;
1820      int maxCol = col;
1821      int lineNo = 1;
1822      foreach (string line in lines)
1823      {
1824        if (lineNo > Format.SkipLinesBeginning && lineNo <= lines.Length - Format.SkipLinesEnd)
1825        {
1826          col = _fromCol;
1827          string v = "";
1828          bool isText = false, isQualifier = false;
1829          int QCount = 0;
1830          foreach (char c in line)
1831          {
1832            if (Format.TextQualifier != 0 && c == Format.TextQualifier)
1833            {
1834              if (!isText && v != "")
1835              {
1836                throw (new Exception(string.Format("Invalid Text Qualifier in line : {0}", line)));
1837              }
1838              isQualifier = !isQualifier;
1839              QCount += 1;
1840              isText = true;
1841            }
1842            else
1843            {
1844                            if (QCount > 1 && !string.IsNullOrEmpty(v))
1845              {
1846                v += new string(Format.TextQualifier, QCount / 2);
1847              }
1848                            else if(QCount>2 && string.IsNullOrEmpty(v))
1849                            {
1850                                v += new string(Format.TextQualifier, (QCount-1) / 2);
1851                            }
1852
1853              if (isQualifier)
1854              {
1855                v += c;
1856              }
1857              else
1858              {
1859                if (c == Format.Delimiter)
1860                {
1861                  _worksheet.Cell(row, col).Value = ConvertData(Format, v, col - _fromCol, isText);
1862                  v = "";
1863                  isText = false;
1864                  col++;
1865                }
1866                else
1867                {
1868                  if (QCount % 2 == 1)
1869                  {
1870                    throw (new Exception(string.Format("Text delimiter is not closed in line : {0}", line)));
1871                  }
1872                  v += c;
1873                }
1874              }
1875              QCount = 0;
1876            }
1877          }
1878          if (QCount > 1)
1879          {
1880            v += new string(Format.TextQualifier, QCount / 2);
1881          }
1882
1883          _worksheet.Cell(row, col).Value = ConvertData(Format, v, col - _fromCol, isText);
1884          if (col > maxCol) maxCol = col;
1885          row++;
1886        }
1887        lineNo++;
1888      }
1889      return _worksheet.Cells[_fromRow, _fromCol, row - 1, maxCol];
1890    }
1891    /// <summary>
1892    /// Loads a CSV text into a range starting from the top left cell.
1893    /// </summary>
1894    /// <param name="Text">The Text</param>
1895    /// <param name="Format">Information how to load the text</param>
1896    /// <param name="TableStyle">Create a table with this style</param>
1897    /// <param name="FirstRowIsHeader">Use the first row as header</param>
1898    /// <returns></returns>
1899    public ExcelRangeBase LoadFromText(string Text, ExcelTextFormat Format, TableStyles TableStyle, bool FirstRowIsHeader)
1900    {
1901      var r = LoadFromText(Text, Format);
1902
1903      var tbl = _worksheet.Tables.Add(r, "");
1904      tbl.ShowHeader = FirstRowIsHeader;
1905      tbl.TableStyle = TableStyle;
1906
1907      return r;
1908    }
1909    /// <summary>
1910    /// Loads a CSV file into a range starting from the top left cell.
1911    /// </summary>
1912    /// <param name="TextFile">The Textfile</param>
1913    /// <returns></returns>
1914    public ExcelRangeBase LoadFromText(FileInfo TextFile)
1915    {
1916      return LoadFromText(File.ReadAllText(TextFile.FullName, Encoding.ASCII));
1917    }
1918    /// <summary>
1919    /// Loads a CSV file into a range starting from the top left cell.
1920    /// </summary>
1921    /// <param name="TextFile">The Textfile</param>
1922    /// <param name="Format">Information how to load the text</param>
1923    /// <returns></returns>
1924    public ExcelRangeBase LoadFromText(FileInfo TextFile, ExcelTextFormat Format)
1925    {
1926      return LoadFromText(File.ReadAllText(TextFile.FullName, Format.Encoding), Format);
1927    }
1928    /// <summary>
1929    /// Loads a CSV file into a range starting from the top left cell.
1930    /// </summary>
1931    /// <param name="TextFile">The Textfile</param>
1932    /// <param name="Format">Information how to load the text</param>
1933    /// <param name="TableStyle">Create a table with this style</param>
1934    /// <param name="FirstRowIsHeader">Use the first row as header</param>
1935    /// <returns></returns>
1936    public ExcelRangeBase LoadFromText(FileInfo TextFile, ExcelTextFormat Format, TableStyles TableStyle, bool FirstRowIsHeader)
1937    {
1938      return LoadFromText(File.ReadAllText(TextFile.FullName, Format.Encoding), Format, TableStyle, FirstRowIsHeader);
1939    }
1940    #endregion
1941    #region GetValue
1942    /// <summary>
1943    /// Get the strongly typed value of the cell.
1944    /// </summary>
1945    /// <typeparam name="T">The type</typeparam>
1946    /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns>
1947    public T GetValue<T>()
1948    {
1949      return _worksheet.GetTypedValue<T>(Value);
1950    }
1951    #endregion
1952    /// <summary>
1953    /// Get a range with an offset from the top left cell.
1954    /// The new range has the same dimensions as the current range
1955    /// </summary>
1956    /// <param name="RowOffset">Row Offset</param>
1957    /// <param name="ColumnOffset">Column Offset</param>
1958    /// <returns></returns>
1959    public ExcelRangeBase Offset(int RowOffset, int ColumnOffset)
1960    {
1961      if (_fromRow + RowOffset < 1 || _fromCol + ColumnOffset < 1 || _fromRow + RowOffset > ExcelPackage.MaxRows || _fromCol + ColumnOffset > ExcelPackage.MaxColumns)
1962      {
1963        throw (new ArgumentOutOfRangeException("Offset value out of range"));
1964      }
1965      string address = GetAddress(_fromRow + RowOffset, _fromCol + ColumnOffset, _toRow + RowOffset, _toCol + ColumnOffset);
1966      return new ExcelRangeBase(_worksheet, address);
1967    }
1968    /// <summary>
1969    /// Get a range with an offset from the top left cell.
1970    /// </summary>
1971    /// <param name="RowOffset">Row Offset</param>
1972    /// <param name="ColumnOffset">Column Offset</param>
1973    /// <param name="NumberOfRows">Number of rows. Minimum 1</param>
1974    /// <param name="NumberOfColumns">Number of colums. Minimum 1</param>
1975    /// <returns></returns>
1976    public ExcelRangeBase Offset(int RowOffset, int ColumnOffset, int NumberOfRows, int NumberOfColumns)
1977    {
1978      if (NumberOfRows < 1 || NumberOfColumns < 1)
1979      {
1980        throw (new Exception("Number of rows/columns must be greater than 0"));
1981      }
1982      NumberOfRows--;
1983      NumberOfColumns--;
1984      if (_fromRow + RowOffset < 1 || _fromCol + ColumnOffset < 1 || _fromRow + RowOffset > ExcelPackage.MaxRows || _fromCol + ColumnOffset > ExcelPackage.MaxColumns ||
1985         _fromRow + RowOffset + NumberOfRows < 1 || _fromCol + ColumnOffset + NumberOfColumns < 1 || _fromRow + RowOffset + NumberOfRows > ExcelPackage.MaxRows || _fromCol + ColumnOffset + NumberOfColumns > ExcelPackage.MaxColumns)
1986      {
1987        throw (new ArgumentOutOfRangeException("Offset value out of range"));
1988      }
1989      string address = GetAddress(_fromRow + RowOffset, _fromCol + ColumnOffset, _fromRow + RowOffset + NumberOfRows, _fromCol + ColumnOffset + NumberOfColumns);
1990      return new ExcelRangeBase(_worksheet, address);
1991    }
1992    /// <summary>
1993    /// Adds a new comment for the range.
1994    /// If this range contains more than one cell, the top left comment is returned by the method.
1995    /// </summary>
1996    /// <param name="Text"></param>
1997    /// <param name="Author"></param>
1998    /// <returns>A reference comment of the top left cell</returns>
1999    public ExcelComment AddComment(string Text, string Author)
2000    {
2001      //Check if any comments exists in the range and throw an exception
2002      _changePropMethod(Exists_Comment, null);
2003      //Create the comments
2004      _changePropMethod(Set_Comment, new string[] { Text, Author });
2005
2006
2007      return _worksheet.Comments[new ExcelCellAddress(_fromRow, _fromCol)];
2008    }
2009
2010    /// <summary>
2011    /// Copies the range of cells to an other range
2012    /// </summary>
2013    /// <param name="Destination">The start cell where the range will be copied.</param>
2014    public void Copy(ExcelRangeBase Destination)
2015    {
2016            bool sameWorkbook = Destination._worksheet.Workbook == _worksheet.Workbook;
2017            ExcelStyles sourceStyles = _worksheet.Workbook.Styles,
2018                                    styles = Destination._worksheet.Workbook.Styles;
2019            Dictionary<int, int> styleCashe = new Dictionary<int, int>();
2020
2021            //Delete all existing cells;           
2022            List<ExcelCell> newCells = new List<ExcelCell>();
2023            Dictionary<ulong, ExcelCell> mergedCells = new Dictionary<ulong, ExcelCell>();
2024            foreach (var cell in this)
2025            {
2026                //Clone the cell
2027                var copiedCell = (_worksheet._cells[GetCellID(_worksheet.SheetID, cell._fromRow, cell._fromCol)] as ExcelCell);
2028
2029                var newCell = copiedCell.Clone(Destination._worksheet,
2030                        Destination._fromRow + (copiedCell.Row - _fromRow),
2031                        Destination._fromCol + (copiedCell.Column - _fromCol));
2032
2033                newCell.MergeId = _worksheet.GetMergeCellId(copiedCell.Row, copiedCell.Column);
2034
2035                //If the formula is shared, remove the shared ID and set the formula for the cell.
2036                if (newCell._sharedFormulaID >= 0)
2037                {
2038                    newCell._sharedFormulaID = int.MinValue;
2039                    newCell.Formula = cell.Formula;
2040                }
2041
2042                if (!string.IsNullOrEmpty(newCell.Formula))
2043                {
2044                    newCell.Formula = ExcelCell.UpdateFormulaReferences(newCell.Formula, newCell.Row - copiedCell.Row, (newCell.Column - copiedCell.Column), 1, 1);
2045                }
2046
2047                //If its not the same workbook we must copy the styles to the new workbook.
2048                if (!sameWorkbook)
2049                {
2050                    if (styleCashe.ContainsKey(cell.StyleID))
2051                    {
2052                        newCell.StyleID = styleCashe[cell.StyleID];
2053                    }
2054                    else
2055                    {
2056                        newCell.StyleID = styles.CloneStyle(sourceStyles, cell.StyleID);
2057                        styleCashe.Add(cell.StyleID, newCell.StyleID);
2058                    }
2059                }
2060                newCells.Add(newCell);
2061                if (newCell.Merge) mergedCells.Add(newCell.CellID, newCell);
2062            }
2063
2064            //Now clear the destination.
2065            Destination.Offset(0, 0, (_toRow - _fromRow) + 1, (_toCol - _fromCol) + 1).Clear();
2066
2067            //And last add the new cells to the worksheet
2068            foreach (var cell in newCells)
2069            {
2070                Destination.Worksheet._cells.Add(cell);
2071            }
2072            //Add merged cells
2073            if (mergedCells.Count > 0)
2074            {
2075                List<ExcelAddressBase> mergedAddresses = new List<ExcelAddressBase>();
2076                foreach (var cell in mergedCells.Values)
2077                {
2078                    if (!IsAdded(cell, mergedAddresses))
2079                    {
2080                        int startRow = cell.Row, startCol = cell.Column, endRow = cell.Row, endCol = cell.Column + 1;
2081                        while (mergedCells.ContainsKey(ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)))
2082                        {
2083                            ExcelCell next = mergedCells[ExcelCell.GetCellID(Destination.Worksheet.SheetID, endRow, endCol)];
2084                            if (cell.MergeId != next.MergeId)
2085                            {
2086                                break;
2087                            }
2088                            endCol++;
2089                        }
2090
2091                        while (IsMerged(mergedCells, Destination.Worksheet, endRow, startCol, endCol - 1, cell))
2092                        {
2093                            endRow++;
2094                        }
2095
2096                        mergedAddresses.Add(new ExcelAddressBase(startRow, startCol, endRow - 1, endCol - 1));
2097                    }
2098                }
2099                Destination.Worksheet.MergedCells.List.AddRange((from r in mergedAddresses select r.Address));
2100            }
2101    }
2102
2103    private bool IsAdded(ExcelCell cell, List<ExcelAddressBase> mergedAddresses)
2104    {
2105            foreach (var address in mergedAddresses)
2106            {
2107                if (address.Collide(new ExcelAddressBase(cell.CellAddress)) == eAddressCollition.Inside)
2108                {
2109                    return true;
2110                }
2111            }
2112            return false;
2113    }
2114
2115    private bool IsMerged(Dictionary<ulong, ExcelCell> mergedCells, ExcelWorksheet worksheet, int row, int startCol, int endCol, ExcelCell cell)
2116    {
2117            for (int col = startCol; col <= endCol; col++)
2118            {
2119                if (!mergedCells.ContainsKey(ExcelCell.GetCellID(worksheet.SheetID, row, col)))
2120                {
2121                    return false;
2122                }
2123                else
2124                {
2125                    ExcelCell next = mergedCells[ExcelCell.GetCellID(worksheet.SheetID, row, col)];
2126                    if (cell.MergeId != next.MergeId)
2127                    {
2128                        return false;
2129                    }
2130                }
2131            }
2132            return true;
2133    }
2134
2135    /// <summary>
2136    /// Clear all cells
2137    /// </summary>
2138    public void Clear()
2139    {
2140      Delete(this);
2141    }
2142    /// <summary>
2143    /// Creates an array-formula.
2144    /// </summary>
2145    /// <param name="ArrayFormula">The formula</param>
2146    public void CreateArrayFormula(string ArrayFormula)
2147    {
2148      if (Addresses != null)
2149      {
2150        throw (new Exception("An Arrayformula can not have more than one address"));
2151      }
2152      Set_SharedFormula(ArrayFormula, this, true);
2153    }
2154    private void Delete(ExcelAddressBase Range)
2155    {
2156            DeleteCheckMergedCells(Range);
2157      //First find the start cell
2158            ulong startID = GetCellID(_worksheet.SheetID, Range._fromRow, Range._fromCol);
2159      int index = _worksheet._cells.IndexOf(startID);
2160      if (index < 0)
2161      {
2162        index = ~index;
2163      }
2164      ExcelCell cell;
2165      //int row=cell.Row, col=cell.Column;
2166      //Remove all cells in the range
2167      while (index < _worksheet._cells.Count)
2168      {
2169        cell = _worksheet._cells[index] as ExcelCell;
2170        if (cell.Row > Range._toRow || cell.Row == Range._toRow && cell.Column > Range._toCol)
2171        {
2172          break;
2173        }
2174        else
2175        {
2176          if (cell.Column >= Range._fromCol && cell.Column <= Range._toCol)
2177          {
2178            _worksheet._cells.Delete(cell.CellID);
2179          }
2180          else
2181          {
2182            index++;
2183          }
2184        }
2185      }
2186
2187      //Delete multi addresses as well
2188      if (Addresses != null)
2189      {
2190        foreach (var sub in Addresses)
2191        {
2192          Delete(sub);
2193        }
2194            }
2195        }
2196
2197        private void DeleteCheckMergedCells(ExcelAddressBase Range)
2198        {
2199            var removeItems = new List<string>();
2200            foreach (var addr in Worksheet.MergedCells)
2201            {
2202                var addrCol = Range.Collide(new ExcelAddress(Range.WorkSheet, addr));
2203                if (addrCol != eAddressCollition.No)
2204                {
2205                    if (addrCol == eAddressCollition.Inside)
2206                    {
2207                        removeItems.Add(addr);
2208                    }
2209                    else
2210                    {
2211                        throw (new InvalidOperationException("Can't remove/overwrite cells that are merged"));
2212                    }
2213                }
2214            }
2215            foreach (var item in removeItems)
2216            {
2217                Worksheet.MergedCells.Remove(item);
2218      }
2219    }
2220    #endregion
2221    #region IDisposable Members
2222
2223    public void Dispose()
2224    {
2225      //_worksheet = null;
2226    }
2227
2228    #endregion
2229    #region "Enumerator"
2230    int _index;
2231    ulong _toCellId;
2232    int _enumAddressIx;
2233    public IEnumerator<ExcelRangeBase> GetEnumerator()
2234    {
2235      Reset();
2236      return this;
2237    }
2238
2239    IEnumerator IEnumerable.GetEnumerator()
2240    {
2241      Reset();
2242      return this;
2243    }
2244
2245    /// <summary>
2246    /// The current range when enumerating
2247    /// </summary>
2248    public ExcelRangeBase Current
2249    {
2250      get
2251      {
2252        return new ExcelRangeBase(_worksheet, (_worksheet._cells[_index] as ExcelCell).CellAddress);
2253      }
2254    }
2255
2256    /// <summary>
2257    /// The current range when enumerating
2258    /// </summary>
2259    object IEnumerator.Current
2260    {
2261      get
2262      {
2263        return ((object)(new ExcelRangeBase(_worksheet, (_worksheet._cells[_index] as ExcelCell).CellAddress)));
2264      }
2265    }
2266
2267    public bool MoveNext()
2268    {
2269      _index++;
2270      if (_enumAddressIx == -1)
2271      {
2272        GetNextIndexEnum(_fromRow, _fromCol, _toRow, _toCol);
2273
2274        if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId)
2275        {
2276          if (Addresses == null)
2277          {
2278            return false;
2279          }
2280          else
2281          {
2282            _enumAddressIx++;
2283            GetStartIndexEnum(Addresses[0].Start.Row, Addresses[0].Start.Column, Addresses[0].End.Row, Addresses[0].End.Column);
2284            return MoveNext();
2285          }
2286        }
2287
2288      }
2289      else
2290      {
2291        GetNextIndexEnum(Addresses[_enumAddressIx].Start.Row, Addresses[_enumAddressIx].Start.Column, Addresses[_enumAddressIx].End.Row, Addresses[_enumAddressIx].End.Column);
2292        if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId)
2293        {
2294          if (++_enumAddressIx < Addresses.Count)
2295          {
2296            GetStartIndexEnum(Addresses[_enumAddressIx].Start.Row, Addresses[_enumAddressIx].Start.Column, Addresses[_enumAddressIx].End.Row, Addresses[_enumAddressIx].End.Column);
2297            MoveNext();
2298          }
2299          else
2300          {
2301            return false;
2302          }
2303        }
2304      }
2305      return true;
2306    }
2307
2308    public void Reset()
2309    {
2310      _enumAddressIx = -1;
2311      GetStartIndexEnum(_fromRow, _fromCol, _toRow, _toCol);
2312    }
2313
2314    private void GetNextIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
2315    {
2316      if (_index >= _worksheet._cells.Count) return;
2317      ExcelCell cell = _worksheet._cells[_index] as ExcelCell;
2318      while (cell.Column > toCol || cell.Column < fromCol)
2319      {
2320        if (cell.Column < fromCol)
2321        {
2322          _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row, fromCol));
2323        }
2324        else
2325        {
2326          _index = _worksheet._cells.IndexOf(ExcelAddress.GetCellID(_worksheet.SheetID, cell.Row + 1, fromCol));
2327        }
2328
2329        if (_index < 0)
2330        {
2331          _index = ~_index;
2332        }
2333        if (_index >= _worksheet._cells.Count || _worksheet._cells[_index].RangeID > _toCellId)
2334        {
2335          break;
2336        }
2337        cell = _worksheet._cells[_index] as ExcelCell;
2338      }
2339    }
2340
2341    private void GetStartIndexEnum(int fromRow, int fromCol, int toRow, int toCol)
2342    {
2343      _index = _worksheet._cells.IndexOf(ExcelCellBase.GetCellID(_worksheet.SheetID, fromRow, fromCol));
2344      _toCellId = ExcelCellBase.GetCellID(_worksheet.SheetID, toRow, toCol);
2345      if (_index < 0)
2346      {
2347        _index = ~_index;
2348      }
2349      _index--;
2350    }
2351    #endregion
2352    }
2353}
Note: See TracBrowser for help on using the repository browser.