Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/ExcelWorksheet.cs @ 12074

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

#2341: Added EPPlus-4.0.3 to ExtLibs

File size: 162.5 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           2011-11-02
30 * Jan Källman          Total rewrite               2010-03-01
31 * Jan Källman        License changed GPL-->LGPL  2011-12-27
32 *******************************************************************************/
33using System;
34using System.Xml;
35using System.Collections.Generic;
36using System.IO;
37using System.Configuration;
38using OfficeOpenXml.Drawing;
39using System.Diagnostics;
40using OfficeOpenXml.Style;
41using System.Globalization;
42using System.Text;
43using System.Security;
44using OfficeOpenXml.Drawing.Chart;
45using OfficeOpenXml.Style.XmlAccess;
46using System.Text.RegularExpressions;
47using OfficeOpenXml.Drawing.Vml;
48using OfficeOpenXml.Table;
49using OfficeOpenXml.DataValidation;
50using OfficeOpenXml.Table.PivotTable;
51using System.ComponentModel;
52using System.Drawing;
53using OfficeOpenXml.ConditionalFormatting;
54using OfficeOpenXml.Utils;
55using Ionic.Zip;
56using OfficeOpenXml.FormulaParsing.LexicalAnalysis;
57using OfficeOpenXml.FormulaParsing;
58using OfficeOpenXml.Packaging.Ionic.Zip;
59namespace OfficeOpenXml
60{
61    /// <summary>
62    /// Worksheet hidden enumeration
63    /// </summary>
64    public enum eWorkSheetHidden
65    {
66        /// <summary>
67        /// The worksheet is visible
68        /// </summary>
69        Visible,
70        /// <summary>
71        /// The worksheet is hidden but can be shown by the user via the user interface
72        /// </summary>
73        Hidden,
74        /// <summary>
75        /// The worksheet is hidden and cannot be shown by the user via the user interface
76        /// </summary>
77        VeryHidden
78    }
79    [Flags]
80    internal enum CellFlags
81    {
82        //Merged = 0x1,
83        RichText = 0x2,
84        SharedFormula = 0x4,
85        ArrayFormula = 0x8
86    }
87    /// <summary>
88    /// Represents an Excel Chartsheet and provides access to its properties and methods
89    /// </summary>
90    public class ExcelChartsheet : ExcelWorksheet
91    {
92        //ExcelDrawings draws;
93        public ExcelChartsheet(XmlNamespaceManager ns, ExcelPackage pck, string relID, Uri uriWorksheet, string sheetName, int sheetID, int positionID, eWorkSheetHidden hidden, eChartType chartType) :
94            base(ns, pck, relID, uriWorksheet, sheetName, sheetID, positionID, hidden)
95        {
96            this.Drawings.AddChart("Chart 1", chartType);
97        }
98        public ExcelChartsheet(XmlNamespaceManager ns, ExcelPackage pck, string relID, Uri uriWorksheet, string sheetName, int sheetID, int positionID, eWorkSheetHidden hidden) :
99            base(ns, pck, relID, uriWorksheet, sheetName, sheetID, positionID, hidden)
100        {
101        }
102        public ExcelChart Chart
103        {
104            get
105            {
106                return (ExcelChart)Drawings[0];
107            }
108        }
109    }
110    /// <summary>
111  /// Represents an Excel worksheet and provides access to its properties and methods
112  /// </summary>
113    public class ExcelWorksheet : XmlHelper, IDisposable
114  {
115        internal class Formulas
116        {
117            public Formulas(ISourceCodeTokenizer tokenizer)
118            {
119                _tokenizer = tokenizer;
120            }
121
122            private ISourceCodeTokenizer _tokenizer;
123            internal int Index { get; set; }
124            internal string Address { get; set; }
125            internal bool IsArray { get; set; }
126            public string Formula { get; set; }
127            public int StartRow { get; set; }
128            public int StartCol { get; set; }
129
130            private IEnumerable<Token> Tokens {get; set;}
131
132            internal string GetFormula(int row, int column, string worksheet)
133            {
134                if (StartRow == row && StartCol == column)
135                {
136                    return Formula;
137                }
138
139                if (Tokens == null)
140                {
141                    Tokens = _tokenizer.Tokenize(Formula, worksheet);
142                }
143               
144                string f = "";
145                foreach (var token in Tokens)
146                {
147                    if (token.TokenType == TokenType.ExcelAddress)
148                    {
149                        var a = new ExcelFormulaAddress(token.Value);
150                        f += a.GetOffset(row - StartRow, column - StartCol);
151                    }
152                    else
153                    {
154                        f += token.Value;
155                    }
156                }
157                return f;
158            }
159        }
160        /// <summary>
161        /// Collection containing merged cell addresses
162        /// </summary>
163        public class MergeCellsCollection : IEnumerable<string>
164        {
165            internal MergeCellsCollection()
166            {
167
168            }
169            internal CellStore<int> _cells = new CellStore<int>();
170            List<string> _list = new List<string>();
171            internal List<string> List { get {return _list;} }
172            public string this[int row, int column]
173            {
174                get
175                {
176                    int ix=-1;
177                    if (_cells.Exists(row, column, ref ix) && ix >= 0 && ix < List.Count)  //Fixes issue 15075
178                    {
179                        return List[ix];
180                    }
181                    else
182                    {
183                        return null;
184                    }
185                }
186            }
187            public string this[int index]
188            {
189                get
190                {
191                    return _list[index];
192                }
193            }
194            internal void Add(ExcelAddressBase address, bool doValidate)
195            {
196                int ix=0;
197
198                //Validate
199                if (doValidate && Validate(address) == false)
200                {
201                    throw(new ArgumentException("Can't merge and already merged range"));
202                }
203                lock(this)
204                {
205                    ix = _list.Count;
206                    _list.Add(address.Address);
207                    SetIndex(address, ix);
208                }
209            }
210
211            private bool Validate(ExcelAddressBase address)
212            {
213                int ix=0;
214                if(_cells.Exists(address._fromRow, address._fromCol, ref ix))
215                {
216                    if (ix>=0 && ix < _list.Count && _list[ix]!=null && address.Address == _list[ix])
217                    {
218                        return true;
219                    }
220                    else
221                    {
222                        return false;
223                    }
224                }
225               
226                var cse = new CellsStoreEnumerator<int>(_cells, address._fromRow, address._fromCol, address._toRow, address._toCol);
227                //cells
228                while(cse.Next())
229                {
230                    return false;
231                }
232                //Entire column
233                cse = new CellsStoreEnumerator<int>(_cells, 0, address._fromCol, 0, address._toCol);
234                while (cse.Next())
235                {
236                    return false;
237                }
238                //Entire row
239                cse = new CellsStoreEnumerator<int>(_cells, address._fromRow, 0, address._toRow, 0);
240                while (cse.Next())
241                {
242                    return false;
243                }
244                return true;
245            }
246
247            internal void SetIndex(ExcelAddressBase address, int ix)
248            {
249                if (address._fromRow == 1 && address._toRow == ExcelPackage.MaxRows) //Entire row
250                {
251                    for (int col = address._fromCol; col <= address._toCol; col++)
252                    {
253                        _cells.SetValue(0, col, ix);
254                    }
255                }
256                else if (address._fromCol == 1 && address._toCol == ExcelPackage.MaxColumns) //Entire row
257                {
258                    for (int row = address._fromRow; row <= address._toRow; row++)
259                    {
260                        _cells.SetValue(row, 0, ix);
261                    }
262                }
263                else
264                {
265                    for (int col = address._fromCol; col <= address._toCol; col++)
266                    {
267                        for (int row = address._fromRow; row <= address._toRow; row++)
268                        {
269                            _cells.SetValue(row, col, ix);
270                        }
271                    }
272                }
273            }
274            public int Count
275            {
276                get
277                {
278                    return _list.Count;
279                }
280            }
281            internal void Remove(string Item)
282            {
283                _list.Remove(Item);
284            }
285            #region IEnumerable<string> Members
286
287            public IEnumerator<string> GetEnumerator()
288            {
289                return _list.GetEnumerator();
290            }
291
292            #endregion
293
294            #region IEnumerable Members
295
296            System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
297            {
298                return _list.GetEnumerator();
299            }
300           
301            #endregion
302            internal void Delete(ExcelAddressBase Destination)
303            {
304                var cse = new CellsStoreEnumerator<int>(_cells, Destination._fromRow, Destination._fromCol, Destination._toRow, Destination._toCol);
305                var used=new HashSet<int>();
306                while(cse.Next())
307                {
308                    var v=cse.Value;
309                    if (!used.Contains(v) && _list[v]!=null)
310                    {
311                        var adr=new ExcelAddressBase(_list[v]);
312                        if (!(Destination.Collide(adr) == ExcelAddressBase.eAddressCollition.Inside || Destination.Collide(adr)==ExcelAddressBase.eAddressCollition.Equal))
313                        {
314                            throw(new InvalidOperationException(string.Format("Can't delete merged cells. A range is partly merged with the deleted range. {0}", adr._address)));
315                        }
316                        used.Add(v);
317                    }
318                }
319
320                _cells.Delete(Destination._fromRow, Destination._fromCol, Destination._toRow - Destination._fromRow + 1, Destination._toCol - Destination._fromCol + 1);
321                foreach(var i in used)
322                {
323                    _list[i] = null;
324                }
325            }
326        }
327        internal CellStore<object> _values;
328        internal CellStore<string> _types;
329        internal CellStore<int> _styles;
330        internal CellStore<object> _formulas;
331        internal FlagCellStore _flags;
332        internal CellStore<List<Token>> _formulaTokens;
333
334        internal CellStore<Uri> _hyperLinks;
335        internal CellStore<ExcelComment> _commentsStore;
336
337        internal Dictionary<int, Formulas> _sharedFormulas = new Dictionary<int, Formulas>();
338        internal int _minCol = ExcelPackage.MaxColumns;
339        internal int _maxCol = 0;
340        #region Worksheet Private Properties
341        internal ExcelPackage _package;
342    private Uri _worksheetUri;
343    private string _name;
344    private int _sheetID;
345        private int _positionID;
346    private string _relationshipID;
347    private XmlDocument _worksheetXml;
348        internal ExcelWorksheetView _sheetView;
349    internal ExcelHeaderFooter _headerFooter;
350        #endregion
351        #region ExcelWorksheet Constructor
352        /// <summary>
353        /// A worksheet
354        /// </summary>
355        /// <param name="ns">Namespacemanager</param>
356        /// <param name="excelPackage">Package</param>
357        /// <param name="relID">Relationship ID</param>
358        /// <param name="uriWorksheet">URI</param>
359        /// <param name="sheetName">Name of the sheet</param>
360        /// <param name="sheetID">Sheet id</param>
361        /// <param name="positionID">Position</param>
362        /// <param name="hide">hide</param>
363        public ExcelWorksheet(XmlNamespaceManager ns, ExcelPackage excelPackage, string relID,
364                              Uri uriWorksheet, string sheetName, int sheetID, int positionID,
365                              eWorkSheetHidden hide) :
366            base(ns, null)
367        {
368            SchemaNodeOrder = new string[] { "sheetPr", "tabColor", "outlinePr", "pageSetUpPr", "dimension", "sheetViews", "sheetFormatPr", "cols", "sheetData", "sheetProtection", "protectedRanges","scenarios", "autoFilter", "sortState", "dataConsolidate", "customSheetViews", "customSheetViews", "mergeCells", "phoneticPr", "conditionalFormatting", "dataValidations", "hyperlinks", "printOptions", "pageMargins", "pageSetup", "headerFooter", "linePrint", "rowBreaks", "colBreaks", "customProperties", "cellWatches", "ignoredErrors", "smartTags", "drawing", "legacyDrawing", "legacyDrawingHF", "picture", "oleObjects", "activeXControls", "webPublishItems", "tableParts" , "extLst" };
369            _package = excelPackage;   
370            _relationshipID = relID;
371            _worksheetUri = uriWorksheet;
372            _name = sheetName;
373            _sheetID = sheetID;
374            _positionID = positionID;
375            Hidden = hide;
376           
377            /**** Cellstore ****/
378            _values=new CellStore<object>();
379            _types = new CellStore<string>();
380            _styles = new CellStore<int>();
381            _formulas = new CellStore<object>();
382            _flags = new FlagCellStore();
383            _commentsStore = new CellStore<ExcelComment>();
384            _hyperLinks = new CellStore<Uri>();
385           
386            _names = new ExcelNamedRangeCollection(Workbook,this);
387            CreateXml();
388            TopNode = _worksheetXml.DocumentElement;
389        }
390
391        #endregion
392        /// <summary>
393        /// The Uri to the worksheet within the package
394        /// </summary>
395        internal Uri WorksheetUri { get { return (_worksheetUri); } }
396        /// <summary>
397        /// The Zip.ZipPackagePart for the worksheet within the package
398        /// </summary>
399        internal Packaging.ZipPackagePart Part { get { return (_package.Package.GetPart(WorksheetUri)); } }
400        /// <summary>
401        /// The ID for the worksheet's relationship with the workbook in the package
402        /// </summary>
403        internal string RelationshipID { get { return (_relationshipID); } }
404        /// <summary>
405        /// The unique identifier for the worksheet.
406        /// </summary>
407        internal int SheetID { get { return (_sheetID); } }
408        /// <summary>
409        /// The position of the worksheet.
410        /// </summary>
411        internal int PositionID { get { return (_positionID); } set { _positionID = value; } }
412    #region Worksheet Public Properties
413      /// <summary>
414        /// The index in the worksheets collection
415        /// </summary>
416        public int Index { get { return (_positionID); } }
417        /// <summary>
418        /// Address for autofilter
419        /// <seealso cref="ExcelRangeBase.AutoFilter" />       
420        /// </summary>
421        public ExcelAddressBase AutoFilterAddress
422        {
423            get
424            {
425                CheckSheetType();
426                string address = GetXmlNodeString("d:autoFilter/@ref");
427                if (address == "")
428                {
429                    return null;
430                }
431                else
432                {
433                    return new ExcelAddressBase(address);
434                }
435            }
436            internal set
437            {
438                CheckSheetType();
439                SetXmlNodeString("d:autoFilter/@ref", value.Address);
440            }
441        }
442
443        internal void CheckSheetType()
444        {
445            if (this is ExcelChartsheet)
446            {
447                throw (new NotSupportedException("This property or method is not supported for a Chartsheet"));
448            }
449        }
450
451    /// <summary>
452    /// Returns a ExcelWorksheetView object that allows you to set the view state properties of the worksheet
453    /// </summary>
454    public ExcelWorksheetView View
455    {
456      get
457      {
458        if (_sheetView == null)
459        {
460                    XmlNode node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager);
461                    if (node == null)
462                    {
463                        CreateNode("d:sheetViews/d:sheetView"); //this one shouls always exist. but check anyway
464                        node = TopNode.SelectSingleNode("d:sheetViews/d:sheetView", NameSpaceManager);
465                    }
466                    _sheetView = new ExcelWorksheetView(NameSpaceManager, node, this);
467        }
468        return (_sheetView);
469      }
470    }
471
472    /// <summary>
473    /// The worksheet's display name as it appears on the tab
474    /// </summary>
475    public string Name
476    {
477      get { return (_name); }
478      set
479      {
480                if (value == _name) return;
481                value=_package.Workbook.Worksheets.ValidateFixSheetName(value);
482                foreach(var ws in Workbook.Worksheets)
483                {
484                    if(ws.PositionID!=PositionID && ws.Name.Equals(value,StringComparison.InvariantCultureIgnoreCase))
485                    {
486                        throw (new ArgumentException("Worksheet name must be unique"));
487                    }
488                }
489                _package.Workbook.SetXmlNodeString(string.Format("d:sheets/d:sheet[@sheetId={0}]/@name", _sheetID), value);
490                ChangeNames(value);
491
492                _name = value;
493            }
494    }
495
496        private void ChangeNames(string value)
497        {
498            //Renames name in this Worksheet;
499            foreach (var n in Workbook.Names)
500            {
501                if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue==null)
502                {
503                    n.ChangeWorksheet(_name, value);
504                }
505            }
506            foreach (var ws in Workbook.Worksheets)
507            {
508                if (!(ws is ExcelChartsheet))
509                {
510                    foreach (var n in ws.Names)
511                    {
512                        if (string.IsNullOrEmpty(n.NameFormula) && n.NameValue == null)
513                        {
514                            n.ChangeWorksheet(_name, value);
515                        }
516                    }
517                }
518            }
519        }
520        internal ExcelNamedRangeCollection _names;
521        /// <summary>
522        /// Provides access to named ranges
523        /// </summary>
524        public ExcelNamedRangeCollection Names
525        {
526            get
527            {
528                CheckSheetType();
529                return _names;
530            }
531        }
532    /// <summary>
533    /// Indicates if the worksheet is hidden in the workbook
534    /// </summary>
535    public eWorkSheetHidden Hidden
536    {
537      get
538            {
539                string state=_package.Workbook.GetXmlNodeString(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID));
540                if (state == "hidden")
541                {
542                    return eWorkSheetHidden.Hidden;
543                }
544                else if (state == "veryHidden")
545                {
546                    return eWorkSheetHidden.VeryHidden;
547                }
548                return eWorkSheetHidden.Visible;
549            }
550      set
551      {
552                    if (value == eWorkSheetHidden.Visible)
553                    {
554                        _package.Workbook.DeleteNode(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID));
555                    }
556                    else
557                    {
558                        string v;
559                        v=value.ToString();                       
560                        v=v.Substring(0,1).ToLower(CultureInfo.InvariantCulture)+v.Substring(1);
561                        _package.Workbook.SetXmlNodeString(string.Format("d:sheets/d:sheet[@sheetId={0}]/@state", _sheetID),v );
562                    }
563        }
564    }
565        double _defaultRowHeight = double.NaN;
566        /// <summary>
567    /// Get/set the default height of all rows in the worksheet
568    /// </summary>
569        public double DefaultRowHeight
570    {
571      get
572      {
573                CheckSheetType();
574                if (double.IsNaN(_defaultRowHeight))
575                {
576                    _defaultRowHeight = GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight");
577                    if(double.IsNaN(_defaultRowHeight))
578                    {
579                        _defaultRowHeight = 15; // Excel default height
580                    }
581                }
582        return _defaultRowHeight;
583      }
584      set
585      {
586                CheckSheetType();
587                _defaultRowHeight = value;
588                SetXmlNodeString("d:sheetFormatPr/@defaultRowHeight", value.ToString(CultureInfo.InvariantCulture));
589                SetXmlNodeBool("d:sheetFormatPr/@customHeight", value != 15);
590
591                if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth")))
592                {
593                    DefaultColWidth = 9.140625;
594                }
595      }
596    }
597        /// <summary>
598        /// Get/set the default width of all rows in the worksheet
599        /// </summary>
600        public double DefaultColWidth
601        {
602            get
603            {
604                CheckSheetType();
605                double ret = GetXmlNodeDouble("d:sheetFormatPr/@defaultColWidth");
606                if (double.IsNaN(ret))
607                {
608                    ret = 9.140625; // Excel's default width
609                }
610                return ret;
611            }
612            set
613            {
614                CheckSheetType();
615                SetXmlNodeString("d:sheetFormatPr/@defaultColWidth", value.ToString(CultureInfo.InvariantCulture));
616
617                if (double.IsNaN(GetXmlNodeDouble("d:sheetFormatPr/@defaultRowHeight")))
618                {
619                    DefaultRowHeight = 15;
620                }
621            }
622        }
623        /** <outlinePr applyStyles="1" summaryBelow="0" summaryRight="0" /> **/
624        const string outLineSummaryBelowPath = "d:sheetPr/d:outlinePr/@summaryBelow";
625        /// <summary>
626        /// Summary rows below details
627        /// </summary>
628        public bool OutLineSummaryBelow
629        {
630            get
631            {
632                CheckSheetType();
633                return GetXmlNodeBool(outLineSummaryBelowPath);
634            }
635            set
636            {
637                CheckSheetType();
638                SetXmlNodeString(outLineSummaryBelowPath, value ? "1" : "0");
639            }
640        }
641        const string outLineSummaryRightPath = "d:sheetPr/d:outlinePr/@summaryRight";
642        /// <summary>
643        /// Summary rows to right of details
644        /// </summary>
645        public bool OutLineSummaryRight
646        {
647            get
648            {
649                CheckSheetType();
650                return GetXmlNodeBool(outLineSummaryRightPath);
651            }
652            set
653            {
654                CheckSheetType();
655                SetXmlNodeString(outLineSummaryRightPath, value ? "1" : "0");
656            }
657        }
658        const string outLineApplyStylePath = "d:sheetPr/d:outlinePr/@applyStyles";
659        /// <summary>
660        /// Automatic styles
661        /// </summary>
662        public bool OutLineApplyStyle
663        {
664            get
665            {
666                CheckSheetType();
667                return GetXmlNodeBool(outLineApplyStylePath);
668            }
669            set
670            {
671                CheckSheetType();
672                SetXmlNodeString(outLineApplyStylePath, value ? "1" : "0");
673            }
674        }
675        const string tabColorPath = "d:sheetPr/d:tabColor/@rgb";
676        /// <summary>
677        /// Color of the sheet tab
678        /// </summary>
679        public Color TabColor
680        {
681            get
682            {
683                string col = GetXmlNodeString(tabColorPath);
684                if (col == "")
685                {
686                    return Color.Empty;
687                }
688                else
689                {
690                    return Color.FromArgb(int.Parse(col, System.Globalization.NumberStyles.AllowHexSpecifier));
691                }
692            }
693            set
694            {
695                SetXmlNodeString(tabColorPath, value.ToArgb().ToString("X"));
696            }
697        }
698        const string codeModuleNamePath = "d:sheetPr/@codeName";
699        internal string CodeModuleName
700        {
701            get
702            {
703                return GetXmlNodeString(codeModuleNamePath);
704            }
705            set
706            {
707                SetXmlNodeString(codeModuleNamePath, value);
708            }
709        }
710        internal void CodeNameChange(string value)
711        {
712            CodeModuleName = value;
713        }
714        public VBA.ExcelVBAModule CodeModule
715        {
716            get
717            {
718                if (_package.Workbook.VbaProject != null)
719                {
720                    return _package.Workbook.VbaProject.Modules[CodeModuleName];
721                }
722                else
723                {
724                    return null;
725                }
726            }
727        }
728        #region WorksheetXml
729    /// <summary>
730    /// The XML document holding the worksheet data.
731        /// All column, row, cell, pagebreak, merged cell and hyperlink-data are loaded into memory and removed from the document when loading the document.       
732    /// </summary>
733    public XmlDocument WorksheetXml
734    {
735      get
736      {
737        return (_worksheetXml);
738      }
739    }
740        internal ExcelVmlDrawingCommentCollection _vmlDrawings = null;
741        /// <summary>
742        /// Vml drawings. underlaying object for comments
743        /// </summary>
744        internal ExcelVmlDrawingCommentCollection VmlDrawingsComments
745        {
746            get
747            {
748                if (_vmlDrawings == null)
749                {
750                    CreateVmlCollection();
751                }
752                return _vmlDrawings;
753            }
754        }
755        internal ExcelCommentCollection _comments = null;
756        /// <summary>
757        /// Collection of comments
758        /// </summary>
759        public ExcelCommentCollection Comments
760        {
761            get
762            {
763                CheckSheetType();
764                if (_comments == null)
765                {
766                    CreateVmlCollection();
767                    _comments = new ExcelCommentCollection(_package, this, NameSpaceManager);
768                }
769                return _comments;
770            }
771        }
772        private void CreateVmlCollection()
773        {
774            var vmlNode = _worksheetXml.DocumentElement.SelectSingleNode("d:legacyDrawing/@r:id", NameSpaceManager);
775            if (vmlNode == null)
776            {
777                _vmlDrawings = new ExcelVmlDrawingCommentCollection(_package, this, null);
778            }
779            else
780            {
781                if (Part.RelationshipExists(vmlNode.Value))
782                {
783                    var rel = Part.GetRelationship(vmlNode.Value);
784                    var vmlUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
785
786                    _vmlDrawings = new ExcelVmlDrawingCommentCollection(_package, this, vmlUri);
787                    _vmlDrawings.RelId = rel.Id;
788                }
789            }
790        }
791
792        private void CreateXml()
793        {
794            _worksheetXml = new XmlDocument();
795            _worksheetXml.PreserveWhitespace = ExcelPackage.preserveWhitespace;
796            Packaging.ZipPackagePart packPart = _package.Package.GetPart(WorksheetUri);
797            string xml = "";
798
799            // First Columns, rows, cells, mergecells, hyperlinks and pagebreakes are loaded from a xmlstream to optimize speed...
800            bool doAdjust = _package.DoAdjustDrawings;
801            _package.DoAdjustDrawings = false;
802            Stream stream = packPart.GetStream();
803
804            XmlTextReader xr = new XmlTextReader(stream);
805            xr.ProhibitDtd = true;
806            xr.WhitespaceHandling = WhitespaceHandling.None;
807            LoadColumns(xr);    //columnXml
808            long start = stream.Position;
809            LoadCells(xr);
810            var nextElementLength = GetAttributeLength(xr);
811            long end = stream.Position - nextElementLength;
812            LoadMergeCells(xr);
813            LoadHyperLinks(xr);
814            LoadRowPageBreakes(xr);
815            LoadColPageBreakes(xr);
816            //...then the rest of the Xml is extracted and loaded into the WorksheetXml document.
817            stream.Seek(0, SeekOrigin.Begin);
818            Encoding encoding;
819            xml = GetWorkSheetXml(stream, start, end, out encoding);
820
821            //first char is invalid sometimes??
822            if (xml[0] != '<')
823                LoadXmlSafe(_worksheetXml, xml.Substring(1, xml.Length - 1), encoding);
824            else
825                LoadXmlSafe(_worksheetXml, xml, encoding);
826
827            _package.DoAdjustDrawings = doAdjust;
828            ClearNodes();
829        }
830        /// <summary>
831        /// Get the lenth of the attributes
832        /// Conditional formatting attributes can be extremly long som get length of the attributes to finetune position.
833        /// </summary>
834        /// <param name="xr"></param>
835        /// <returns></returns>
836        private int GetAttributeLength(XmlTextReader xr)
837        {
838            if (xr.NodeType != XmlNodeType.Element) return 0;
839            var length = 0;
840           
841            for (int i = 0; i < xr.AttributeCount; i++)
842            {
843                var a=xr.GetAttribute(i);
844                length += string.IsNullOrEmpty(a) ? 0 : a.Length;
845            }
846            return length;
847        }
848        private void LoadRowPageBreakes(XmlTextReader xr)
849        {
850            if(!ReadUntil(xr, "rowBreaks","colBreaks")) return;
851            while (xr.Read())
852            {
853                if (xr.LocalName == "brk")
854                {
855                    if (xr.NodeType == XmlNodeType.Element)
856                    {
857                        int id;
858                        if (int.TryParse(xr.GetAttribute("id"), out id))
859                        {
860                            Row(id).PageBreak = true;
861                        }   
862                    }
863                }
864                else
865                {
866                    break;
867                }
868            }
869        }
870        private void LoadColPageBreakes(XmlTextReader xr)
871        {
872            if (!ReadUntil(xr, "colBreaks")) return;
873            while (xr.Read())
874            {
875                if (xr.LocalName == "brk")
876                {
877                    if (xr.NodeType == XmlNodeType.Element)
878                    {
879                        int id;
880                        if (int.TryParse(xr.GetAttribute("id"), out id))
881                        {
882                            Column(id).PageBreak = true;
883                        }
884                    }
885                }
886                else
887                {
888                    break;
889                }
890            }
891        }
892
893        private void ClearNodes()
894        {
895            if (_worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager)!=null)
896            {
897                _worksheetXml.SelectSingleNode("//d:cols", NameSpaceManager).RemoveAll();
898            }
899            if (_worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager) != null)
900            {
901                _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager).RemoveAll();
902            }
903            if (_worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager) != null)
904            {
905                _worksheetXml.SelectSingleNode("//d:hyperlinks", NameSpaceManager).RemoveAll();
906            }
907            if (_worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager) != null)
908            {
909                _worksheetXml.SelectSingleNode("//d:rowBreaks", NameSpaceManager).RemoveAll();
910            }
911            if (_worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager) != null)
912            {
913                _worksheetXml.SelectSingleNode("//d:colBreaks", NameSpaceManager).RemoveAll();
914            }
915        }
916        const int BLOCKSIZE=8192;
917        private string GetWorkSheetXml(Stream stream, long start, long end, out Encoding encoding)
918        {
919            StreamReader sr = new StreamReader(stream);
920            int length = 0;
921            char[] block;
922            int pos;
923            StringBuilder sb = new StringBuilder();           
924            Match startmMatch, endMatch;
925            do
926            {
927                int size = stream.Length < BLOCKSIZE ? (int)stream.Length : BLOCKSIZE;
928                block = new char[size];
929                pos = sr.ReadBlock(block, 0, size);                 
930                sb.Append(block,0,pos);
931                length += size;
932            }
933            while (length < start + 20 && length < end);
934            startmMatch = Regex.Match(sb.ToString(), string.Format("(<[^>]*{0}[^>]*>)", "sheetData"));
935            if (!startmMatch.Success) //Not found
936            {
937                encoding = sr.CurrentEncoding;
938                return sb.ToString();
939            }
940            else
941            {
942                string s = sb.ToString();
943                string xml = s.Substring(0, startmMatch.Index);
944                if(startmMatch.Value.EndsWith("/>"))
945                {
946                    xml += s.Substring(startmMatch.Index, s.Length - startmMatch.Index);
947                }
948                else
949                {
950                    if (sr.Peek() != -1)
951                    {
952                        /**** Fixes issue 14788. Fix by Philip Garrett ****/
953                        long endSeekStart = end;
954
955                        while (endSeekStart >= 0)
956                        {
957                            endSeekStart = Math.Max(endSeekStart - BLOCKSIZE, 0);
958                            int size = (int)(end - endSeekStart);
959                            stream.Seek(endSeekStart, SeekOrigin.Begin);
960                            block = new char[size];
961                            sr = new StreamReader(stream);
962                            pos = sr.ReadBlock(block, 0, size);
963                            sb = new StringBuilder();
964                            sb.Append(block, 0, pos);
965                            s = sb.ToString();
966                            endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData"));
967                            if (endMatch.Success)
968                            {
969                                break;
970                            }
971                        }
972                    }
973                    endMatch = Regex.Match(s, string.Format("(</[^>]*{0}[^>]*>)", "sheetData"));
974                    xml += "<sheetData/>" + s.Substring(endMatch.Index + endMatch.Length, s.Length - (endMatch.Index + endMatch.Length));
975                }
976                if (sr.Peek() > -1)
977                {
978                    xml += sr.ReadToEnd();
979                }
980               
981                encoding = sr.CurrentEncoding;
982                return xml;
983            }
984        }
985        private void GetBlockPos(string xml, string tag, ref int start, ref int end)
986        {
987            Match startmMatch, endMatch;
988            startmMatch = Regex.Match(xml.Substring(start), string.Format("(<[^>]*{0}[^>]*>)", tag)); //"<[a-zA-Z:]*" + tag + "[?]*>");
989
990            if (!startmMatch.Success) //Not found
991            {
992                start = -1;
993                end = -1;
994                return;
995            }
996            var startPos=startmMatch.Index+start;
997            if(startmMatch.Value.Substring(startmMatch.Value.Length-2,1)=="/")
998            {
999                end = startPos + startmMatch.Length;
1000            }
1001            else
1002            {
1003                endMatch = Regex.Match(xml.Substring(start), string.Format("(</[^>]*{0}[^>]*>)", tag));
1004                if (endMatch.Success)
1005                {
1006                    end = endMatch.Index + endMatch.Length + start;
1007                }
1008            }
1009            start = startPos;
1010        }
1011        private bool ReadUntil(XmlTextReader xr,params string[] tagName)
1012        {
1013            if (xr.EOF) return false;
1014            while (!Array.Exists(tagName, tag => xr.LocalName.EndsWith(tag)))
1015            {
1016                xr.Read();
1017                if (xr.EOF) return false;
1018            }
1019            return (xr.LocalName.EndsWith(tagName[0]));
1020        }
1021        private void LoadColumns (XmlTextReader xr)//(string xml)
1022        {
1023            var colList = new List<IRangeID>();
1024            if (ReadUntil(xr, "cols", "sheetData"))
1025            {
1026            //if (xml != "")
1027            //{
1028                //var xr=new XmlTextReader(new StringReader(xml));
1029                while(xr.Read())
1030                {
1031                    if (xr.NodeType == XmlNodeType.Whitespace) continue;
1032                    if (xr.LocalName != "col") break;
1033                    if (xr.NodeType == XmlNodeType.Element)
1034                    {
1035                        int min = int.Parse(xr.GetAttribute("min"));
1036
1037                        ExcelColumn col = new ExcelColumn(this, min);
1038
1039                        col.ColumnMax = int.Parse(xr.GetAttribute("max"));
1040                        col.Width = xr.GetAttribute("width") == null ? 0 : double.Parse(xr.GetAttribute("width"), CultureInfo.InvariantCulture);
1041                            col.BestFit = xr.GetAttribute("bestFit") != null && xr.GetAttribute("bestFit") == "1" ? true : false;
1042                            col.Collapsed = xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed") == "1" ? true : false;
1043                            col.Phonetic = xr.GetAttribute("phonetic") != null && xr.GetAttribute("phonetic") == "1" ? true : false;
1044                        col.OutlineLevel = (short)(xr.GetAttribute("outlineLevel") == null ? 0 : int.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture));
1045                            col.Hidden = xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false;
1046                        _values.SetValue(0, min, col);
1047                   
1048                        int style;
1049                        if (!(xr.GetAttribute("style") == null || !int.TryParse(xr.GetAttribute("style"), out style)))
1050                        {
1051                            _styles.SetValue(0, min, style);
1052                        }
1053                    }
1054                }
1055            }
1056        }
1057        /// <summary>
1058        /// Read until the node is found. If not found the xmlreader is reseted.
1059        /// </summary>
1060        /// <param name="xr">The reader</param>
1061        /// <param name="nodeText">Text to search for</param>
1062        /// <param name="altNode">Alternative text to search for</param>
1063        /// <returns></returns>
1064        private static bool ReadXmlReaderUntil(XmlTextReader xr, string nodeText, string altNode)
1065        {
1066            do
1067            {
1068                if (xr.LocalName == nodeText || xr.LocalName == altNode) return true;
1069            }
1070            while(xr.Read());
1071            xr.Close();
1072            return false;
1073        }
1074        /// <summary>
1075        /// Load Hyperlinks
1076        /// </summary>
1077        /// <param name="xr">The reader</param>
1078        private void LoadHyperLinks(XmlTextReader xr)
1079        {
1080            if (!ReadUntil(xr, "hyperlinks", "rowBreaks", "colBreaks")) return;
1081            while (xr.Read())
1082            {
1083                if (xr.LocalName == "hyperlink")
1084                {
1085                    int fromRow, fromCol, toRow, toCol;
1086                    ExcelCellBase.GetRowColFromAddress(xr.GetAttribute("ref"), out fromRow, out fromCol, out toRow, out toCol);
1087                    ExcelHyperLink hl = null;
1088                    if (xr.GetAttribute("id", ExcelPackage.schemaRelationships) != null)
1089                    {
1090                        var rId = xr.GetAttribute("id", ExcelPackage.schemaRelationships);
1091                        var uri = Part.GetRelationship(rId).TargetUri;
1092                        if (uri.IsAbsoluteUri)
1093                        {
1094                            try
1095                            {
1096                                hl = new ExcelHyperLink(uri.AbsoluteUri);
1097                            }
1098                            catch
1099                            {
1100                                hl = new ExcelHyperLink(uri.OriginalString, UriKind.Absolute);
1101                            }
1102                        }
1103                        else
1104                        {
1105                            hl = new ExcelHyperLink(uri.OriginalString, UriKind.Relative);
1106                        }
1107                        hl.RId = rId;
1108                        Part.DeleteRelationship(rId); //Delete the relationship, it is recreated when we save the package.
1109                    }
1110                    else if (xr.GetAttribute("location") != null)
1111                    {
1112                        hl = new ExcelHyperLink(xr.GetAttribute("location"), xr.GetAttribute("display"));
1113                        hl.RowSpann = toRow - fromRow;
1114                        hl.ColSpann = toCol - fromCol;
1115                    }
1116
1117                    string tt = xr.GetAttribute("tooltip");
1118                    if (!string.IsNullOrEmpty(tt))
1119                    {
1120                        hl.ToolTip = tt;
1121                    }
1122                    _hyperLinks.SetValue(fromRow, fromCol, hl);
1123                }
1124                else
1125                {
1126                    break;
1127                }
1128            }
1129        }
1130        /// <summary>
1131        /// Load cells
1132        /// </summary>
1133        /// <param name="xr">The reader</param>
1134        private void LoadCells(XmlTextReader xr)
1135        {
1136            //var cellList=new List<IRangeID>();
1137            //var rowList = new List<IRangeID>();
1138            //var formulaList = new List<IRangeID>();
1139            ReadUntil(xr, "sheetData", "mergeCells", "hyperlinks", "rowBreaks", "colBreaks");
1140            ExcelAddressBase address=null;
1141            string type="";
1142            int style=0;
1143            int row = 0;
1144            int col = 0;
1145            xr.Read();
1146           
1147            while (!xr.EOF)
1148            {
1149                while (xr.NodeType == XmlNodeType.EndElement)
1150                {
1151                    xr.Read();
1152                    continue;
1153                }               
1154                if (xr.LocalName == "row")
1155                {
1156                    var r = xr.GetAttribute("r");
1157                    if (r == null)
1158                    {
1159                        row++;
1160                    }
1161                    else
1162                    {
1163                        row = Convert.ToInt32(r);
1164                    }
1165
1166                    if (DoAddRow(xr))
1167                    {
1168                        _values.SetValue(row, 0, AddRow(xr, row));
1169                        if(xr.GetAttribute("s") != null)
1170                        {
1171                            _styles.SetValue(row, 0, int.Parse(xr.GetAttribute("s"), CultureInfo.InvariantCulture));
1172                        }
1173                    }
1174                    xr.Read();
1175                }
1176                else if (xr.LocalName == "c")
1177                {
1178                    //if (cell != null) cellList.Add(cell);
1179                    //cell = new ExcelCell(this, xr.GetAttribute("r"));
1180                    var r = xr.GetAttribute("r");
1181                    if (r == null)
1182                    {
1183                        //Handle cells with no reference
1184                        col++;
1185                        address = new ExcelAddressBase(row, col, row, col);
1186                    }
1187                    else
1188                    {
1189                        address = new ExcelAddressBase(r);
1190                        col = address._fromCol;
1191                    }
1192
1193                   
1194                    //Datetype
1195                    if (xr.GetAttribute("t") != null)
1196                    {
1197                        type=xr.GetAttribute("t");
1198                        _types.SetValue(address._fromRow, address._fromCol, type);
1199                    }
1200                    else
1201                    {
1202                        type="";
1203                    }
1204                    //Style
1205                    if(xr.GetAttribute("s") != null)
1206                    {
1207                        style=int.Parse(xr.GetAttribute("s"));
1208                        _styles.SetValue(address._fromRow, address._fromCol, style);
1209                        _values.SetValue(address._fromRow, address._fromCol, null); //TODO:Better Performance ??
1210                    }
1211                    else
1212                    {
1213                        style = 0;
1214                    }
1215                    xr.Read();
1216                }
1217                else if (xr.LocalName == "v")
1218                {
1219                    SetValueFromXml(xr, type, style, address._fromRow, address._fromCol);
1220                   
1221                    xr.Read();
1222                }
1223                else if (xr.LocalName == "f")
1224                {
1225                    string t = xr.GetAttribute("t");
1226                    if (t == null)
1227                    {
1228                        _formulas.SetValue(address._fromRow, address._fromCol, xr.ReadElementContentAsString());
1229                        _values.SetValue(address._fromRow, address._fromCol, null);
1230                        //formulaList.Add(cell);
1231                    }
1232                    else if (t == "shared")
1233                    {
1234
1235                        string si = xr.GetAttribute("si");
1236                        if (si != null)
1237                        {
1238                            var sfIndex = int.Parse(si);
1239                            _formulas.SetValue(address._fromRow, address._fromCol, sfIndex);
1240                            _values.SetValue(address._fromRow, address._fromCol, null);
1241                            string fAddress = xr.GetAttribute("ref");
1242                            string formula = xr.ReadElementContentAsString();
1243                            if (formula != "")
1244                            {
1245                                _sharedFormulas.Add(sfIndex, new Formulas(SourceCodeTokenizer.Default) { Index = sfIndex, Formula = formula, Address = fAddress, StartRow = address._fromRow, StartCol = address._fromCol });
1246                            }
1247                        }
1248                        else
1249                        {
1250                            xr.Read();  //Something is wrong in the sheet, read next
1251                        }
1252                    }
1253                    else if (t == "array") //TODO: Array functions are not support yet. Read the formula for the start cell only.
1254                    {
1255                        string aAddress = xr.GetAttribute("ref");
1256                        string formula = xr.ReadElementContentAsString();
1257                        var afIndex = GetMaxShareFunctionIndex(true);
1258                        _formulas.SetValue(address._fromRow, address._fromCol, afIndex);
1259                        _values.SetValue(address._fromRow, address._fromCol, null);
1260                        _sharedFormulas.Add(afIndex, new Formulas(SourceCodeTokenizer.Default) { Index = afIndex, Formula = formula, Address = aAddress, StartRow = address._fromRow, StartCol = address._fromCol, IsArray = true });
1261                    }
1262                    else // ??? some other type
1263                    {
1264                        xr.Read();  //Something is wrong in the sheet, read next
1265                    }
1266
1267                }
1268                else if (xr.LocalName == "is")   //Inline string
1269                {
1270                    xr.Read();
1271                    if (xr.LocalName == "t")
1272                    {
1273                        _values.SetValue(address._fromRow, address._fromCol, xr.ReadInnerXml());
1274                        //cell._value = xr.ReadInnerXml();
1275                    }
1276                    else
1277                    {
1278                        _values.SetValue(address._fromRow, address._fromCol, xr.ReadOuterXml());
1279                        _types.SetValue(address._fromRow, address._fromCol, "rt");
1280                        _flags.SetFlagValue(address._fromRow, address._fromCol, true, CellFlags.RichText);
1281                        //cell.IsRichText = true;
1282                    }
1283                }
1284                else
1285                {
1286                    break;
1287                }
1288            }
1289            //if (cell != null) cellList.Add(cell);
1290
1291            //_cells = new RangeCollection(cellList);
1292            //_rows = new RangeCollection(rowList);
1293            //_formulaCells = new RangeCollection(formulaList);
1294        }
1295
1296        private bool DoAddRow(XmlTextReader xr)
1297        {
1298            var c = xr.GetAttribute("r")==null ? 0:1;
1299            if (xr.GetAttribute("spans") != null)
1300            {
1301                c++;
1302            }
1303            return xr.AttributeCount > c;
1304        }
1305        /// <summary>
1306        /// Load merged cells
1307        /// </summary>
1308        /// <param name="xr"></param>
1309        private void LoadMergeCells(XmlTextReader xr)
1310        {
1311            if(ReadUntil(xr, "mergeCells", "hyperlinks", "rowBreaks", "colBreaks") && !xr.EOF)
1312            {
1313                while (xr.Read())
1314                {                   
1315                    if (xr.LocalName != "mergeCell") break;
1316                    if (xr.NodeType == XmlNodeType.Element)
1317                    {
1318                        string address = xr.GetAttribute("ref");
1319                        //int fromRow, fromCol, toRow, toCol;
1320                        //ExcelCellBase.GetRowColFromAddress(address, out fromRow, out fromCol, out toRow, out toCol);
1321                        //for (int row = fromRow; row <= toRow; row++)
1322                        //{
1323                        //    for (int col = fromCol; col <= toCol; col++)
1324                        //    {
1325                        //        _flags.SetFlagValue(row, col, true,CellFlags.Merged);
1326                        //    }
1327                        //}
1328                        //_mergedCells.List.Add(address);
1329                        _mergedCells.Add(new ExcelAddress(address), false);
1330                    }
1331                }
1332            }
1333        }
1334        /// <summary>
1335        /// Update merged cells
1336        /// </summary>
1337        /// <param name="sw">The writer</param>
1338        private void UpdateMergedCells(StreamWriter sw)
1339        {
1340            sw.Write("<mergeCells>");
1341            foreach (string address in _mergedCells)
1342            {
1343                sw.Write("<mergeCell ref=\"{0}\" />", address);
1344            }
1345            sw.Write("</mergeCells>");
1346        }
1347        /// <summary>
1348        /// Reads a row from the XML reader
1349        /// </summary>
1350        /// <param name="xr">The reader</param>
1351        /// <param name="row">The row number</param>
1352        /// <returns></returns>
1353        private RowInternal AddRow(XmlTextReader xr, int row)
1354        {
1355            return new RowInternal()
1356            {
1357                Collapsed=(xr.GetAttribute("collapsed") != null && xr.GetAttribute("collapsed")== "1" ? true : false),
1358                OutlineLevel = (xr.GetAttribute("outlineLevel") == null ? (short)0 : short.Parse(xr.GetAttribute("outlineLevel"), CultureInfo.InvariantCulture)),
1359                Height = (xr.GetAttribute("ht") == null ? -1 : double.Parse(xr.GetAttribute("ht"), CultureInfo.InvariantCulture)),
1360                Hidden = (xr.GetAttribute("hidden") != null && xr.GetAttribute("hidden") == "1" ? true : false),
1361                Phonetic = xr.GetAttribute("ph") != null && xr.GetAttribute("ph") == "1" ? true : false,
1362                CustomHeight = xr.GetAttribute("customHeight") == null ? false : xr.GetAttribute("customHeight")=="1"
1363            };
1364        }
1365
1366        private void SetValueFromXml(XmlTextReader xr, string type, int styleID, int row, int col)
1367        {
1368            //XmlNode vnode = colNode.SelectSingleNode("d:v", NameSpaceManager);
1369            //if (vnode == null) return null;
1370            if (type == "s")
1371            {
1372                int ix = xr.ReadElementContentAsInt();
1373                _values.SetValue(row, col, _package.Workbook._sharedStringsList[ix].Text);
1374                if (_package.Workbook._sharedStringsList[ix].isRichText)
1375                {
1376                    _flags.SetFlagValue(row, col, true, CellFlags.RichText);
1377                }               
1378            }
1379            else if (type == "str")
1380            {
1381                _values.SetValue(row, col, ConvertUtil.ExcelDecodeString(xr.ReadElementContentAsString()));
1382            }
1383            else if (type == "b")
1384            {
1385                _values.SetValue(row, col, (xr.ReadElementContentAsString()!="0"));
1386            }
1387            else if (type == "e")
1388            {
1389                _values.SetValue(row, col, GetErrorType(xr.ReadElementContentAsString()));
1390            }
1391            else
1392            {
1393                string v = xr.ReadElementContentAsString();
1394                var nf = Workbook.Styles.CellXfs[styleID].NumberFormatId;
1395                if ((nf >= 14 && nf <= 22) || (nf >= 45 && nf <= 47))
1396                {
1397                    double res;
1398                    if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out res))
1399                    {
1400                        if (Workbook.Date1904)
1401                        {
1402                            res += ExcelWorkbook.date1904Offset;
1403                        }
1404                        if (res >= -657435.0 && res < 2958465.9999999)
1405                        {
1406                            _values.SetValue(row, col, DateTime.FromOADate(res));
1407                        }
1408                        else
1409                        {
1410                            _values.SetValue(row, col, "");
1411                        }
1412                    }
1413                    else
1414                    {
1415                        _values.SetValue(row, col, "");
1416                    }
1417                }
1418                else
1419                {
1420                    double d;
1421                    if (double.TryParse(v, NumberStyles.Any, CultureInfo.InvariantCulture, out d))
1422                    {
1423                        _values.SetValue(row, col, d);
1424                    }
1425                    else
1426                    {
1427                        _values.SetValue(row, col, double.NaN);
1428                    }
1429                }
1430            }
1431        }
1432
1433        private object GetErrorType(string v)
1434        {
1435            return ExcelErrorValue.Parse(v.ToUpper(CultureInfo.InvariantCulture));
1436            //switch(v.ToUpper())
1437            //{
1438            //    case "#DIV/0!":
1439            //        return new ExcelErrorValue.cre(eErrorType.Div0);
1440            //    case "#REF!":
1441            //        return new ExcelErrorValue(eErrorType.Ref);
1442            //    case "#N/A":
1443            //        return new ExcelErrorValue(eErrorType.NA);
1444            //    case "#NAME?":
1445            //        return new ExcelErrorValue(eErrorType.Name);
1446            //    case "#NULL!":
1447            //        return new ExcelErrorValue(eErrorType.Null);
1448            //    case "#NUM!":
1449            //        return new ExcelErrorValue(eErrorType.Num);
1450            //    default:
1451            //        return new ExcelErrorValue(eErrorType.Value);
1452            //}
1453        }
1454        //private string GetSharedString(int stringID)
1455        //{
1456        //    string retValue = null;
1457        //    XmlNodeList stringNodes = xlPackage.Workbook.SharedStringsXml.SelectNodes(string.Format("//d:si", stringID), NameSpaceManager);
1458        //    XmlNode stringNode = stringNodes[stringID];
1459        //    if (stringNode != null)
1460        //        retValue = stringNode.InnerText;
1461        //    return (retValue);
1462        //}
1463        #endregion
1464    #region HeaderFooter
1465    /// <summary>
1466    /// A reference to the header and footer class which allows you to
1467    /// set the header and footer for all odd, even and first pages of the worksheet
1468        /// </summary>
1469        /// <remarks>
1470        /// To format the text you can use the following format
1471        /// <list type="table">
1472        /// <listheader><term>Prefix</term><description>Description</description></listheader>
1473        /// <item><term>&amp;U</term><description>Underlined</description></item>
1474        /// <item><term>&amp;E</term><description>Double Underline</description></item>
1475        /// <item><term>&amp;K:xxxxxx</term><description>Color. ex &amp;K:FF0000 for red</description></item>
1476        /// <item><term>&amp;"Font,Regular Bold Italic"</term><description>Changes the font. Regular or Bold or Italic or Bold Italic can be used. ex &amp;"Arial,Bold Italic"</description></item>
1477        /// <item><term>&amp;nn</term><description>Change font size. nn is an integer. ex &amp;24</description></item>
1478        /// <item><term>&amp;G</term><description>Placeholder for images. Images can not be added by the library, but its possible to use in a template.</description></item>
1479        /// </list>
1480        /// </remarks>
1481        public ExcelHeaderFooter HeaderFooter
1482    {
1483      get
1484      {
1485        if (_headerFooter == null)
1486        {
1487                    XmlNode headerFooterNode = TopNode.SelectSingleNode("d:headerFooter", NameSpaceManager);
1488                    if (headerFooterNode == null)
1489                        headerFooterNode= CreateNode("d:headerFooter");
1490                    _headerFooter = new ExcelHeaderFooter(NameSpaceManager, headerFooterNode, this);
1491        }               
1492        return (_headerFooter);
1493      }
1494    }
1495    #endregion
1496
1497        #region "PrinterSettings"
1498        /// <summary>
1499        /// Printer settings
1500        /// </summary>
1501        public ExcelPrinterSettings PrinterSettings
1502        {
1503            get
1504            {
1505                var ps = new ExcelPrinterSettings(NameSpaceManager, TopNode, this);
1506                ps.SchemaNodeOrder = SchemaNodeOrder;
1507                return ps;
1508            }
1509        }
1510        #endregion
1511
1512    #endregion // END Worksheet Public Properties
1513
1514    #region Worksheet Public Methods
1515       
1516        ///// <summary>
1517        ///// Provides access to an individual cell within the worksheet.
1518        ///// </summary>
1519        ///// <param name="row">The row number in the worksheet</param>
1520        ///// <param name="col">The column number in the worksheet</param>
1521        ///// <returns></returns>   
1522        //internal ExcelCell Cell(int row, int col)
1523        //{
1524        //    return new ExcelCell(_values, row, col);
1525        //}
1526         /// <summary>
1527         /// Provides access to a range of cells
1528        /// </summary> 
1529        public ExcelRange Cells
1530        {
1531            get
1532            {
1533                CheckSheetType();
1534                return new ExcelRange(this, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
1535            }
1536        }
1537        /// <summary>
1538        /// Provides access to the selected range of cells
1539        /// </summary> 
1540        public ExcelRange SelectedRange
1541        {
1542            get
1543            {
1544                CheckSheetType();
1545                return new ExcelRange(this, View.SelectedRange);
1546            }
1547        }
1548        MergeCellsCollection _mergedCells = new MergeCellsCollection();
1549        /// <summary>
1550        /// Addresses to merged ranges
1551        /// </summary>
1552        public MergeCellsCollection MergedCells
1553        {
1554            get
1555            {
1556                CheckSheetType();
1557                return _mergedCells;
1558            }
1559        }
1560        /// <summary>
1561    /// Provides access to an individual row within the worksheet so you can set its properties.
1562    /// </summary>
1563    /// <param name="row">The row number in the worksheet</param>
1564    /// <returns></returns>
1565    public ExcelRow Row(int row)
1566    {
1567            //ExcelRow r;
1568            //ulong id = ExcelRow.GetRowID(_sheetID, row);
1569            //TODO: Fixa.
1570            //var v = _values.GetValue(row, 0);
1571            //if (v!=null)
1572            //{
1573            //    var ri=(RowInternal)v;
1574            //    r = new ExcelRow(this, row)
1575            //}
1576            //else
1577            //{
1578                //r = new ExcelRow(this, row);
1579                //_values.SetValue(row, 0, r);
1580                //_rows.Add(r);
1581            //}
1582            CheckSheetType();
1583            if (row < 1 || row > ExcelPackage.MaxRows)
1584            {
1585                throw (new ArgumentException("Row number out of bounds"));
1586            }
1587            return new ExcelRow(this, row);
1588            //return r;
1589    }
1590    /// <summary>
1591    /// Provides access to an individual column within the worksheet so you can set its properties.
1592    /// </summary>
1593    /// <param name="col">The column number in the worksheet</param>
1594    /// <returns></returns>
1595    public ExcelColumn Column(int col)
1596    {           
1597            CheckSheetType();
1598            if (col < 1 || col > ExcelPackage.MaxColumns)
1599            {
1600                throw (new ArgumentException("Column number out of bounds"));
1601            }
1602            var column = _values.GetValue(0, col) as ExcelColumn;
1603            if (column!=null)
1604            {               
1605               
1606                if (column.ColumnMin != column.ColumnMax)
1607                {
1608                    int maxCol = column.ColumnMax;
1609                    column.ColumnMax = col;
1610                    ExcelColumn copy = CopyColumn(column, col + 1, maxCol);
1611                }
1612            }
1613            else
1614            {
1615                int r=0, c=col;
1616                if (_values.PrevCell(ref r, ref c))
1617                {
1618                    column = _values.GetValue(0, c) as ExcelColumn;
1619                    int maxCol = column.ColumnMax;
1620                    if (maxCol >= col)
1621                    {
1622                        column.ColumnMax = col-1;
1623                        if (maxCol > col)
1624                        {
1625                            ExcelColumn newC = CopyColumn(column, col + 1, maxCol);
1626                        }
1627                        return CopyColumn(column, col, col);
1628                    }
1629                }
1630                //foreach (ExcelColumn checkColumn in _columns)
1631                //{
1632                //    if (col > checkColumn.ColumnMin && col <= checkColumn.ColumnMax)
1633                //    {
1634                //        int maxCol = checkColumn.ColumnMax;
1635                //        checkColumn.ColumnMax = col - 1;
1636                //        if (maxCol > col)
1637                //        {
1638                //            ExcelColumn newC = CopyColumn(checkColumn, col + 1, maxCol);
1639                //        }
1640                //        return CopyColumn(checkColumn, col,col);                       
1641                //    }
1642                //}
1643                column = new ExcelColumn(this, col);
1644                _values.SetValue(0, col, column);
1645                //_columns.Add(column);
1646             }
1647            return column;
1648    }
1649        /// <summary>
1650        /// Returns the name of the worksheet
1651        /// </summary>
1652        /// <returns>The name of the worksheet</returns>
1653        public override string ToString()
1654        {
1655            return Name;
1656        }
1657        internal ExcelColumn CopyColumn(ExcelColumn c, int col, int maxCol)
1658        {
1659            ExcelColumn newC = new ExcelColumn(this, col);
1660            newC.ColumnMax = maxCol < ExcelPackage.MaxColumns ? maxCol : ExcelPackage.MaxColumns;
1661            if (c.StyleName != "")
1662                newC.StyleName = c.StyleName;
1663            else
1664                newC.StyleID = c.StyleID;
1665
1666            newC._hidden = c.Hidden;
1667            newC.OutlineLevel = c.OutlineLevel;
1668            newC.Phonetic = c.Phonetic;
1669            newC.BestFit = c.BestFit;
1670            //_columns.Add(newC);
1671            _values.SetValue(0, col, newC);
1672            newC.Width = c._width;
1673            return newC;
1674       }
1675        /// <summary>
1676        /// Make the current worksheet active.
1677        /// </summary>
1678        public void Select()
1679        {
1680            View.TabSelected = true;
1681            //Select(Address, true);
1682        }
1683        /// <summary>
1684        /// Selects a range in the worksheet. The active cell is the topmost cell.
1685        /// Make the current worksheet active.
1686        /// </summary>
1687        /// <param name="Address">An address range</param>
1688        public void Select(string Address)
1689        {
1690            Select(Address, true);
1691        }
1692        /// <summary>
1693        /// Selects a range in the worksheet. The actice cell is the topmost cell.
1694        /// </summary>
1695        /// <param name="Address">A range of cells</param>
1696        /// <param name="SelectSheet">Make the sheet active</param>
1697        public void Select(string Address, bool SelectSheet)
1698        {
1699            CheckSheetType();
1700            int fromCol, fromRow, toCol, toRow;
1701            //Get rows and columns and validate as well
1702            ExcelCellBase.GetRowColFromAddress(Address, out fromRow, out fromCol, out toRow, out toCol);
1703
1704            if (SelectSheet)
1705            {
1706                View.TabSelected = true;
1707            }
1708            View.SelectedRange = Address;
1709            View.ActiveCell = ExcelCellBase.GetAddress(fromRow, fromCol);           
1710        }
1711        /// <summary>
1712        /// Selects a range in the worksheet. The active cell is the topmost cell of the first address.
1713        /// Make the current worksheet active.
1714        /// </summary>
1715        /// <param name="Address">An address range</param>
1716        public void Select(ExcelAddress Address)
1717        {
1718            CheckSheetType();
1719            Select(Address, true);
1720        }
1721        /// <summary>
1722        /// Selects a range in the worksheet. The active cell is the topmost cell of the first address.
1723        /// </summary>
1724        /// <param name="Address">A range of cells</param>
1725        /// <param name="SelectSheet">Make the sheet active</param>
1726        public void Select(ExcelAddress Address, bool SelectSheet)
1727        {
1728
1729            CheckSheetType();
1730            if (SelectSheet)
1731            {
1732                View.TabSelected = true;
1733            }
1734            string selAddress = ExcelCellBase.GetAddress(Address.Start.Row, Address.Start.Column) + ":" + ExcelCellBase.GetAddress(Address.End.Row, Address.End.Column);
1735            if (Address.Addresses != null)
1736            {
1737                foreach (var a in Address.Addresses)
1738                {
1739                    selAddress += " " + ExcelCellBase.GetAddress(a.Start.Row, a.Start.Column) + ":" + ExcelCellBase.GetAddress(a.End.Row, a.End.Column);
1740                }
1741            }
1742            View.SelectedRange = selAddress;
1743            View.ActiveCell = ExcelCellBase.GetAddress(Address.Start.Row, Address.Start.Column);
1744        }
1745
1746    #region InsertRow
1747        /// <summary>
1748        /// Inserts a new row into the spreadsheet.  Existing rows below the position are
1749        /// shifted down.  All formula are updated to take account of the new row.
1750        /// </summary>
1751        /// <param name="rowFrom">The position of the new row</param>
1752        /// <param name="rows">Number of rows to insert</param>
1753        public void InsertRow(int rowFrom, int rows)
1754        {
1755            InsertRow(rowFrom, rows, 0);
1756        }
1757        /// <summary>
1758    /// Inserts a new row into the spreadsheet.  Existing rows below the position are
1759    /// shifted down.  All formula are updated to take account of the new row.
1760    /// </summary>
1761        /// <param name="rowFrom">The position of the new row</param>
1762        /// <param name="rows">Number of rows to insert.</param>
1763        /// <param name="copyStylesFromRow">Copy Styles from this row. Applied to all inserted rows</param>
1764    public void  InsertRow(int rowFrom, int rows, int copyStylesFromRow)
1765    {
1766            CheckSheetType();
1767                var d = Dimension;
1768
1769            if (rowFrom < 1)
1770            {
1771                throw (new ArgumentOutOfRangeException("rowFrom can't be lesser that 1"));
1772            }
1773
1774            //Check that cells aren't shifted outside the boundries
1775            if (d != null && d.End.Row > rowFrom && d.End.Row + rows > ExcelPackage.MaxRows)
1776            {
1777                throw (new ArgumentOutOfRangeException("Can't insert. Rows will be shifted outside the boundries of the worksheet."));
1778            }
1779
1780            lock (this)
1781            {
1782                _values.Insert(rowFrom, 0, rows, 0);
1783                _formulas.Insert(rowFrom, 0, rows, 0);
1784                _styles.Insert(rowFrom, 0, rows, 0);
1785                _types.Insert(rowFrom, 0, rows, 0);
1786                _commentsStore.Insert(rowFrom, 0, rows, 0);
1787                _hyperLinks.Insert(rowFrom, 0, rows, 0);
1788                _flags.Insert(rowFrom, 0, rows, 0);
1789
1790                foreach (var f in _sharedFormulas.Values)
1791                {
1792                    if (f.StartRow >= rowFrom) f.StartRow += rows;
1793                    var a = new ExcelAddressBase(f.Address);
1794                    if (a._fromRow >= rowFrom)
1795                    {
1796                        a._fromRow += rows;
1797                        a._toRow += rows;
1798                    }
1799                    else if (a._toRow >= rowFrom)
1800                    {
1801                        a._toRow += rows;
1802                    }
1803                    f.Address = ExcelAddressBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
1804                    f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, rows, 0, rowFrom, 0);
1805                }
1806                var cse = new CellsStoreEnumerator<object>(_formulas);
1807                while (cse.Next())
1808                {
1809                    if (cse.Value is string)
1810                    {
1811                        cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), rows, 0, rowFrom, 0);
1812                    }
1813                }
1814
1815                FixMergedCellsRow(rowFrom, rows, false);
1816                if (copyStylesFromRow > 0)
1817                {
1818                    var cseS = new CellsStoreEnumerator<int>(_styles, copyStylesFromRow, 0, copyStylesFromRow, ExcelPackage.MaxColumns); //Fixes issue 15068 , 15090
1819                    while(cseS.Next())
1820                    {
1821                        for (var r = 0; r < rows; r++)
1822                        {
1823                            _styles.SetValue(rowFrom + r, cseS.Column, cseS.Value);
1824                        }
1825                    }
1826                }
1827                foreach (var tbl in Tables)
1828                {
1829                    tbl.Address = tbl.Address.AddRow(rowFrom, rows);
1830                }
1831            }
1832        }
1833        /// <summary>
1834        /// Inserts a new column into the spreadsheet.  Existing columns below the position are
1835        /// shifted down.  All formula are updated to take account of the new column.
1836        /// </summary>
1837        /// <param name="columnFrom">The position of the new column</param>
1838        /// <param name="columns">Number of columns to insert</param>       
1839        public void InsertColumn(int columnFrom, int columns)
1840        {
1841            InsertColumn(columnFrom, columns, 0);
1842        }
1843        ///<summary>
1844        /// Inserts a new column into the spreadsheet.  Existing column to the left are
1845        /// shifted.  All formula are updated to take account of the new column.
1846        /// </summary>
1847        /// <param name="columnFrom">The position of the new column</param>
1848        /// <param name="columns">Number of columns to insert.</param>
1849        /// <param name="copyStylesFromColumn">Copy Styles from this column. Applied to all inserted columns</param>
1850        public void InsertColumn(int columnFrom, int columns, int copyStylesFromColumn)
1851        {
1852            CheckSheetType();
1853            var d = Dimension;
1854
1855            if (columnFrom < 1)
1856            {
1857                throw (new ArgumentOutOfRangeException("columnFrom can't be lesser that 1"));
1858            }           
1859            //Check that cells aren't shifted outside the boundries
1860            if (d != null && d.End.Column > columnFrom && d.End.Column + columns > ExcelPackage.MaxColumns)
1861            {
1862                throw (new ArgumentOutOfRangeException("Can't insert. Columns will be shifted outside the boundries of the worksheet."));
1863            }
1864
1865            lock (this)
1866            {
1867                _values.Insert(0, columnFrom, 0, columns);
1868                _formulas.Insert(0, columnFrom, 0, columns);
1869                _styles.Insert(0, columnFrom, 0, columns);
1870                _types.Insert(0, columnFrom, 0, columns);
1871                _commentsStore.Insert(0, columnFrom, 0, columns);
1872                _hyperLinks.Insert(0, columnFrom, 0, columns);
1873                _flags.Insert(0, columnFrom, 0, columns);
1874
1875                foreach (var f in _sharedFormulas.Values)
1876                {
1877                    if (f.StartCol >= columnFrom) f.StartCol += columns;
1878                    var a = new ExcelAddressBase(f.Address);
1879                    if (a._fromCol >= columnFrom)
1880                    {
1881                        a._fromCol += columns;
1882                        a._toCol += columns;
1883                    }
1884                    else if (a._toCol >= columnFrom)
1885                    {
1886                        a._toCol += columns;
1887                    }
1888                    f.Address = ExcelAddressBase.GetAddress(a._fromRow, a._fromCol, a._toRow, a._toCol);
1889                    f.Formula = ExcelCellBase.UpdateFormulaReferences(f.Formula, 0, columns, 0, columnFrom);
1890                }
1891
1892                var cse = new CellsStoreEnumerator<object>(_formulas);
1893                while (cse.Next())
1894                {
1895                    if (cse.Value is string)
1896                    {
1897                        cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), 0, columns, 0, columnFrom);
1898                    }
1899                }
1900
1901                FixMergedCellsColumn(columnFrom, columns, false);
1902
1903                var csec = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
1904                var lst = new List<ExcelColumn>();
1905                foreach (var col in csec)
1906                {
1907                    if (col is ExcelColumn)
1908                    {
1909                        lst.Add((ExcelColumn)col);
1910                    }
1911                }
1912
1913                for (int i = lst.Count-1; i >= 0; i--)
1914                {
1915                    var c = lst[i];
1916                    if (c._columnMin >= columnFrom)
1917                    {
1918                        if (c._columnMin + columns <= ExcelPackage.MaxColumns)
1919                        {
1920                            c._columnMin += columns;
1921                        }
1922                        else
1923                        {
1924                            c._columnMin = ExcelPackage.MaxColumns;
1925                        }
1926                       
1927                        if (c._columnMax + columns <= ExcelPackage.MaxColumns)
1928                        {
1929                            c._columnMax += columns;
1930                        }
1931                        else
1932                        {
1933                            c._columnMax = ExcelPackage.MaxColumns;
1934                        }
1935                    }
1936                    else if (c._columnMax >= columnFrom)
1937                    {
1938                        var cc = c._columnMax - columnFrom;
1939                        c._columnMax = columnFrom - 1;
1940                        CopyColumn(c, columnFrom + columns, columnFrom + columns + cc);
1941                    }                   
1942                }
1943
1944
1945                if (copyStylesFromColumn > 0)
1946                {
1947                    for (var c = 0; c < columns; c++)
1948                    {
1949                        var col = this.Column(columnFrom + c);
1950                        col.StyleID = this.Column(copyStylesFromColumn).StyleID;
1951                    }
1952                }
1953                //Adjust tables
1954                foreach (var tbl in Tables)
1955                {
1956                    if (columnFrom > tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column)
1957                    {
1958                        InsertTableColumns(columnFrom, columns, tbl);
1959                    }
1960
1961                    tbl.Address=tbl.Address.AddColumn(columnFrom, columns);
1962                }
1963            }
1964        }
1965
1966        private static void InsertTableColumns(int columnFrom, int columns, ExcelTable tbl)
1967        {
1968            var node = tbl.Columns[0].TopNode.ParentNode;
1969            var ix = columnFrom - tbl.Address.Start.Column - 1;
1970            var insPos = node.ChildNodes[ix];
1971            ix += 2;
1972            for (int i = 0; i < columns; i++)
1973            {
1974                var name =
1975                    tbl.Columns.GetUniqueName(string.Format("Column{0}",
1976                        (ix++).ToString(CultureInfo.InvariantCulture)));
1977                XmlElement tableColumn =
1978                    (XmlElement) tbl.TableXml.CreateNode(XmlNodeType.Element, "tableColumn", ExcelPackage.schemaMain);
1979                tableColumn.SetAttribute("id", (tbl.Columns.Count + i + 1).ToString(CultureInfo.InvariantCulture));
1980                tableColumn.SetAttribute("name", name);
1981                insPos = node.InsertAfter(tableColumn, insPos);
1982            } //Create tbl Column
1983            tbl._cols = new ExcelTableColumnCollection(tbl);
1984        }
1985
1986        /// <summary>
1987        /// Adds a value to the row of merged cells to fix for inserts or deletes
1988        /// </summary>
1989        /// <param name="row"></param>
1990        /// <param name="rows"></param>
1991        /// <param name="delete"></param>
1992        private void FixMergedCellsRow(int row, int rows, bool delete)
1993        {
1994            List<int> removeIndex = new List<int>();
1995            for (int i = 0; i < _mergedCells.Count; i++)
1996            {
1997                if (!string.IsNullOrEmpty( _mergedCells[i]))
1998                {
1999                    ExcelAddressBase addr = new ExcelAddressBase(_mergedCells[i]), newAddr;
2000                    if (delete)
2001                    {
2002                        newAddr = addr.DeleteRow(row, rows);
2003                        _mergedCells._cells.Delete(row, 0, rows, 0);
2004                        if (newAddr == null)
2005                        {
2006                            removeIndex.Add(i);
2007                            continue;
2008                        }
2009                    }
2010                    else
2011                    {
2012                        newAddr = addr.AddRow(row, rows);
2013                        if (newAddr.Address != addr.Address)
2014                        {
2015                            _mergedCells._cells.Insert(row, 0, rows, 0);
2016                            _mergedCells.SetIndex(newAddr, i);
2017                        }
2018                    }
2019
2020                    if (newAddr.Address != addr.Address)
2021                    {
2022                        _mergedCells.List[i] = newAddr._address;
2023                    }
2024                }
2025            }
2026            for (int i = removeIndex.Count - 1; i >= 0; i--)
2027            {
2028                _mergedCells.List.RemoveAt(removeIndex[i]);
2029            }
2030        }
2031        /// <summary>
2032        /// Adds a value to the row of merged cells to fix for inserts or deletes
2033        /// </summary>
2034        /// <param name="column"></param>
2035        /// <param name="columns"></param>
2036        /// <param name="delete"></param>
2037        private void FixMergedCellsColumn(int column, int columns, bool delete)
2038        {
2039            List<int> removeIndex = new List<int>();
2040            for (int i = 0; i < _mergedCells.Count; i++)
2041            {
2042                if (!string.IsNullOrEmpty(_mergedCells[i]))
2043                {
2044                    ExcelAddressBase addr = new ExcelAddressBase(_mergedCells[i]), newAddr;
2045                    if (delete)
2046                    {
2047                        newAddr = addr.DeleteColumn(column, columns);
2048                        _mergedCells._cells.Delete(0, column, 0, columns);
2049                        if (newAddr == null)
2050                        {
2051                            removeIndex.Add(i);
2052                            continue;
2053                        }
2054                    }
2055                    else
2056                    {
2057                        newAddr = addr.AddColumn(column, columns);
2058                        if (newAddr.Address != addr.Address)
2059                        {
2060                            _mergedCells._cells.Insert(0, column, 0, columns);
2061                            _mergedCells.SetIndex(newAddr, i);
2062                        }
2063                    }
2064
2065                    if (newAddr.Address != addr.Address)
2066                    {
2067                        _mergedCells.List[i] = newAddr._address;
2068                    }
2069                }
2070            }
2071            for (int i = removeIndex.Count - 1; i >= 0; i--)
2072            {
2073                _mergedCells.List.RemoveAt(removeIndex[i]);
2074            }
2075        }
2076        private void FixSharedFormulasRows(int position, int rows)
2077        {
2078            List<Formulas> added = new List<Formulas>();
2079            List<Formulas> deleted = new List<Formulas>();
2080
2081            foreach (int id in _sharedFormulas.Keys)
2082            {
2083                var f = _sharedFormulas[id];
2084                int fromCol, fromRow, toCol, toRow;
2085
2086                ExcelCellBase.GetRowColFromAddress(f.Address, out fromRow, out fromCol, out toRow, out toCol);
2087                if (position >= fromRow && position+(Math.Abs(rows)) <= toRow) //Insert/delete is whithin the share formula address
2088                {
2089                    if (rows > 0) //Insert
2090                    {
2091                        f.Address = ExcelCellBase.GetAddress(fromRow, fromCol) + ":" + ExcelCellBase.GetAddress(position - 1, toCol);
2092                        if (toRow != fromRow)
2093                        {
2094                            Formulas newF = new Formulas(SourceCodeTokenizer.Default);
2095                            newF.StartCol = f.StartCol;
2096                            newF.StartRow = position + rows;
2097                            newF.Address = ExcelCellBase.GetAddress(position + rows, fromCol) + ":" + ExcelCellBase.GetAddress(toRow + rows, toCol);
2098                            newF.Formula = ExcelCellBase.TranslateFromR1C1(ExcelCellBase.TranslateToR1C1(f.Formula, f.StartRow, f.StartCol), position, f.StartCol);
2099                            added.Add(newF);
2100                        }
2101                    }
2102                    else
2103                    {
2104                        if (fromRow - rows < toRow)
2105                        {
2106                            f.Address = ExcelCellBase.GetAddress(fromRow, fromCol, toRow+rows, toCol);
2107                        }
2108                        else
2109                        {
2110                            f.Address = ExcelCellBase.GetAddress(fromRow, fromCol) + ":" + ExcelCellBase.GetAddress(toRow + rows, toCol);
2111                        }
2112                    }
2113                }
2114                else if (position <= toRow)
2115                {
2116                    if (rows > 0) //Insert before shift down
2117                    {
2118                        f.StartRow += rows;
2119                        //f.Formula = ExcelCell.UpdateFormulaReferences(f.Formula, rows, 0, position, 0); //Recalc the cells positions
2120                        f.Address = ExcelCellBase.GetAddress(fromRow + rows, fromCol) + ":" + ExcelCellBase.GetAddress(toRow + rows, toCol);
2121                    }
2122                    else
2123                    {
2124                        //Cells[f.Address].SetSharedFormulaID(int.MinValue);
2125                        if (position <= fromRow && position + Math.Abs(rows) > toRow)  //Delete the formula
2126                        {
2127                            deleted.Add(f);
2128                        }
2129                        else
2130                        {
2131                            toRow = toRow + rows < position - 1 ? position - 1 : toRow + rows;
2132                            if (position <= fromRow)
2133                            {
2134                                fromRow = fromRow + rows < position ? position : fromRow + rows;
2135                            }
2136
2137                            f.Address = ExcelCellBase.GetAddress(fromRow, fromCol, toRow, toCol);
2138                            Cells[f.Address].SetSharedFormulaID(f.Index);
2139                            //f.StartRow = fromRow;
2140
2141                            //f.Formula = ExcelCell.UpdateFormulaReferences(f.Formula, rows, 0, position, 0);
2142                       
2143                        }
2144                    }
2145                }
2146            }
2147
2148            AddFormulas(added, position, rows);
2149
2150            //Remove formulas
2151            foreach (Formulas f in deleted)
2152            {
2153                _sharedFormulas.Remove(f.Index);
2154            }
2155
2156            //Fix Formulas
2157            added = new List<Formulas>();
2158            foreach (int id in _sharedFormulas.Keys)
2159            {
2160                var f = _sharedFormulas[id];
2161                UpdateSharedFormulaRow(ref f, position, rows, ref added);
2162            }
2163            AddFormulas(added, position, rows);
2164        }
2165
2166        private void AddFormulas(List<Formulas> added, int position, int rows)
2167        {
2168            //Add new formulas
2169            foreach (Formulas f in added)
2170            {
2171                f.Index = GetMaxShareFunctionIndex(false);
2172                _sharedFormulas.Add(f.Index, f);
2173                Cells[f.Address].SetSharedFormulaID(f.Index);
2174            }
2175        }
2176
2177        private void UpdateSharedFormulaRow(ref Formulas formula, int startRow, int rows, ref List<Formulas> newFormulas)
2178        {
2179            int fromRow,fromCol, toRow, toCol;
2180            int newFormulasCount = newFormulas.Count;
2181            ExcelCellBase.GetRowColFromAddress(formula.Address, out fromRow, out fromCol, out toRow, out toCol);
2182            //int refSplits = Regex.Split(formula.Formula, "#REF!").GetUpperBound(0);
2183            string formualR1C1;
2184            if (rows > 0 || fromRow <= startRow)
2185            {
2186                formualR1C1 = ExcelRangeBase.TranslateToR1C1(formula.Formula, formula.StartRow, formula.StartCol);
2187                formula.Formula = ExcelRangeBase.TranslateFromR1C1(formualR1C1, fromRow, formula.StartCol);
2188            }
2189            else
2190            {
2191                formualR1C1 = ExcelRangeBase.TranslateToR1C1(formula.Formula, formula.StartRow-rows, formula.StartCol);
2192                formula.Formula = ExcelRangeBase.TranslateFromR1C1(formualR1C1, formula.StartRow, formula.StartCol);
2193            }
2194            //bool isRef = false;
2195            //Formulas restFormula=formula;
2196            string prevFormualR1C1 = formualR1C1;
2197            for (int row = fromRow; row <= toRow; row++)
2198            {
2199                for (int col = fromCol; col <= toCol; col++)
2200                {
2201                    string newFormula;
2202                    string currentFormulaR1C1;
2203                    if (rows > 0 || row < startRow)
2204                    {
2205                        newFormula = ExcelCellBase.UpdateFormulaReferences(ExcelCellBase.TranslateFromR1C1(formualR1C1, row, col), rows, 0, startRow, 0);
2206                        currentFormulaR1C1 = ExcelRangeBase.TranslateToR1C1(newFormula, row, col);
2207                    }
2208                    else
2209                    {
2210                        newFormula = ExcelCellBase.UpdateFormulaReferences(ExcelCellBase.TranslateFromR1C1(formualR1C1, row-rows, col), rows, 0, startRow, 0);
2211                        currentFormulaR1C1 = ExcelRangeBase.TranslateToR1C1(newFormula, row, col);
2212                    }
2213                    if (currentFormulaR1C1 != prevFormualR1C1) //newFormula.Contains("#REF!"))
2214                    {
2215                        //if (refSplits == 0 || Regex.Split(newFormula, "#REF!").GetUpperBound(0) != refSplits)
2216                        //{
2217                        //isRef = true;
2218                        if (row == fromRow && col == fromCol)
2219                        {
2220                            formula.Formula = newFormula;
2221                        }
2222                        else
2223                        {
2224                            if (newFormulas.Count == newFormulasCount)
2225                            {
2226                                formula.Address = ExcelCellBase.GetAddress(formula.StartRow, formula.StartCol, row - 1, col);
2227                            }
2228                            else
2229                            {
2230                                newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress(newFormulas[newFormulas.Count - 1].StartRow, newFormulas[newFormulas.Count - 1].StartCol, row - 1, col);
2231                            }
2232                            var refFormula = new Formulas(SourceCodeTokenizer.Default);
2233                            refFormula.Formula = newFormula;
2234                            refFormula.StartRow = row;
2235                            refFormula.StartCol = col;
2236                            newFormulas.Add(refFormula);
2237
2238                            //restFormula = null;
2239                            prevFormualR1C1 = currentFormulaR1C1;
2240                        }
2241                    }
2242                    //    }
2243                    //    else
2244                    //    {
2245                    //        isRef = false;
2246                    //    }
2247                    //}
2248                    //else
2249                    //{
2250                    //    isRef = false;
2251                    //}
2252                    //if (restFormula==null)
2253                    //{
2254                        //if (newFormulas.Count == newFormulasCount)
2255                        //{
2256                        //    formula.Address = ExcelCellBase.GetAddress(formula.StartRow, formula.StartCol, row - 1, col);
2257                        //}
2258                        //else
2259                        //{
2260//                            newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress(newFormulas[newFormulas.Count - 1].StartRow, newFormulas[0].StartCol, row - 1, col);
2261                        //}
2262
2263                        //restFormula = new Formulas();
2264                        //restFormula.Formula = newFormula;
2265                        //restFormula.StartRow = row;
2266                        //restFormula.StartCol = col;
2267                        //newFormulas.Add(restFormula);
2268                    //}
2269                }
2270            }
2271            if (rows < 0 && formula.StartRow > startRow)
2272            {
2273                if (formula.StartRow + rows < startRow)
2274                {
2275                    formula.StartRow = startRow;
2276                }
2277                else
2278                {
2279                    formula.StartRow += rows;
2280                }
2281            }
2282            if (newFormulas.Count > newFormulasCount)
2283            {
2284                newFormulas[newFormulas.Count - 1].Address = ExcelCellBase.GetAddress(newFormulas[newFormulas.Count - 1].StartRow, newFormulas[newFormulas.Count - 1].StartCol, toRow, toCol);
2285            }
2286        }
2287        #endregion
2288
2289        #region DeleteRow
2290        /// <summary>
2291        /// Delete the specified row from the worksheet.
2292        /// </summary>
2293        /// <param name="row">A row to be deleted</param>
2294        public void DeleteRow(int row)
2295        {
2296            DeleteRow(row, 1);
2297        }
2298        /// <summary>
2299        /// Delete the specified row from the worksheet.
2300        /// </summary>
2301        /// <param name="rowFrom">The start row</param>
2302        /// <param name="rows">Number of rows to delete</param>
2303        public void DeleteRow(int rowFrom, int rows)
2304        {
2305            CheckSheetType();
2306            if (rowFrom < 1 || rowFrom + rows > ExcelPackage.MaxRows)
2307            {
2308                throw(new ArgumentException("Row out of range. Spans from 1 to " + ExcelPackage.MaxRows.ToString(CultureInfo.InvariantCulture)));
2309            }
2310            lock (this)
2311            {
2312                _values.Delete(rowFrom, 1, rows, ExcelPackage.MaxColumns);
2313                _types.Delete(rowFrom, 1, rows, ExcelPackage.MaxColumns);
2314                _formulas.Delete(rowFrom, 1, rows, ExcelPackage.MaxColumns);
2315                _styles.Delete(rowFrom, 1, rows, ExcelPackage.MaxColumns);
2316                _flags.Delete(rowFrom, 1, rows, ExcelPackage.MaxColumns);
2317                _commentsStore.Delete(rowFrom, 1, rows, ExcelPackage.MaxColumns);
2318                _hyperLinks.Delete(rowFrom, 1, rows, ExcelPackage.MaxColumns);
2319
2320                AdjustFormulasRow(rowFrom, rows);
2321                FixMergedCellsRow(rowFrom, rows, true);
2322
2323                foreach (var tbl in Tables)
2324                {
2325                    tbl.Address = tbl.Address.DeleteRow(rowFrom, rows);
2326                }
2327            }
2328        }
2329        /// <summary>
2330        /// Delete the specified column from the worksheet.
2331        /// </summary>
2332        /// <param name="column">The column to be deleted</param>
2333        public void DeleteColumn(int column)
2334        {
2335            DeleteColumn(column,1);
2336        }
2337        /// <summary>
2338        /// Delete the specified column from the worksheet.
2339        /// </summary>
2340        /// <param name="columnFrom">The start column</param>
2341        /// <param name="columns">Number of columns to delete</param>
2342        public void DeleteColumn(int columnFrom, int columns)
2343        {
2344            if (columnFrom < 1 || columnFrom + columns > ExcelPackage.MaxColumns)
2345            {
2346                throw (new ArgumentException("Column out of range. Spans from 1 to " + ExcelPackage.MaxColumns.ToString(CultureInfo.InvariantCulture)));
2347            }
2348            lock (this)
2349            {
2350                var col = _values.GetValue(0, columnFrom) as ExcelColumn;
2351                if (col == null)
2352                {
2353                    var r = 0;
2354                    var c = columnFrom;
2355                    if(_values.PrevCell(ref r,ref c))
2356                    {
2357                        col = _values.GetValue(0, c) as ExcelColumn;
2358                        if(col._columnMax >= columnFrom)
2359                        {
2360                            col.ColumnMax=columnFrom-1;
2361                        }
2362                    }
2363                }
2364
2365                _values.Delete(1, columnFrom, ExcelPackage.MaxRows, columns);
2366                _types.Delete(1, columnFrom, ExcelPackage.MaxRows, columns);
2367                _formulas.Delete(1, columnFrom, ExcelPackage.MaxRows, columns);
2368                _styles.Delete(1, columnFrom, ExcelPackage.MaxRows, columns);
2369                _flags.Delete(1, columnFrom, ExcelPackage.MaxRows, columns);
2370                _commentsStore.Delete(1, columnFrom, ExcelPackage.MaxRows, columns);
2371                _hyperLinks.Delete(1, columnFrom, ExcelPackage.MaxRows, columns);
2372
2373                AdjustFormulasColumn(columnFrom, columns);
2374                FixMergedCellsColumn(columnFrom, columns, true);
2375
2376                var csec = new CellsStoreEnumerator<object>(_values, 0, columnFrom, 0, ExcelPackage.MaxColumns);
2377                foreach (var column in csec)   
2378                {
2379                    if (column is ExcelColumn)
2380                    {
2381                        var c = (ExcelColumn)column;
2382                        if (c._columnMin >= columnFrom)
2383                        {
2384                            c._columnMin -= columns;
2385                            c._columnMax -= columns;
2386                        }
2387                    }
2388                }
2389
2390                foreach (var tbl in Tables)
2391                {
2392                    if (columnFrom >= tbl.Address.Start.Column && columnFrom <= tbl.Address.End.Column)
2393                    {
2394                        var node = tbl.Columns[0].TopNode.ParentNode;
2395                        var ix = columnFrom - tbl.Address.Start.Column;
2396                        for (int i = 0; i < columns; i++)
2397                        {
2398                            if (node.ChildNodes.Count > ix)
2399                            {
2400                                node.RemoveChild(node.ChildNodes[ix]);
2401                            }
2402                        }
2403                        tbl._cols = new ExcelTableColumnCollection(tbl);
2404                    }
2405
2406                    tbl.Address = tbl.Address.DeleteColumn(columnFrom, columns);
2407                }
2408            }
2409        }
2410        internal void AdjustFormulasRow(int rowFrom, int rows)
2411        {
2412            var delSF = new List<int>();
2413            foreach (var sf in _sharedFormulas.Values)
2414            {
2415                var a = new ExcelAddress(sf.Address).DeleteRow(rowFrom, rows);
2416                if (a==null)
2417                {
2418                    delSF.Add(sf.Index);
2419                }
2420                else
2421                {
2422                    sf.Address = a.Address;
2423                    if (sf.StartRow > rowFrom)
2424                    {
2425                        var r = Math.Min(sf.StartRow - rowFrom, rows);
2426                        sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, -r, 0, rowFrom, 0);
2427                        sf.StartRow -= r;
2428                    }
2429                }
2430            }
2431            foreach (var ix in delSF)
2432            {
2433                _sharedFormulas.Remove(ix);
2434            }
2435            delSF = null;
2436            var cse = new CellsStoreEnumerator<object>(_formulas, 1, 1, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
2437            while (cse.Next())
2438            {
2439                if (cse.Value is string)
2440                {
2441                    cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), -rows, 0, rowFrom, 0);
2442                }
2443            }
2444        }
2445        internal void AdjustFormulasColumn(int columnFrom, int columns)
2446        {
2447            var delSF = new List<int>();
2448            foreach (var sf in _sharedFormulas.Values)
2449            {
2450                var a = new ExcelAddress(sf.Address).DeleteColumn(columnFrom, columns);
2451                if (a == null)
2452                {
2453                    delSF.Add(sf.Index);
2454                }
2455                else
2456                {
2457                    sf.Address = a.Address;
2458                    //sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -columns, 0, columnFrom);
2459                    if (sf.StartCol > columnFrom)
2460                    {
2461                        var c = Math.Min(sf.StartCol - columnFrom, columns);
2462                        sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0, -c, 0, 1);
2463                        sf.StartCol-= c;
2464                    }
2465
2466                    //sf.Address = a.Address;
2467                    //sf.Formula = ExcelCellBase.UpdateFormulaReferences(sf.Formula, 0,-columns,0, columnFrom);
2468                    //if (sf.StartCol >= columnFrom)
2469                    //{
2470                    //    sf.StartCol -= sf.StartCol;
2471                    //}
2472                }
2473            }
2474            foreach (var ix in delSF)
2475            {
2476                _sharedFormulas.Remove(ix);
2477            }
2478            delSF = null;
2479            var cse = new CellsStoreEnumerator<object>(_formulas, 1, 1,  ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
2480            while (cse.Next())
2481            {
2482                if (cse.Value is string)
2483                {
2484                    cse.Value = ExcelCellBase.UpdateFormulaReferences(cse.Value.ToString(), 0, -columns, 0, columnFrom);
2485                }
2486            }
2487        }
2488        /// <summary>
2489        /// Deletes the specified row from the worksheet.
2490        /// </summary>
2491        /// <param name="rowFrom">The number of the start row to be deleted</param>
2492        /// <param name="rows">Number of rows to delete</param>
2493        /// <param name="shiftOtherRowsUp">Not used. Rows are always shifted</param>
2494        public void DeleteRow(int rowFrom, int rows, bool shiftOtherRowsUp)
2495    {
2496            DeleteRow(rowFrom, rows);
2497        }
2498    #endregion
2499        /// <summary>
2500        /// Get the cell value from thw worksheet
2501        /// </summary>
2502        /// <param name="Row">The row number</param>
2503        /// <param name="Column">The row number</param>
2504        /// <returns>The value</returns>
2505        public object GetValue(int Row, int Column)
2506        {
2507            CheckSheetType();
2508            //ulong cellID = ExcelCellBase.GetCellID(SheetID, Row, Column);
2509            var v = _values.GetValue(Row, Column);
2510            if (v!=null)
2511            {
2512                //var cell = ((ExcelCell)_cells[cellID]);
2513                if (_flags.GetFlagValue(Row, Column, CellFlags.RichText))
2514                {
2515                    return (object)Cells[Row, Column].RichText.Text;
2516                }
2517                else
2518                {
2519                    return v;
2520                }
2521            }
2522            else
2523            {
2524                return null;
2525            }
2526        }
2527
2528        /// <summary>
2529        /// Get a strongly typed cell value from the worksheet
2530        /// </summary>
2531        /// <typeparam name="T">The type</typeparam>
2532        /// <param name="Row">The row number</param>
2533        /// <param name="Column">The row number</param>
2534        /// <returns>The value. If the value can't be converted to the specified type, the default value will be returned</returns>
2535        public T GetValue<T>(int Row, int Column)
2536        {
2537            CheckSheetType();
2538            //ulong cellID=ExcelCellBase.GetCellID(SheetID, Row, Column);
2539            var v = _values.GetValue(Row, Column);           
2540            if (v==null)
2541            {
2542                return default(T);
2543            }
2544
2545            //var cell=((ExcelCell)_cells[cellID]);
2546            if (_flags.GetFlagValue(Row, Column, CellFlags.RichText))
2547            {
2548                return (T)(object)Cells[Row, Column].RichText.Text;
2549            }
2550            else
2551            {
2552                return GetTypedValue<T>(v);
2553            }
2554        }
2555        //Thanks to Michael Tran for parts of this method
2556        internal T GetTypedValue<T>(object v)
2557        {
2558            if (v == null)
2559            {
2560                return default(T);
2561            }
2562            Type fromType = v.GetType();
2563            Type toType = typeof(T);
2564            if (fromType == toType)
2565            {
2566                return (T)v;
2567            }
2568            var cnv = TypeDescriptor.GetConverter(fromType);
2569            if (toType == typeof(DateTime))    //Handle dates
2570            {
2571                if (fromType == typeof(TimeSpan))
2572                {
2573                    return ((T)(object)(new DateTime(((TimeSpan)v).Ticks)));
2574                }
2575                else if (fromType == typeof(string))
2576                {
2577                    DateTime dt;
2578                    if (DateTime.TryParse(v.ToString(), out dt))
2579                    {
2580                        return (T)(object)(dt);
2581                    }
2582                    else
2583                    {
2584                        return default(T);
2585                    }
2586
2587                }
2588                else
2589                {
2590                    if (cnv.CanConvertTo(typeof(double)))
2591                    {
2592                        return (T)(object)(DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))));
2593                    }
2594                    else
2595                    {
2596                        return default(T);
2597                    }
2598                }
2599            }
2600            else if (toType == typeof(TimeSpan))    //Handle timespan
2601            {
2602                if (fromType == typeof(DateTime))
2603                {
2604                    return ((T)(object)(new TimeSpan(((DateTime)v).Ticks)));
2605                }
2606                else if (fromType == typeof(string))
2607                {
2608                    TimeSpan ts;
2609                    if (TimeSpan.TryParse(v.ToString(), out ts))
2610                    {
2611                        return (T)(object)(ts);
2612                    }
2613                    else
2614                    {
2615                        return default(T);
2616                    }
2617                }
2618                else
2619                {
2620                    if (cnv.CanConvertTo(typeof(double)))
2621                    {
2622
2623                        return (T)(object)(new TimeSpan(DateTime.FromOADate((double)cnv.ConvertTo(v, typeof(double))).Ticks));
2624                    }
2625                    else
2626                    {
2627                        try
2628                        {
2629                            // Issue 14682 -- "GetValue<decimal>() won't convert strings"
2630                            // As suggested, after all special cases, all .NET to do it's
2631                            // preferred conversion rather than simply returning the default
2632                            return (T)Convert.ChangeType(v, typeof(T));
2633                        }
2634                        catch (Exception)
2635                        {
2636                            // This was the previous behaviour -- no conversion is available.
2637                            return default(T);
2638                        }
2639                    }
2640                }
2641            }
2642            else
2643            {
2644                if (cnv.CanConvertTo(toType))
2645                {
2646                    return (T)cnv.ConvertTo(v, typeof(T));
2647                }
2648                else
2649                {
2650                    if (toType.IsGenericType && toType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
2651                    {
2652                        toType = Nullable.GetUnderlyingType(toType);
2653                        if (cnv.CanConvertTo(toType))
2654                        {
2655                            return (T)cnv.ConvertTo(v, typeof(T));
2656                        }
2657                    }
2658
2659                    if(fromType==typeof(double) && toType==typeof(decimal))
2660                    {
2661                        return (T)(object)Convert.ToDecimal(v);
2662                    }
2663                    else if (fromType == typeof(decimal) && toType == typeof(double))
2664                    {
2665                        return (T)(object)Convert.ToDouble(v);
2666                    }
2667                    else
2668                    {
2669                        return default(T);
2670                    }
2671                }
2672            }
2673        }
2674        /// <summary>
2675        /// Set the value of a cell
2676        /// </summary>
2677        /// <param name="Row">The row number</param>
2678        /// <param name="Column">The column number</param>
2679        /// <param name="Value">The value</param>
2680        public void SetValue(int Row, int Column, object Value)
2681        {
2682            CheckSheetType();
2683            if (Row < 1 || Column < 1 || Row > ExcelPackage.MaxRows && Column > ExcelPackage.MaxColumns)
2684            {
2685                throw new ArgumentOutOfRangeException("Row or Column out of range");
2686            }           
2687            _values.SetValue(Row, Column, Value);
2688        }
2689        /// <summary>
2690        /// Set the value of a cell
2691        /// </summary>
2692        /// <param name="Address">The Excel address</param>
2693        /// <param name="Value">The value</param>
2694        public void SetValue(string Address, object Value)
2695        {
2696            CheckSheetType();
2697            int row, col;
2698            ExcelAddressBase.GetRowCol(Address, out row, out col, true);
2699            if (row < 1 || col < 1 || row > ExcelPackage.MaxRows && col > ExcelPackage.MaxColumns)
2700            {
2701                throw new ArgumentOutOfRangeException("Address is invalid or out of range");
2702            }
2703            _values.SetValue(row, col, Value);           
2704        }
2705
2706        #region MergeCellId
2707
2708        /// <summary>
2709        /// Get MergeCell Index No
2710        /// </summary>
2711        /// <param name="row"></param>
2712        /// <param name="column"></param>
2713        /// <returns></returns>
2714        public int GetMergeCellId(int row, int column)
2715        {
2716            for (int i = 0; i < _mergedCells.Count; i++)
2717            {
2718               if(!string.IsNullOrEmpty( _mergedCells[i]))
2719               {
2720                    ExcelRange range = Cells[_mergedCells[i]];
2721
2722                    if (range.Start.Row <= row && row <= range.End.Row)
2723                    {
2724                        if (range.Start.Column <= column && column <= range.End.Column)
2725                        {
2726                            return i + 1;
2727                        }
2728                    }
2729                }
2730            }
2731            return 0;
2732        }
2733
2734        #endregion
2735    #endregion // END Worksheet Public Methods
2736
2737    #region Worksheet Private Methods
2738
2739    #region Worksheet Save
2740        internal void Save()
2741        {
2742                DeletePrinterSettings();
2743
2744                if (_worksheetXml != null)
2745                {
2746
2747                    if (!(this is ExcelChartsheet))
2748                    {
2749                        // save the header & footer (if defined)
2750                        if (_headerFooter != null)
2751                            HeaderFooter.Save();
2752
2753                        var d = Dimension;
2754                        if (d == null)
2755                        {
2756                            this.DeleteAllNode("d:dimension/@ref");
2757                        }
2758                        else
2759                        {
2760                            this.SetXmlNodeString("d:dimension/@ref", d.Address);
2761                        }
2762
2763
2764                        if (Drawings.Count == 0)
2765                        {
2766                            //Remove node if no drawings exists.
2767                            DeleteNode("d:drawing");
2768                        }
2769
2770                        SaveComments();
2771                        HeaderFooter.SaveHeaderFooterImages();
2772                        SaveTables();
2773                        SavePivotTables();
2774                    }
2775                }
2776
2777                if (Drawings.UriDrawing!=null)
2778                {
2779                    if (Drawings.Count == 0)
2780                    {                                           
2781                        Part.DeleteRelationship(Drawings._drawingRelation.Id);
2782                        _package.Package.DeletePart(Drawings.UriDrawing);                   
2783                    }
2784                    else
2785                    {
2786                        Packaging.ZipPackagePart partPack = Drawings.Part;
2787                        Drawings.DrawingXml.Save(partPack.GetStream(FileMode.Create, FileAccess.Write));
2788                        foreach (ExcelDrawing d in Drawings)
2789                        {
2790                            if (d is ExcelChart)
2791                            {
2792                                ExcelChart c = (ExcelChart)d;
2793                                c.ChartXml.Save(c.Part.GetStream(FileMode.Create, FileAccess.Write));
2794                            }
2795                        }
2796                    }
2797                }
2798        }
2799        internal void SaveHandler(ZipOutputStream stream, CompressionLevel compressionLevel, string fileName)
2800        {
2801                    //Init Zip
2802                    stream.CodecBufferSize = 8096;
2803                    stream.CompressionLevel = (OfficeOpenXml.Packaging.Ionic.Zlib.CompressionLevel)compressionLevel;
2804                    stream.PutNextEntry(fileName);
2805
2806                   
2807                    SaveXml(stream);
2808        }
2809
2810       
2811
2812        ///// <summary>
2813        ///// Saves the worksheet to the package.
2814        ///// </summary>
2815        //internal void Save()  // Worksheet Save
2816        //{
2817        //    DeletePrinterSettings();
2818
2819        //    if (_worksheetXml != null)
2820        //    {
2821               
2822        //        // save the header & footer (if defined)
2823        //        if (_headerFooter != null)
2824        //            HeaderFooter.Save();
2825
2826        //        var d = Dimension;
2827        //        if (d == null)
2828        //        {
2829        //            this.DeleteAllNode("d:dimension/@ref");
2830        //        }
2831        //        else
2832        //        {
2833        //            this.SetXmlNodeString("d:dimension/@ref", d.Address);
2834        //        }
2835               
2836
2837        //        if (_drawings != null && _drawings.Count == 0)
2838        //        {
2839        //            //Remove node if no drawings exists.
2840        //            DeleteNode("d:drawing");
2841        //        }
2842
2843        //        SaveComments();
2844        //        HeaderFooter.SaveHeaderFooterImages();
2845        //        SaveTables();
2846        //        SavePivotTables();
2847        //        SaveXml();
2848        //    }
2849           
2850        //    if (Drawings.UriDrawing!=null)
2851        //    {
2852        //        if (Drawings.Count == 0)
2853        //        {                   
2854        //            Part.DeleteRelationship(Drawings._drawingRelation.Id);
2855        //            _package.Package.DeletePart(Drawings.UriDrawing);                   
2856        //        }
2857        //        else
2858        //        {
2859        //            Packaging.ZipPackagePart partPack = Drawings.Part;
2860        //            Drawings.DrawingXml.Save(partPack.GetStream(FileMode.Create, FileAccess.Write));
2861        //            foreach (ExcelDrawing d in Drawings)
2862        //            {
2863        //                if (d is ExcelChart)
2864        //                {
2865        //                    ExcelChart c = (ExcelChart)d;
2866        //                    c.ChartXml.Save(c.Part.GetStream(FileMode.Create, FileAccess.Write));
2867        //                }
2868        //            }
2869        //        }
2870        //    }
2871        //}
2872
2873        /// <summary>
2874        /// Delete the printersettings relationship and part.
2875        /// </summary>
2876        private void DeletePrinterSettings()
2877        {
2878            //Delete the relationship from the pageSetup tag
2879            XmlAttribute attr = (XmlAttribute)WorksheetXml.SelectSingleNode("//d:pageSetup/@r:id", NameSpaceManager);
2880            if (attr != null)
2881            {
2882                string relID = attr.Value;
2883                //First delete the attribute from the XML
2884                attr.OwnerElement.Attributes.Remove(attr);
2885                if(Part.RelationshipExists(relID))
2886                {
2887                    var rel = Part.GetRelationship(relID);
2888                    Uri printerSettingsUri = UriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri);
2889                    Part.DeleteRelationship(rel.Id);
2890
2891                    //Delete the part from the package
2892                    if(_package.Package.PartExists(printerSettingsUri))
2893                    {
2894                        _package.Package.DeletePart(printerSettingsUri);
2895                    }
2896                }
2897            }
2898        }
2899        private void SaveComments()
2900        {
2901            if (_comments != null)
2902            {
2903                if (_comments.Count == 0)
2904                {
2905                    if (_comments.Uri != null)
2906                    {
2907                        Part.DeleteRelationship(_comments.RelId);
2908                        _package.Package.DeletePart(_comments.Uri);                       
2909                    }
2910                    RemoveLegacyDrawingRel(VmlDrawingsComments.RelId);
2911                }
2912                else
2913                {
2914                    if (_comments.Uri == null)
2915                    {
2916                        _comments.Uri=new Uri(string.Format(@"/xl/comments{0}.xml", SheetID), UriKind.Relative);                       
2917                    }
2918                    if(_comments.Part==null)
2919                    {
2920                        _comments.Part = _package.Package.CreatePart(_comments.Uri, "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", _package.Compression);
2921                        var rel = Part.CreateRelationship(UriHelper.GetRelativeUri(WorksheetUri, _comments.Uri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships+"/comments");
2922                    }
2923                    _comments.CommentXml.Save(_comments.Part.GetStream(FileMode.Create));
2924                }
2925            }
2926
2927            if (_vmlDrawings != null)
2928            {
2929                if (_vmlDrawings.Count == 0)
2930                {
2931                    if (_vmlDrawings.Uri != null)
2932                    {
2933                        Part.DeleteRelationship(_vmlDrawings.RelId);
2934                        _package.Package.DeletePart(_vmlDrawings.Uri);
2935                    }
2936                }
2937                else
2938                {
2939                    if (_vmlDrawings.Uri == null)
2940                    {
2941                        _vmlDrawings.Uri = XmlHelper.GetNewUri(_package.Package, @"/xl/drawings/vmlDrawing{0}.vml");
2942                    }
2943                    if (_vmlDrawings.Part == null)
2944                    {
2945                        _vmlDrawings.Part = _package.Package.CreatePart(_vmlDrawings.Uri, "application/vnd.openxmlformats-officedocument.vmlDrawing", _package.Compression);
2946                        var rel = Part.CreateRelationship(UriHelper.GetRelativeUri(WorksheetUri, _vmlDrawings.Uri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/vmlDrawing");
2947                        SetXmlNodeString("d:legacyDrawing/@r:id", rel.Id);
2948                        _vmlDrawings.RelId = rel.Id;
2949                    }
2950                    _vmlDrawings.VmlDrawingXml.Save(_vmlDrawings.Part.GetStream());
2951                }
2952            }
2953        }
2954        /// <summary>
2955        /// Save all table data
2956        /// </summary>
2957        private void SaveTables()
2958        {
2959            foreach (var tbl in Tables)
2960            {
2961                if (tbl.ShowHeader || tbl.ShowTotal)
2962                {
2963                    int colNum = tbl.Address._fromCol;
2964                    var colVal = new HashSet<string>();
2965                    foreach (var col in tbl.Columns)
2966                    {                       
2967                        var n=col.Name.ToLower(CultureInfo.InvariantCulture);
2968                        if(colVal.Contains(n))
2969                        {
2970                            throw(new InvalidDataException(string.Format("Table {0} Column {1} does not have a unique name.", tbl.Name, col.Name)));
2971                        }
2972                        colVal.Add(n);
2973                        if (tbl.ShowHeader)
2974                        {
2975                            _values.SetValue(tbl.Address._fromRow, colNum, col.Name);
2976                        }
2977                        if (tbl.ShowTotal)
2978                        {
2979                            SetTableTotalFunction(tbl, col, colNum);
2980                        }
2981                        if (!string.IsNullOrEmpty(col.CalculatedColumnFormula))
2982                        {
2983                            int fromRow = tbl.ShowHeader ? tbl.Address._fromRow + 1 : tbl.Address._fromRow;
2984                            int toRow = tbl.ShowTotal ? tbl.Address._toRow - 1 : tbl.Address._toRow;
2985                            for (int row = fromRow; row <= toRow; row++)
2986                            {
2987                                //Cell(row, colNum).Formula = col.CalculatedColumnFormula;
2988                                SetFormula(row, colNum, col.CalculatedColumnFormula);
2989                            }                           
2990                        }
2991                        colNum++;
2992                    }
2993                }               
2994                if (tbl.Part == null)
2995                {
2996                    tbl.TableUri = GetNewUri(_package.Package, @"/xl/tables/table{0}.xml", tbl.Id);
2997                    tbl.Part = _package.Package.CreatePart(tbl.TableUri, "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", Workbook._package.Compression);
2998                    var stream = tbl.Part.GetStream(FileMode.Create);
2999                    tbl.TableXml.Save(stream);
3000                    var rel = Part.CreateRelationship(UriHelper.GetRelativeUri(WorksheetUri, tbl.TableUri), Packaging.TargetMode.Internal, ExcelPackage.schemaRelationships + "/table");
3001                    tbl.RelationshipID = rel.Id;
3002
3003                    CreateNode("d:tableParts");
3004                    XmlNode tbls = TopNode.SelectSingleNode("d:tableParts",NameSpaceManager);
3005
3006                    var tblNode = tbls.OwnerDocument.CreateElement("tablePart",ExcelPackage.schemaMain);
3007                    tbls.AppendChild(tblNode);
3008                    tblNode.SetAttribute("id",ExcelPackage.schemaRelationships, rel.Id);
3009                }
3010                else
3011                {
3012                    var stream = tbl.Part.GetStream(FileMode.Create);
3013                    tbl.TableXml.Save(stream);
3014                }
3015            }
3016        }
3017
3018        internal void SetTableTotalFunction(ExcelTable tbl, ExcelTableColumn col, int colNum=-1)
3019        {
3020            if (tbl.ShowTotal == false) return;
3021            if (colNum == -1)
3022            {
3023                for (int i = 0; i < tbl.Columns.Count; i++)
3024                {
3025                    if (tbl.Columns[i].Name == col.Name)
3026                    {
3027                        colNum = tbl.Address._fromCol + i;
3028                    }
3029                }
3030            }
3031            if (col.TotalsRowFunction == RowFunctions.Custom)
3032            {
3033                SetFormula(tbl.Address._toRow, colNum, col.TotalsRowFormula);
3034            }
3035            else if (col.TotalsRowFunction != RowFunctions.None)
3036            {
3037                switch (col.TotalsRowFunction)
3038                {
3039                    case RowFunctions.Average:
3040                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "101"));
3041                        break;
3042                    case RowFunctions.Count:
3043                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "102"));
3044                        break;
3045                    case RowFunctions.CountNums:
3046                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "103"));
3047                        break;
3048                    case RowFunctions.Max:
3049                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "104"));
3050                        break;
3051                    case RowFunctions.Min:
3052                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "105"));
3053                        break;
3054                    case RowFunctions.StdDev:
3055                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "107"));
3056                        break;
3057                    case RowFunctions.Var:
3058                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "110"));
3059                        break;
3060                    case RowFunctions.Sum:
3061                        SetFormula(tbl.Address._toRow, colNum, GetTotalFunction(col, "109"));
3062                        break;
3063                    default:
3064                        throw (new Exception("Unknown RowFunction enum"));
3065                }
3066            }
3067            else
3068            {
3069                _values.SetValue(tbl.Address._toRow, colNum, col.TotalsRowLabel);
3070
3071            }
3072        }
3073
3074        internal void SetFormula(int row, int col, object value)
3075        {
3076            _formulas.SetValue(row, col, value);
3077            if (!_values.Exists(row, col)) _values.SetValue(row, col, null);
3078        }
3079        internal void SetStyle(int row, int col, int value)
3080        {
3081            _styles.SetValue(row, col, value);
3082            if(!_values.Exists(row,col)) _values.SetValue(row, col, null);
3083        }
3084       
3085        private void SavePivotTables()
3086        {
3087            foreach (var pt in PivotTables)
3088            {
3089                if (pt.DataFields.Count > 1)
3090                {
3091                    XmlElement parentNode;
3092                    if(pt.DataOnRows==true)
3093                    {
3094                        parentNode =  pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) as XmlElement;
3095                        if (parentNode == null)
3096                        {
3097                            pt.CreateNode("d:rowFields");
3098                            parentNode = pt.PivotTableXml.SelectSingleNode("//d:rowFields", pt.NameSpaceManager) as XmlElement;
3099                        }
3100                    }
3101                    else
3102                    {
3103                        parentNode =  pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) as XmlElement;
3104                        if (parentNode == null)
3105                        {
3106                            pt.CreateNode("d:colFields");
3107                            parentNode = pt.PivotTableXml.SelectSingleNode("//d:colFields", pt.NameSpaceManager) as XmlElement;
3108                        }
3109                    }
3110
3111                    if (parentNode.SelectSingleNode("d:field[@ x= \"-2\"]", pt.NameSpaceManager) == null)
3112                    {
3113                        XmlElement fieldNode = pt.PivotTableXml.CreateElement("field", ExcelPackage.schemaMain);
3114                        fieldNode.SetAttribute("x", "-2");
3115                        parentNode.AppendChild(fieldNode);
3116                    }
3117                }
3118                pt.PivotTableXml.Save(pt.Part.GetStream(FileMode.Create));
3119                pt.CacheDefinition.CacheDefinitionXml.Save(pt.CacheDefinition.Part.GetStream(FileMode.Create));
3120            }
3121        }
3122        private static string GetTotalFunction(ExcelTableColumn col,string FunctionNum)
3123        {
3124            return string.Format("SUBTOTAL({0},{1}[{2}])", FunctionNum, col._tbl.Name, col.Name);
3125        }
3126        private void SaveXml(Stream stream)
3127        {
3128            //Create the nodes if they do not exist.
3129            StreamWriter sw = new StreamWriter(stream, System.Text.Encoding.UTF8, 65536);
3130            if (this is ExcelChartsheet)
3131            {
3132                sw.Write(_worksheetXml.OuterXml);
3133            }
3134            else
3135            {
3136                CreateNode("d:cols");
3137                CreateNode("d:sheetData");
3138                CreateNode("d:mergeCells");
3139                CreateNode("d:hyperlinks");
3140                CreateNode("d:rowBreaks");
3141                CreateNode("d:colBreaks");
3142
3143                //StreamWriter sw=new StreamWriter(Part.GetStream(FileMode.Create, FileAccess.Write));
3144                var xml = _worksheetXml.OuterXml;
3145                int colStart = 0, colEnd = 0;
3146                GetBlockPos(xml, "cols", ref colStart, ref colEnd);
3147
3148                sw.Write(xml.Substring(0, colStart));
3149                var colBreaks = new List<int>();
3150                //if (_columns.Count > 0)
3151                //{
3152                UpdateColumnData(sw);
3153                //}
3154
3155                int cellStart = colEnd, cellEnd = colEnd;
3156                GetBlockPos(xml, "sheetData", ref cellStart, ref cellEnd);
3157
3158                sw.Write(xml.Substring(colEnd, cellStart - colEnd));
3159                var rowBreaks = new List<int>();
3160                UpdateRowCellData(sw);
3161
3162                int mergeStart = cellEnd, mergeEnd = cellEnd;
3163
3164                GetBlockPos(xml, "mergeCells", ref mergeStart, ref mergeEnd);
3165                sw.Write(xml.Substring(cellEnd, mergeStart - cellEnd));
3166
3167                CleanupMergedCells(_mergedCells);
3168                if (_mergedCells.Count > 0)
3169                {
3170                    UpdateMergedCells(sw);
3171                }
3172
3173                int hyperStart = mergeEnd, hyperEnd = mergeEnd;
3174                GetBlockPos(xml, "hyperlinks", ref hyperStart, ref hyperEnd);
3175                sw.Write(xml.Substring(mergeEnd, hyperStart - mergeEnd));
3176                //if (_hyperLinkCells.Count > 0)
3177                //{
3178                UpdateHyperLinks(sw);
3179                // }
3180
3181                int rowBreakStart = hyperEnd, rowBreakEnd = hyperEnd;
3182                GetBlockPos(xml, "rowBreaks", ref rowBreakStart, ref rowBreakEnd);
3183                sw.Write(xml.Substring(hyperEnd, rowBreakStart - hyperEnd));
3184                //if (rowBreaks.Count > 0)
3185                //{
3186                UpdateRowBreaks(sw);
3187                //}
3188
3189                int colBreakStart = rowBreakEnd, colBreakEnd = rowBreakEnd;
3190                GetBlockPos(xml, "colBreaks", ref colBreakStart, ref colBreakEnd);
3191                sw.Write(xml.Substring(rowBreakEnd, colBreakStart - rowBreakEnd));
3192                //if (colBreaks.Count > 0)
3193                //{
3194                UpdateColBreaks(sw);
3195                //}
3196                sw.Write(xml.Substring(colBreakEnd, xml.Length - colBreakEnd));
3197            }
3198            sw.Flush();
3199            //sw.Close();
3200        }
3201
3202        private void CleanupMergedCells(MergeCellsCollection _mergedCells)
3203        {
3204            int i=0;
3205            while (i < _mergedCells.List.Count)
3206            {
3207                if (_mergedCells[i] == null)
3208                {
3209                    _mergedCells.List.RemoveAt(i);
3210                }
3211                else
3212                {
3213                    i++;
3214                }
3215            }
3216        }
3217        private void UpdateColBreaks(StreamWriter sw)
3218        {
3219            StringBuilder breaks = new StringBuilder();
3220            int count = 0;
3221            var cse = new CellsStoreEnumerator<object>(_values, 0, 0, 0, ExcelPackage.MaxColumns);
3222            //foreach (ExcelColumn col in _columns)
3223            while(cse.Next())
3224            {
3225                var col=cse.Value as ExcelColumn;
3226                if (col != null && col.PageBreak)
3227                {
3228                    breaks.AppendFormat("<brk id=\"{0}\" max=\"16383\" man=\"1\" />", cse.Column);
3229                    count++;
3230                }
3231            }
3232            if (count > 0)
3233            {
3234                sw.Write(string.Format("<colBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</colBreaks>", count, breaks.ToString()));
3235            }
3236        }
3237
3238        private void UpdateRowBreaks(StreamWriter sw)
3239        {
3240            StringBuilder breaks=new StringBuilder();
3241            int count = 0;
3242            var cse = new CellsStoreEnumerator<object>(_values, 0, 0, ExcelPackage.MaxRows, 0);
3243            //foreach(ExcelRow row in _rows)           
3244            while(cse.Next())
3245            {
3246                var row=cse.Value as RowInternal;
3247                if (row != null && row.PageBreak)
3248                {
3249                    breaks.AppendFormat("<brk id=\"{0}\" max=\"1048575\" man=\"1\" />", cse.Row);
3250                    count++;
3251                }
3252            }
3253            if (count>0)
3254            {
3255                sw.Write(string.Format("<rowBreaks count=\"{0}\" manualBreakCount=\"{0}\">{1}</rowBreaks>", count, breaks.ToString()));               
3256            }
3257        }
3258        /// <summary>
3259        /// Inserts the cols collection into the XML document
3260        /// </summary>
3261        private void UpdateColumnData(StreamWriter sw)
3262        {
3263            //ExcelColumn prevCol = null;   //commented out 11/1-12 JK
3264            //foreach (ExcelColumn col in _columns)
3265            //{               
3266            //    if (prevCol != null)
3267            //    {
3268            //        if(prevCol.ColumnMax != col.ColumnMin-1)
3269            //        {
3270            //            prevCol._columnMax=col.ColumnMin-1;
3271            //        }
3272            //    }
3273            //    prevCol = col;
3274            //}
3275            var cse = new CellsStoreEnumerator<object>(_values, 0, 1, 0, ExcelPackage.MaxColumns);
3276            //sw.Write("<cols>");
3277            //foreach (ExcelColumn col in _columns)
3278            bool first = true;
3279            while(cse.Next())
3280            {
3281                if (first)
3282                {
3283                    sw.Write("<cols>");
3284                    first = false;
3285                }
3286                var col = cse.Value as ExcelColumn;
3287                ExcelStyleCollection<ExcelXfs> cellXfs = _package.Workbook.Styles.CellXfs;
3288
3289                sw.Write("<col min=\"{0}\" max=\"{1}\"", col.ColumnMin, col.ColumnMax);
3290                if (col.Hidden == true)
3291                {
3292                    //sbXml.Append(" width=\"0\" hidden=\"1\" customWidth=\"1\"");
3293                    sw.Write(" hidden=\"1\"");
3294                }
3295                else if (col.BestFit)
3296                {
3297                    sw.Write(" bestFit=\"1\"");
3298                }
3299                sw.Write(string.Format(CultureInfo.InvariantCulture, " width=\"{0}\" customWidth=\"1\"", col.Width));
3300                if (col.OutlineLevel > 0)
3301                {                   
3302                    sw.Write(" outlineLevel=\"{0}\" ", col.OutlineLevel);
3303                    if (col.Collapsed)
3304                    {
3305                        if (col.Hidden)
3306                        {
3307                            sw.Write(" collapsed=\"1\"");
3308                        }
3309                        else
3310                        {
3311                            sw.Write(" collapsed=\"1\" hidden=\"1\""); //Always hidden
3312                        }
3313                    }
3314                }
3315                if (col.Phonetic)
3316                {
3317                    sw.Write(" phonetic=\"1\"");
3318                }
3319
3320                var styleID = col.StyleID >= 0 ? cellXfs[col.StyleID].newID : col.StyleID;
3321                if (styleID > 0)
3322                {
3323                    sw.Write(" style=\"{0}\"", styleID);
3324                }
3325                sw.Write(" />");
3326
3327                //if (col.PageBreak)
3328                //{
3329                //    colBreaks.Add(col.ColumnMin);
3330                //}
3331            }
3332            if (!first)
3333            {
3334                sw.Write("</cols>");
3335            }
3336        }
3337        /// <summary>
3338        /// Insert row and cells into the XML document
3339        /// </summary>
3340        private void UpdateRowCellData(StreamWriter sw)
3341        {
3342            ExcelStyleCollection<ExcelXfs> cellXfs = _package.Workbook.Styles.CellXfs;
3343           
3344            int row = -1;
3345
3346            StringBuilder sbXml = new StringBuilder();
3347            var ss = _package.Workbook._sharedStrings;
3348            var styles = _package.Workbook.Styles;
3349            var cache = new StringBuilder();
3350            cache.Append("<sheetData>");
3351           
3352            //Set a value for cells with style and no value set.
3353            var cseStyle = new CellsStoreEnumerator<int>(_styles, 0, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
3354            foreach (var s in cseStyle)
3355            {
3356                if(!_values.Exists(cseStyle.Row, cseStyle.Column))
3357                {
3358                    _values.SetValue(cseStyle.Row, cseStyle.Column, null);
3359                }
3360            }
3361
3362            var cse = new CellsStoreEnumerator<object>(_values, 1, 0, ExcelPackage.MaxRows, ExcelPackage.MaxColumns);
3363            //foreach (IRangeID r in _cells)
3364            while(cse.Next())
3365            {
3366                if (cse.Column>0)
3367                {
3368                    int styleID = cellXfs[styles.GetStyleId(this, cse.Row, cse.Column)].newID;
3369                    //Add the row element if it's a new row
3370                    if (cse.Row != row)
3371                    {
3372                        WriteRow(cache, cellXfs, row, cse.Row);
3373                        row = cse.Row;
3374                    }
3375                    object v = cse.Value;
3376                    object formula = _formulas.GetValue(cse.Row, cse.Column);
3377                    if (formula is int)
3378                    {
3379                        int sfId = (int)formula;
3380                        var f = _sharedFormulas[(int)sfId];
3381                        if (f.Address.IndexOf(':') > 0)
3382                        {
3383                            if (f.StartCol == cse.Column && f.StartRow == cse.Row)
3384                            {
3385                                if (f.IsArray)
3386                                {
3387                                    cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, SecurityElement.Escape(f.Formula), GetFormulaValue(v), GetCellType(v,true));
3388                                }
3389                                else
3390                                {
3391                                    cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{6}><f ref=\"{2}\" t=\"shared\"  si=\"{3}\">{4}</f>{5}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, f.Address, sfId, SecurityElement.Escape(f.Formula), GetFormulaValue(v), GetCellType(v,true));
3392                                }
3393
3394                            }
3395                            else if (f.IsArray)
3396                            {
3397                                cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" />", cse.CellAddress, styleID < 0 ? 0 : styleID);
3398                            }
3399                            else
3400                            {
3401                                cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{4}><f t=\"shared\" si=\"{2}\" />{3}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, sfId, GetFormulaValue(v), GetCellType(v,true));
3402                            }
3403                        }
3404                        else
3405                        {
3406                            // We can also have a single cell array formula
3407                            if(f.IsArray)
3408                            {
3409                                cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{5}><f ref=\"{2}\" t=\"array\">{3}</f>{4}</c>", cse.CellAddress, styleID < 0 ? 0 : styleID, string.Format("{0}:{1}", f.Address, f.Address), SecurityElement.Escape(f.Formula), GetFormulaValue(v), GetCellType(v,true));
3410                            }
3411                            else
3412                            {
3413                                cache.AppendFormat("<c r=\"{0}\" s=\"{1}\">", f.Address, styleID < 0 ? 0 : styleID);
3414                                cache.AppendFormat("<f>{0}</f>{1}</c>", SecurityElement.Escape(f.Formula), GetFormulaValue(v));
3415                            }
3416                        }
3417                    }
3418                    else if (formula!=null && formula.ToString()!="")
3419                    {
3420                        cache.AppendFormat("<c r=\"{0}\" s=\"{1}\"{2}>", cse.CellAddress, styleID < 0 ? 0 : styleID, GetCellType(v,true));
3421                        cache.AppendFormat("<f>{0}</f>{1}</c>", SecurityElement.Escape(formula.ToString()), GetFormulaValue(v));
3422                    }
3423                    else
3424                    {
3425                        if (v == null && styleID > 0)
3426                        {
3427                            cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" />", cse.CellAddress, styleID < 0 ? 0 : styleID);
3428                        }
3429                        else if(v != null)
3430                        {
3431                            if ((v.GetType().IsPrimitive || v is double || v is decimal || v is DateTime || v is TimeSpan))
3432                            {
3433                                //string sv = GetValueForXml(v);
3434                                cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" {2}>", cse.CellAddress, styleID < 0 ? 0 : styleID, GetCellType(v));
3435                                cache.AppendFormat("{0}</c>", GetFormulaValue(v));
3436                            }
3437                            else
3438                            {
3439                                int ix;
3440                                if (!ss.ContainsKey(v.ToString()))
3441                                {
3442                                    ix = ss.Count;
3443                                    ss.Add(v.ToString(), new ExcelWorkbook.SharedStringItem() { isRichText = _flags.GetFlagValue(cse.Row,cse.Column,CellFlags.RichText), pos = ix });
3444                                }
3445                                else
3446                                {
3447                                    ix = ss[v.ToString()].pos;
3448                                }
3449                                cache.AppendFormat("<c r=\"{0}\" s=\"{1}\" t=\"s\">", cse.CellAddress, styleID < 0 ? 0 : styleID);
3450                                cache.AppendFormat("<v>{0}</v></c>", ix);
3451                            }
3452                        }
3453                    }
3454                    ////Update hyperlinks.
3455                   //if (cell.Hyperlink != null)
3456                    //{
3457                    //    _hyperLinkCells.Add(cell.CellID);
3458                    //}
3459                }
3460                else  //ExcelRow
3461                {
3462                    //int newRow=((ExcelRow)cse.Value).Row;
3463                    WriteRow(cache, cellXfs, row, cse.Row);
3464                    row = cse.Row;
3465                }
3466                if (cache.Length > 0x600000)
3467                {
3468                    sw.Write(cache.ToString());
3469                    cache = new StringBuilder();
3470                }
3471            }
3472
3473            if (row != -1) cache.Append("</row>");
3474            cache.Append("</sheetData>");
3475            sw.Write(cache.ToString());
3476            sw.Flush();
3477        }
3478
3479        private object GetFormulaValue(object v)
3480        {
3481            //if (_package.Workbook._isCalculated)
3482            //{                   
3483            if (v != null && v.ToString()!="")
3484            {
3485                return "<v>" + SecurityElement.Escape(GetValueForXml(v)) + "</v>"; //Fixes issue 15071
3486            }           
3487            else
3488            {
3489                return "";
3490            }
3491        }
3492
3493        private string GetCellType(object v, bool allowStr=false)
3494        {
3495            if (v is bool)
3496            {
3497                return " t=\"b\"";
3498            }
3499            else if ((v is double && double.IsInfinity((double)v)) || v is ExcelErrorValue)
3500            {
3501                return " t=\"e\"";
3502            }
3503            else if(allowStr && v!=null && !(v.GetType().IsPrimitive || v is double || v is decimal || v is DateTime || v is TimeSpan))
3504            {
3505                return " t=\"str\"";
3506            }
3507            else
3508            {
3509                return "";
3510            }
3511        }
3512
3513        private string GetValueForXml(object v)
3514        {
3515            string s;
3516            try
3517            {
3518                if (v is DateTime)
3519                {
3520                    double sdv = ((DateTime)v).ToOADate();
3521
3522                    if (Workbook.Date1904)
3523                    {
3524                        sdv -= ExcelWorkbook.date1904Offset;
3525                    }
3526
3527                    s = sdv.ToString(CultureInfo.InvariantCulture);
3528                }
3529                else if (v is TimeSpan)
3530                {
3531                    s = new DateTime(((TimeSpan)v).Ticks).ToOADate().ToString(CultureInfo.InvariantCulture); ;
3532                }
3533                else if(v.GetType().IsPrimitive || v is double || v is decimal)
3534                {
3535                    if (v is double && double.IsNaN((double)v))
3536                    {
3537                        s = "";
3538                    }
3539                    else if (v is double && double.IsInfinity((double)v))
3540                    {
3541                        s = "#NUM!";
3542                    }
3543                    else
3544                    {
3545                        s = Convert.ToDouble(v, CultureInfo.InvariantCulture).ToString("R15", CultureInfo.InvariantCulture);
3546                    }
3547                }
3548                else
3549                {
3550                    s = v.ToString();
3551                }
3552            }
3553
3554            catch
3555            {
3556                s = "0";
3557            }
3558            return s;
3559        }
3560        private void WriteRow(StringBuilder cache, ExcelStyleCollection<ExcelXfs> cellXfs, int prevRow, int row)
3561        {
3562            if (prevRow != -1) cache.Append("</row>");
3563            //ulong rowID = ExcelRow.GetRowID(SheetID, row);
3564            cache.AppendFormat("<row r=\"{0}\" ", row);
3565            RowInternal currRow = _values.GetValue(row, 0) as RowInternal;
3566            if (currRow != null)
3567            {
3568
3569                if (currRow.Hidden == true)
3570                {
3571                    cache.Append("ht=\"0\" hidden=\"1\" ");
3572                }
3573                else if (currRow.Height != DefaultRowHeight && currRow.Height>=0)
3574                {
3575                    cache.AppendFormat(string.Format(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height));
3576                    if (currRow.CustomHeight)
3577                    {
3578                        cache.Append("customHeight=\"1\" ");
3579                    }
3580                }
3581
3582                if (currRow.OutlineLevel > 0)
3583                {
3584                    cache.AppendFormat("outlineLevel =\"{0}\" ", currRow.OutlineLevel);
3585                    if (currRow.Collapsed)
3586                    {
3587                        if (currRow.Hidden)
3588                        {
3589                            cache.Append(" collapsed=\"1\" ");
3590                        }
3591                        else
3592                        {
3593                            cache.Append(" collapsed=\"1\" hidden=\"1\" "); //Always hidden
3594                        }
3595                    }
3596                }
3597                if (currRow.Phonetic)
3598                {
3599                    cache.Append("ph=\"1\" ");
3600                }
3601            }
3602            var s = _styles.GetValue(row, 0);
3603            if (s > 0)
3604            {
3605                cache.AppendFormat("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID);
3606            }
3607            cache.Append(">");
3608        }
3609        private void WriteRow(StreamWriter sw, ExcelStyleCollection<ExcelXfs> cellXfs, int prevRow, int row)
3610        {
3611            if (prevRow != -1) sw.Write("</row>");
3612            //ulong rowID = ExcelRow.GetRowID(SheetID, row);
3613            sw.Write("<row r=\"{0}\" ", row);
3614            RowInternal currRow = _values.GetValue(row, 0) as RowInternal;
3615            if (currRow!=null)
3616            {
3617               
3618                if (currRow.Hidden == true)
3619                {
3620                    sw.Write("ht=\"0\" hidden=\"1\" ");
3621                }
3622                else if (currRow.Height != DefaultRowHeight)
3623                {
3624                    sw.Write(string.Format(CultureInfo.InvariantCulture, "ht=\"{0}\" ", currRow.Height));
3625                    if (currRow.CustomHeight)
3626                    {
3627                        sw.Write("customHeight=\"1\" ");
3628                    }
3629                }
3630
3631                if (currRow.OutlineLevel > 0)
3632                {
3633                    sw.Write("outlineLevel =\"{0}\" ", currRow.OutlineLevel);
3634                    if (currRow.Collapsed)
3635                    {
3636                        if (currRow.Hidden)
3637                        {
3638                            sw.Write(" collapsed=\"1\" ");
3639                        }
3640                        else
3641                        {
3642                            sw.Write(" collapsed=\"1\" hidden=\"1\" "); //Always hidden
3643                        }
3644                    }
3645                }
3646                if (currRow.Phonetic)
3647                {
3648                    sw.Write("ph=\"1\" ");
3649                }
3650            }
3651            var s = _styles.GetValue(row, 0);
3652            if (s > 0)
3653            {
3654                sw.Write("s=\"{0}\" customFormat=\"1\"", cellXfs[s].newID);
3655            }
3656            sw.Write(">");
3657        }
3658
3659        /// <summary>
3660        /// Update xml with hyperlinks
3661        /// </summary>
3662        /// <param name="sw">The stream</param>
3663        private void UpdateHyperLinks(StreamWriter sw)
3664        {
3665                Dictionary<string, string> hyps = new Dictionary<string, string>();
3666                var cse = new CellsStoreEnumerator<Uri>(_hyperLinks);
3667                bool first = true;
3668                //foreach (ulong cell in _hyperLinks)
3669                while(cse.Next())
3670                {
3671                    if (first)
3672                    {
3673                        sw.Write("<hyperlinks>");
3674                        first = false;
3675                    }
3676                    //int row, col;
3677                    var uri = _hyperLinks.GetValue(cse.Row, cse.Column);
3678                    //ExcelCell cell = _cells[cellId] as ExcelCell;
3679                    if (uri is ExcelHyperLink && !string.IsNullOrEmpty((uri as ExcelHyperLink).ReferenceAddress))
3680                    {
3681                        ExcelHyperLink hl = uri as ExcelHyperLink;
3682                        sw.Write("<hyperlink ref=\"{0}\" location=\"{1}\" {2}{3}/>",
3683                                Cells[cse.Row, cse.Column, cse.Row + hl.RowSpann, cse.Column + hl.ColSpann].Address,
3684                                ExcelCellBase.GetFullAddress(SecurityElement.Escape(Name), SecurityElement.Escape(hl.ReferenceAddress)),
3685                                    string.IsNullOrEmpty(hl.Display) ? "" : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ",
3686                                    string.IsNullOrEmpty(hl.ToolTip) ? "" : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" ");
3687                    }
3688                    else if( uri!=null)
3689                    {
3690                        string id;
3691                        Uri hyp;
3692                        if (uri is ExcelHyperLink)
3693                        {
3694                            hyp = ((ExcelHyperLink)uri).OriginalUri;
3695                        }
3696                        else
3697                        {
3698                            hyp = uri;
3699                        }
3700                        if (hyps.ContainsKey(hyp.OriginalString))
3701                        {
3702                            id = hyps[hyp.OriginalString];
3703                        }
3704                        else
3705                        {
3706                            var relationship = Part.CreateRelationship(hyp, Packaging.TargetMode.External, ExcelPackage.schemaHyperlink);
3707                            if (uri is ExcelHyperLink)
3708                            {
3709                                ExcelHyperLink hl = uri as ExcelHyperLink;
3710                                sw.Write("<hyperlink ref=\"{0}\" {2}{3}r:id=\"{1}\" />", ExcelCellBase.GetAddress(cse.Row, cse.Column), relationship.Id,                               
3711                                    string.IsNullOrEmpty(hl.Display) ? "" : "display=\"" + SecurityElement.Escape(hl.Display) + "\" ",
3712                                    string.IsNullOrEmpty(hl.ToolTip) ? "" : "tooltip=\"" + SecurityElement.Escape(hl.ToolTip) + "\" ");
3713                            }
3714                            else
3715                            {
3716                                sw.Write("<hyperlink ref=\"{0}\" r:id=\"{1}\" />", ExcelCellBase.GetAddress(cse.Row, cse.Column), relationship.Id);
3717                            }
3718                            id = relationship.Id;
3719                        }
3720                        //cell.HyperLinkRId = id;
3721                    }
3722                }
3723                if (!first)
3724                {
3725                    sw.Write("</hyperlinks>");
3726                }
3727        }
3728        /// <summary>
3729        /// Create the hyperlinks node in the XML
3730        /// </summary>
3731        /// <returns></returns>
3732        private XmlNode CreateHyperLinkCollection()
3733        {
3734            XmlElement hl=_worksheetXml.CreateElement("hyperlinks",ExcelPackage.schemaMain);
3735            XmlNode prevNode = _worksheetXml.SelectSingleNode("//d:conditionalFormatting", NameSpaceManager);
3736            if (prevNode == null)
3737            {
3738                prevNode = _worksheetXml.SelectSingleNode("//d:mergeCells", NameSpaceManager);
3739                if (prevNode == null)
3740                {
3741                    prevNode = _worksheetXml.SelectSingleNode("//d:sheetData", NameSpaceManager);
3742                }
3743            }
3744            return _worksheetXml.DocumentElement.InsertAfter(hl, prevNode);
3745        }
3746        /// <summary>
3747        /// Dimension address for the worksheet.
3748        /// Top left cell to Bottom right.
3749        /// If the worksheet has no cells, null is returned
3750        /// </summary>
3751        public ExcelAddressBase Dimension
3752        {
3753            get
3754            {
3755                CheckSheetType();
3756                int fromRow, fromCol, toRow, toCol;
3757                if (_values.GetDimension(out fromRow, out fromCol, out toRow, out toCol))
3758                {
3759                    var addr = new ExcelAddressBase(fromRow, fromCol, toRow, toCol);
3760                    addr._ws = Name;
3761                    return addr;
3762                }
3763                else
3764                {
3765                    return null;
3766                }
3767            }
3768        }
3769        ExcelSheetProtection _protection=null;
3770        /// <summary>
3771        /// Access to sheet protection properties
3772        /// </summary>
3773        public ExcelSheetProtection Protection
3774        {
3775            get
3776            {
3777                if (_protection == null)
3778                {
3779                    _protection = new ExcelSheetProtection(NameSpaceManager, TopNode, this);
3780                }
3781                return _protection;
3782            }
3783        }
3784
3785        private ExcelProtectedRangeCollection _protectedRanges;
3786        public ExcelProtectedRangeCollection ProtectedRanges
3787        {
3788            get
3789            {
3790                if (_protectedRanges == null)
3791                    _protectedRanges = new ExcelProtectedRangeCollection(NameSpaceManager, TopNode, this);
3792                return _protectedRanges;
3793            }
3794        }
3795
3796        #region Drawing
3797        ExcelDrawings _drawings = null;
3798        /// <summary>
3799        /// Collection of drawing-objects like shapes, images and charts
3800        /// </summary>
3801        public ExcelDrawings Drawings
3802        {
3803            get
3804            {
3805                if (_drawings == null)
3806                {
3807                    _drawings = new ExcelDrawings(_package, this);
3808                }
3809                return _drawings;
3810            }
3811        }
3812        #endregion
3813        ExcelTableCollection _tables = null;
3814        /// <summary>
3815        /// Tables defined in the worksheet.
3816        /// </summary>
3817        public ExcelTableCollection Tables
3818        {
3819            get
3820            {
3821                CheckSheetType();
3822                if (_tables == null)
3823                {
3824                    _tables = new ExcelTableCollection(this);
3825                }
3826                return _tables;
3827            }
3828        }
3829        ExcelPivotTableCollection _pivotTables = null;
3830        /// <summary>
3831        /// Pivottables defined in the worksheet.
3832        /// </summary>
3833        public ExcelPivotTableCollection PivotTables
3834        {
3835            get
3836            {
3837                CheckSheetType();
3838                if (_pivotTables == null)
3839                {
3840                    _pivotTables = new ExcelPivotTableCollection(this);
3841                }
3842                return _pivotTables;
3843            }
3844        }
3845        private ExcelConditionalFormattingCollection _conditionalFormatting = null;
3846        /// <summary>
3847        /// ConditionalFormatting defined in the worksheet. Use the Add methods to create ConditionalFormatting and add them to the worksheet. Then
3848        /// set the properties on the instance returned.
3849        /// </summary>
3850        /// <seealso cref="ExcelConditionalFormattingCollection"/>
3851        public ExcelConditionalFormattingCollection ConditionalFormatting
3852        {
3853            get
3854            {
3855                CheckSheetType();
3856                if (_conditionalFormatting == null)
3857                {
3858                    _conditionalFormatting = new ExcelConditionalFormattingCollection(this);
3859                }
3860                return _conditionalFormatting;
3861            }
3862        }
3863        private ExcelDataValidationCollection _dataValidation = null;
3864        /// <summary>
3865        /// DataValidation defined in the worksheet. Use the Add methods to create DataValidations and add them to the worksheet. Then
3866        /// set the properties on the instance returned.
3867        /// </summary>
3868        /// <seealso cref="ExcelDataValidationCollection"/>
3869        public ExcelDataValidationCollection DataValidations
3870        {
3871            get
3872            {
3873                CheckSheetType();
3874                if (_dataValidation == null)
3875                {
3876                    _dataValidation = new ExcelDataValidationCollection(this);
3877                }
3878                return _dataValidation;
3879            }
3880        }
3881        ExcelBackgroundImage _backgroundImage = null;
3882        /// <summary>
3883        /// An image displayed as the background of the worksheet.
3884        /// </summary>
3885        public ExcelBackgroundImage BackgroundImage
3886        {
3887            get
3888            {
3889                if (_backgroundImage == null)
3890                {
3891                    _backgroundImage = new ExcelBackgroundImage(NameSpaceManager, TopNode, this);
3892                }
3893                return _backgroundImage;
3894            }
3895        }
3896        /// <summary>
3897    /// Returns the style ID given a style name. 
3898    /// The style ID will be created if not found, but only if the style name exists!
3899    /// </summary>
3900    /// <param name="StyleName"></param>
3901    /// <returns></returns>
3902    internal int GetStyleID(string StyleName)
3903    {
3904      ExcelNamedStyleXml namedStyle=null;
3905            Workbook.Styles.NamedStyles.FindByID(StyleName, ref namedStyle);
3906            if (namedStyle.XfId == int.MinValue)
3907            {
3908                namedStyle.XfId=Workbook.Styles.CellXfs.FindIndexByID(namedStyle.Style.Id);
3909            }
3910            return namedStyle.XfId;
3911    }
3912        /// <summary>
3913        /// The workbook object
3914        /// </summary>
3915        public ExcelWorkbook Workbook
3916        {
3917            get
3918            {
3919                return _package.Workbook;
3920            }
3921        }
3922    #endregion
3923        #endregion  // END Worksheet Private Methods
3924
3925        /// <summary>
3926        /// Get the next ID from a shared formula or an Array formula
3927        /// Sharedforumlas will have an id from 0-x. Array formula ids start from 0x4000001-.
3928        /// </summary>
3929        /// <param name="isArray">If the formula is an array formula</param>
3930        /// <returns></returns>
3931        internal int GetMaxShareFunctionIndex(bool isArray)
3932        {
3933            int i=_sharedFormulas.Count + 1;
3934            if (isArray)
3935                i |= 0x40000000;
3936
3937            while(_sharedFormulas.ContainsKey(i))
3938            {
3939                i++;
3940            }
3941            return i;
3942        }
3943        internal void SetHFLegacyDrawingRel(string relID)
3944        {
3945            SetXmlNodeString("d:legacyDrawingHF/@r:id", relID);
3946        }
3947        internal void RemoveLegacyDrawingRel(string relID)
3948        {
3949            var n = WorksheetXml.DocumentElement.SelectSingleNode(string.Format("d:legacyDrawing[@r:id=\"{0}\"]", relID), NameSpaceManager);
3950            if (n != null)
3951            {
3952                n.ParentNode.RemoveChild(n);
3953            }
3954        }
3955
3956        internal void UpdateCellsWithDate1904Setting()
3957        {
3958            var cse = new CellsStoreEnumerator<object>(_values);
3959            var offset = Workbook.Date1904 ? -ExcelWorkbook.date1904Offset : ExcelWorkbook.date1904Offset;
3960            while(cse.MoveNext())
3961            {
3962                if (cse.Value is DateTime)
3963                {
3964                    try
3965                    {
3966                        double sdv = ((DateTime)cse.Value).ToOADate();
3967                        sdv += offset;
3968
3969                        cse.Value = DateTime.FromOADate(sdv);
3970                    }
3971                    catch
3972                    {
3973                    }
3974                }
3975            }
3976        }
3977        internal string GetFormula(int row, int col)
3978        {
3979            var v = _formulas.GetValue(row, col);
3980            if (v is int)
3981            {
3982                return _sharedFormulas[(int)v].GetFormula(row,col, Name);
3983            }
3984            else if (v != null)
3985            {
3986                return v.ToString();
3987            }
3988            else
3989            {
3990                return "";
3991            }
3992        }
3993        internal string GetFormulaR1C1(int row, int col)
3994        {
3995            var v = _formulas.GetValue(row, col);
3996            if (v is int)
3997            {
3998                var sf = _sharedFormulas[(int)v];
3999                return ExcelCellBase.TranslateToR1C1(sf.Formula, sf.StartRow, sf.StartCol);
4000            }
4001            else if (v != null)
4002            {
4003                return ExcelCellBase.TranslateToR1C1(v.ToString(), row, col);
4004            }
4005            else
4006            {
4007                return "";
4008            }
4009        }
4010
4011        private void DisposeInternal(IDisposable candidateDisposable)
4012        {
4013            if (candidateDisposable != null)
4014            {
4015                candidateDisposable.Dispose();
4016            }
4017        }
4018
4019
4020        public void Dispose()
4021        {
4022            DisposeInternal(_values);
4023            DisposeInternal(_formulas);
4024            DisposeInternal(_flags);
4025            DisposeInternal(_hyperLinks);
4026            DisposeInternal(_styles);
4027            DisposeInternal(_types);
4028            DisposeInternal(_commentsStore);
4029            DisposeInternal(_formulaTokens);
4030
4031            _values = null;
4032            _formulas = null;
4033            _flags = null;
4034            _hyperLinks = null;
4035            _styles = null;
4036            _types = null;
4037            _commentsStore = null;
4038            _formulaTokens = null;
4039
4040            _package = null;
4041            _pivotTables = null;
4042            _protection = null;
4043            if(_sharedFormulas != null) _sharedFormulas.Clear();
4044            _sharedFormulas = null;
4045            _sheetView = null;
4046            _tables = null;
4047            _vmlDrawings = null;
4048            _conditionalFormatting = null;
4049            _dataValidation = null;
4050            _drawings = null;
4051        }
4052
4053        /// <summary>
4054        /// Get the ExcelColumn for column (span ColumnMin and ColumnMax)
4055        /// </summary>
4056        /// <param name="column"></param>
4057        /// <returns></returns>
4058        internal ExcelColumn GetColumn(int column)
4059        {
4060            var c = _values.GetValue(0, column) as ExcelColumn;
4061            if (c == null)
4062            {
4063                int row = 0, col = column;
4064                if (_values.PrevCell(ref row, ref col))
4065                {
4066                    c = _values.GetValue(0, col) as ExcelColumn;
4067                    if (c != null && c.ColumnMax >= column)
4068                    {
4069                        return c;
4070                    }
4071                    return null;
4072                }
4073            }
4074            return c;
4075
4076        }
4077    }  // END class Worksheet
4078}
Note: See TracBrowser for help on using the repository browser.