Free cookie consent management tool by TermsFeed Policy Generator

source: branches/Breadcrumbs/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/3.1.3/EPPlus-3.1.3/ExcelWorkbook.cs @ 11571

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

#1730:

  • added SymbolicDataAnalysisExpressionExcelFormatter
  • changed modifiers in SymbolicExpressionTreeChart of methods SaveImageAsBitmap and SaveImageAsEmf to public
  • added menu item ExportSymbolicSolutionToExcelMenuItem to export a symbolic solution to an excel file
  • added EPPlus-3.1.3 to ExtLibs
File size: 31.8 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-01-01
30 * Jan Källman        License changed GPL-->LGPL 2011-12-27
31 *******************************************************************************/
32using System;
33using System.Xml;
34using System.IO;
35using System.IO.Packaging;
36using System.Collections.Generic;
37using System.Text;
38using System.Security;
39using System.Globalization;
40using System.Text.RegularExpressions;
41using OfficeOpenXml.VBA;
42using System.Drawing;
43namespace OfficeOpenXml
44{
45  #region Public Enum ExcelCalcMode
46  /// <summary>
47  /// How the application should calculate formulas in the workbook
48  /// </summary>
49  public enum ExcelCalcMode
50  {
51    /// <summary>
52    /// Indicates that calculations in the workbook are performed automatically when cell values change.
53    /// The application recalculates those cells that are dependent on other cells that contain changed values.
54    /// This mode of calculation helps to avoid unnecessary calculations.
55    /// </summary>
56    Automatic,
57    /// <summary>
58    /// Indicates tables be excluded during automatic calculation
59    /// </summary>
60    AutomaticNoTable,
61    /// <summary>
62    /// Indicates that calculations in the workbook be triggered manually by the user.
63    /// </summary>
64    Manual
65  }
66  #endregion
67
68  /// <summary>
69  /// Represents the Excel workbook and provides access to all the
70  /// document properties and worksheets within the workbook.
71  /// </summary>
72  public sealed class ExcelWorkbook : XmlHelper
73  {
74    internal class SharedStringItem
75    {
76      internal int pos;
77      internal string Text;
78      internal bool isRichText = false;
79    }
80    #region Private Properties
81    internal ExcelPackage _package;
82    private ExcelWorksheets _worksheets;
83    private OfficeProperties _properties;
84
85    private ExcelStyles _styles;
86    #endregion
87
88    #region ExcelWorkbook Constructor
89    /// <summary>
90    /// Creates a new instance of the ExcelWorkbook class.
91    /// </summary>
92    /// <param name="package">The parent package</param>
93    /// <param name="namespaceManager">NamespaceManager</param>
94    internal ExcelWorkbook(ExcelPackage package, XmlNamespaceManager namespaceManager) :
95      base(namespaceManager)
96    {
97      _package = package;
98      WorkbookUri = new Uri("/xl/workbook.xml", UriKind.Relative);
99      SharedStringsUri = new Uri("/xl/sharedStrings.xml", UriKind.Relative);
100      StylesUri = new Uri("/xl/styles.xml", UriKind.Relative);
101
102      _names = new ExcelNamedRangeCollection(this);
103      _namespaceManager = namespaceManager;
104      TopNode = WorkbookXml.DocumentElement;
105      SchemaNodeOrder = new string[] { "fileVersion", "fileSharing", "workbookPr", "workbookProtection", "bookViews", "sheets", "functionGroups", "functionPrototypes", "externalReferences", "definedNames", "calcPr", "oleSize", "customWorkbookViews", "pivotCaches", "smartTagPr", "smartTagTypes", "webPublishing", "fileRecoveryPr", };
106      GetSharedStrings();
107    }
108    #endregion
109
110    internal Dictionary<string, SharedStringItem> _sharedStrings = new Dictionary<string, SharedStringItem>(); //Used when reading cells.
111    internal List<SharedStringItem> _sharedStringsList = new List<SharedStringItem>(); //Used when reading cells.
112    internal ExcelNamedRangeCollection _names;
113    internal int _nextDrawingID = 0;
114    internal int _nextTableID = 1;
115    internal int _nextPivotTableID = 1;
116    internal XmlNamespaceManager _namespaceManager;
117    /// <summary>
118    /// Read shared strings to list
119    /// </summary>
120    private void GetSharedStrings()
121    {
122      if (_package.Package.PartExists(SharedStringsUri))
123      {
124        var xml = _package.GetXmlFromUri(SharedStringsUri);
125        XmlNodeList nl = xml.SelectNodes("//d:sst/d:si", NameSpaceManager);
126        _sharedStringsList = new List<SharedStringItem>();
127        if (nl != null)
128        {
129          foreach (XmlNode node in nl)
130          {
131            XmlNode n = node.SelectSingleNode("d:t", NameSpaceManager);
132            if (n != null)
133            {
134              _sharedStringsList.Add(new SharedStringItem() { Text = ExcelDecodeString(n.InnerText) });
135            }
136            else
137            {
138              _sharedStringsList.Add(new SharedStringItem() { Text = node.InnerXml, isRichText = true });
139            }
140          }
141        }
142      }
143    }
144    internal void GetDefinedNames()
145    {
146      XmlNodeList nl = WorkbookXml.SelectNodes("//d:definedNames/d:definedName", NameSpaceManager);
147      if (nl != null)
148      {
149        foreach (XmlElement elem in nl)
150        {
151          string fullAddress = elem.InnerText;
152
153          int localSheetID;
154          ExcelWorksheet nameWorksheet;
155          if(!int.TryParse(elem.GetAttribute("localSheetId"), out localSheetID))
156          {
157            localSheetID = -1;
158            nameWorksheet=null;
159          }
160          else
161          {
162            nameWorksheet=Worksheets[localSheetID + 1];
163          }
164          var addressType = ExcelAddressBase.IsValid(fullAddress);
165          ExcelRangeBase range;
166          ExcelNamedRange namedRange;
167
168          if (fullAddress.IndexOf("[") > -1)
169          {
170            int start = fullAddress.IndexOf("[");
171            int end = fullAddress.IndexOf("]", start);
172            if (start >= 0 && end >= 0)
173            {
174
175              string externalIndex = fullAddress.Substring(start + 1, end - start - 1);
176              int index;
177              if (int.TryParse(externalIndex, out index))
178              {
179                if (index > 0 && index <= _externalReferences.Count)
180                {
181                  fullAddress = fullAddress.Substring(0, start) + "[" + _externalReferences[index - 1] + "]" + fullAddress.Substring(end + 1);
182                }
183              }
184            }
185          }
186
187          if (addressType == ExcelAddressBase.AddressType.Invalid || addressType == ExcelAddressBase.AddressType.InternalName || addressType == ExcelAddressBase.AddressType.ExternalName)    //A value or a formula
188          {
189            double value;
190            range = new ExcelRangeBase(this, nameWorksheet, elem.GetAttribute("name"), true);
191            if (nameWorksheet == null)
192            {
193              namedRange = _names.Add(elem.GetAttribute("name"), range);
194            }
195            else
196            {
197              namedRange = nameWorksheet.Names.Add(elem.GetAttribute("name"), range);
198            }
199           
200            if (fullAddress.StartsWith("\"")) //String value
201            {
202              namedRange.NameValue = fullAddress.Substring(1,fullAddress.Length-2);
203            }
204            else if (double.TryParse(fullAddress, NumberStyles.Any, CultureInfo.InvariantCulture, out value))
205            {
206              namedRange.NameValue = value;
207            }
208            else
209            {
210              namedRange.NameFormula = fullAddress;
211            }
212          }
213          else
214          {
215            ExcelAddress addr = new ExcelAddress(fullAddress);
216            if (localSheetID > -1)
217            {
218              if (string.IsNullOrEmpty(addr._ws))
219              {
220                namedRange = Worksheets[localSheetID + 1].Names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, Worksheets[localSheetID + 1], fullAddress, false));
221              }
222              else
223              {
224                namedRange = Worksheets[localSheetID + 1].Names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, Worksheets[addr._ws], fullAddress, false));
225              }
226            }
227            else
228            {
229              var ws = Worksheets[addr._ws];
230              namedRange = _names.Add(elem.GetAttribute("name"), new ExcelRangeBase(this, ws, fullAddress, false));
231            }
232          }
233          if (elem.GetAttribute("hidden") == "1" && namedRange != null) namedRange.IsNameHidden = true;
234          if(!string.IsNullOrEmpty(elem.GetAttribute("comment"))) namedRange.NameComment=elem.GetAttribute("comment");
235        }
236      }
237    }
238    #region Worksheets
239    /// <summary>
240    /// Provides access to all the worksheets in the workbook.
241    /// </summary>
242    public ExcelWorksheets Worksheets
243    {
244      get
245      {
246        if (_worksheets == null)
247        {
248          var sheetsNode = _workbookXml.DocumentElement.SelectSingleNode("d:sheets", _namespaceManager);
249          if (sheetsNode == null)
250          {
251            sheetsNode = CreateNode("d:sheets");
252          }
253         
254          _worksheets = new ExcelWorksheets(_package, _namespaceManager, sheetsNode);
255        }
256        return (_worksheets);
257      }
258    }
259    #endregion
260
261    /// <summary>
262    /// Provides access to named ranges
263    /// </summary>
264    public ExcelNamedRangeCollection Names
265    {
266      get
267      {
268        return _names;
269      }
270    }
271    #region Workbook Properties
272    decimal _standardFontWidth = decimal.MinValue;
273        string fontID = "";
274    /// <summary>
275    /// Max font width for the workbook
276        /// <remarks>This method uses GDI. If you use Asure or another environment that does not support GDI, you have to set this value manually if you don't use the standard Calibri font</remarks>
277    /// </summary>
278    public decimal MaxFontWidth
279    {
280      get
281      {
282                if (_standardFontWidth == decimal.MinValue || fontID != Styles.Fonts[0].Id)
283        {
284          var font = Styles.Fonts[0];
285                    try
286                    {
287                        Font f = new Font(font.Name, font.Size);
288                        fontID = font.Id;
289                        using (Bitmap b = new Bitmap(1, 1))
290                        {
291                            using (Graphics g = Graphics.FromImage(b))
292                            {
293                                _standardFontWidth = (decimal)Math.Truncate(g.MeasureString("00", f).Width - g.MeasureString("0", f).Width);
294                            }
295                        }
296                        if (_standardFontWidth <= 0) //No GDI?
297                        {
298                            _standardFontWidth = (int)(font.Size * (2D / 3D)); //Aprox. for Calibri.
299                        }
300                    }
301                    catch   //Error, set default value
302                    {
303                        _standardFontWidth = (int)(font.Size * (2D / 3D)); //Aprox for Calibri.
304                    }
305        }
306        return _standardFontWidth;
307      }
308            set
309            {
310                _standardFontWidth = value;
311            }
312    }
313    ExcelProtection _protection = null;
314    /// <summary>
315    /// Access properties to protect or unprotect a workbook
316    /// </summary>
317    public ExcelProtection Protection
318    {
319      get
320      {
321        if (_protection == null)
322        {
323          _protection = new ExcelProtection(NameSpaceManager, TopNode, this);
324          _protection.SchemaNodeOrder = SchemaNodeOrder;
325        }
326        return _protection;
327      }
328    }
329    ExcelWorkbookView _view = null;
330    /// <summary>
331    /// Access to workbook view properties
332    /// </summary>
333    public ExcelWorkbookView View
334    {
335      get
336      {
337        if (_view == null)
338        {
339          _view = new ExcelWorkbookView(NameSpaceManager, TopNode, this);
340        }
341        return _view;
342      }
343    }
344        ExcelVbaProject _vba = null;
345        /// <summary>
346        /// A reference to the VBA project.
347        /// Null if no project exists.
348        /// User Workbook.CreateVBAProject to create a new VBA-Project
349        /// </summary>
350        public ExcelVbaProject VbaProject
351        {
352            get
353            {
354                if (_vba == null)
355                {
356                    if(_package.Package.PartExists(new Uri(ExcelVbaProject.PartUri, UriKind.Relative)))
357                    {
358                        _vba = new ExcelVbaProject(this);
359                    }
360                }
361                return _vba;
362            }
363        }
364        /// <summary>
365        /// Create an empty VBA project.
366        /// </summary>
367        public void CreateVBAProject()
368        {
369            if (_vba != null || _package.Package.PartExists(new Uri(ExcelVbaProject.PartUri, UriKind.Relative)))
370            {
371                throw (new InvalidOperationException("VBA project already exists."));
372            }
373                       
374            _vba = new ExcelVbaProject(this);
375            _vba.Create();
376        }
377    /// <summary>
378    /// URI to the workbook inside the package
379    /// </summary>
380    internal Uri WorkbookUri { get; private set; }
381    /// <summary>
382        /// URI to the styles inside the package
383    /// </summary>
384    internal Uri StylesUri { get; private set; }
385    /// <summary>
386        /// URI to the shared strings inside the package
387    /// </summary>
388    internal Uri SharedStringsUri { get; private set; }
389    /// <summary>
390    /// Returns a reference to the workbook's part within the package
391    /// </summary>
392    internal PackagePart Part { get { return (_package.Package.GetPart(WorkbookUri)); } }
393   
394    #region WorkbookXml
395    private XmlDocument _workbookXml;
396    /// <summary>
397    /// Provides access to the XML data representing the workbook in the package.
398    /// </summary>
399    public XmlDocument WorkbookXml
400    {
401      get
402      {
403        if (_workbookXml == null)
404        {
405          CreateWorkbookXml(_namespaceManager);
406        }
407        return (_workbookXml);
408      }
409    }
410        const string codeModuleNamePath = "d:workbookPr/@codeName";
411        internal string CodeModuleName
412        {
413            get
414            {
415                return GetXmlNodeString(codeModuleNamePath);
416            }
417            set
418            {
419                SetXmlNodeString(codeModuleNamePath,value);
420            }
421        }
422        internal void CodeNameChange(string value)
423        {
424            CodeModuleName = value;
425        }
426        public VBA.ExcelVBAModule CodeModule
427        {
428            get
429            {
430                if (VbaProject != null)
431                {
432                    return VbaProject.Modules[CodeModuleName];
433                }
434                else
435                {
436                    return null;
437                }
438            }
439        }
440    /// <summary>
441    /// Create or read the XML for the workbook.
442    /// </summary>
443    private void CreateWorkbookXml(XmlNamespaceManager namespaceManager)
444    {
445      if (_package.Package.PartExists(WorkbookUri))
446        _workbookXml = _package.GetXmlFromUri(WorkbookUri);
447      else
448      {
449        // create a new workbook part and add to the package
450        PackagePart partWorkbook = _package.Package.CreatePart(WorkbookUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml", _package.Compression);
451
452        // create the workbook
453        _workbookXml = new XmlDocument(namespaceManager.NameTable);               
454       
455        _workbookXml.PreserveWhitespace = ExcelPackage.preserveWhitespace;
456        // create the workbook element
457        XmlElement wbElem = _workbookXml.CreateElement("workbook", ExcelPackage.schemaMain);
458
459        // Add the relationships namespace
460        wbElem.SetAttribute("xmlns:r", ExcelPackage.schemaRelationships);
461
462        _workbookXml.AppendChild(wbElem);
463
464        // create the bookViews and workbooks element
465        XmlElement bookViews = _workbookXml.CreateElement("bookViews", ExcelPackage.schemaMain);
466        wbElem.AppendChild(bookViews);
467        XmlElement workbookView = _workbookXml.CreateElement("workbookView", ExcelPackage.schemaMain);
468        bookViews.AppendChild(workbookView);
469
470        // save it to the package
471        StreamWriter stream = new StreamWriter(partWorkbook.GetStream(FileMode.Create, FileAccess.Write));
472        _workbookXml.Save(stream);
473        stream.Close();
474        _package.Package.Flush();
475      }
476    }
477    #endregion
478    #region StylesXml
479    private XmlDocument _stylesXml;
480    /// <summary>
481    /// Provides access to the XML data representing the styles in the package.
482    /// </summary>
483    public XmlDocument StylesXml
484    {
485      get
486      {
487        if (_stylesXml == null)
488        {
489          if (_package.Package.PartExists(StylesUri))
490            _stylesXml = _package.GetXmlFromUri(StylesUri);
491          else
492          {
493            // create a new styles part and add to the package
494            PackagePart part = _package.Package.CreatePart(StylesUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml", _package.Compression);
495            // create the style sheet
496
497            StringBuilder xml = new StringBuilder("<styleSheet xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\">");
498            xml.Append("<numFmts />");
499            xml.Append("<fonts count=\"1\"><font><sz val=\"11\" /><name val=\"Calibri\" /></font></fonts>");
500            xml.Append("<fills><fill><patternFill patternType=\"none\" /></fill><fill><patternFill patternType=\"gray125\" /></fill></fills>");
501            xml.Append("<borders><border><left /><right /><top /><bottom /><diagonal /></border></borders>");
502            xml.Append("<cellStyleXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" /></cellStyleXfs>");
503            xml.Append("<cellXfs count=\"1\"><xf numFmtId=\"0\" fontId=\"0\" xfId=\"0\" /></cellXfs>");
504            xml.Append("<cellStyles><cellStyle name=\"Normal\" xfId=\"0\" builtinId=\"0\" /></cellStyles>");
505                        xml.Append("<dxfs count=\"0\" />");
506                        xml.Append("</styleSheet>");
507           
508            _stylesXml = new XmlDocument();
509            _stylesXml.LoadXml(xml.ToString());
510           
511            //Save it to the package
512            StreamWriter stream = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
513
514            _stylesXml.Save(stream);
515            stream.Close();
516            _package.Package.Flush();
517
518            // create the relationship between the workbook and the new shared strings part
519            _package.Workbook.Part.CreateRelationship(PackUriHelper.GetRelativeUri(WorkbookUri, StylesUri), TargetMode.Internal, ExcelPackage.schemaRelationships + "/styles");
520            _package.Package.Flush();
521          }
522        }
523        return (_stylesXml);
524      }
525      set
526      {
527        _stylesXml = value;
528      }
529    }
530    /// <summary>
531    /// Package styles collection. Used internally to access style data.
532    /// </summary>
533    public ExcelStyles Styles
534    {
535      get
536      {
537        if (_styles == null)
538        {
539          _styles = new ExcelStyles(NameSpaceManager, StylesXml, this);
540        }
541        return _styles;
542      }
543    }
544    #endregion
545
546    #region Office Document Properties
547    /// <summary>
548    /// The office document properties
549    /// </summary>
550    public OfficeProperties Properties
551    {
552      get
553      {
554        if (_properties == null)
555        {
556          //  Create a NamespaceManager to handle the default namespace,
557          //  and create a prefix for the default namespace:                   
558          _properties = new OfficeProperties(_package, NameSpaceManager);
559        }
560        return _properties;
561      }
562    }
563    #endregion
564
565    #region CalcMode
566    private string CALC_MODE_PATH = "d:calcPr/@calcMode";
567    /// <summary>
568    /// Calculation mode for the workbook.
569    /// </summary>
570    public ExcelCalcMode CalcMode
571    {
572      get
573      {
574        string calcMode = GetXmlNodeString(CALC_MODE_PATH);
575        switch (calcMode)
576        {
577          case "autoNoTable":
578            return ExcelCalcMode.AutomaticNoTable;
579          case "manual":
580            return ExcelCalcMode.Manual;
581          default:
582            return ExcelCalcMode.Automatic;
583
584        }
585      }
586      set
587      {
588        switch (value)
589        {
590          case ExcelCalcMode.AutomaticNoTable:
591            SetXmlNodeString(CALC_MODE_PATH, "autoNoTable") ;
592            break;
593          case ExcelCalcMode.Manual:
594            SetXmlNodeString(CALC_MODE_PATH, "manual");
595            break;
596          default:
597            SetXmlNodeString(CALC_MODE_PATH, "auto");
598            break;
599
600        }
601      }
602      #endregion
603    }
604    #endregion
605    #region Workbook Private Methods
606     
607    #region Save // Workbook Save
608    /// <summary>
609    /// Saves the workbook and all its components to the package.
610    /// For internal use only!
611    /// </summary>
612    internal void Save()  // Workbook Save
613    {
614      if (Worksheets.Count == 0)
615        throw new InvalidOperationException("The workbook must contain at least one worksheet");
616
617      DeleteCalcChain();
618
619            if (VbaProject == null)
620            {
621                if (Part.ContentType != ExcelPackage.contentTypeWorkbookDefault)
622                {
623                    ChangeContentTypeWorkbook(ExcelPackage.contentTypeWorkbookDefault);
624                }
625            }
626            else
627            {
628                if (Part.ContentType != ExcelPackage.contentTypeWorkbookMacroEnabled)
629                {
630                    ChangeContentTypeWorkbook(ExcelPackage.contentTypeWorkbookMacroEnabled);
631                }
632            }
633     
634      UpdateDefinedNamesXml();
635
636      // save the workbook
637      if (_workbookXml != null)
638      {
639        _package.SavePart(WorkbookUri, _workbookXml);
640      }
641
642      // save the properties of the workbook
643      if (_properties != null)
644      {
645        _properties.Save();
646      }
647
648      // save the style sheet
649      Styles.UpdateXml();
650      _package.SavePart(StylesUri, _stylesXml);
651
652      // save all the open worksheets
653      var isProtected = Protection.LockWindows || Protection.LockStructure;
654      foreach (ExcelWorksheet worksheet in Worksheets)
655      {
656        if (isProtected && Protection.LockWindows)
657        {
658          worksheet.View.WindowProtection = true;
659        }
660        worksheet.Save();
661      }
662     
663      UpdateSharedStringsXml();
664     
665      // Data validation
666      ValidateDataValidations();
667
668            //VBA
669            if (VbaProject!=null)
670            {
671                VbaProject.Save();
672            }
673
674    }
675        /// <summary>
676        /// Recreate the workbook part with a new contenttype
677        /// </summary>
678        /// <param name="contentType">The new contenttype</param>
679        private void ChangeContentTypeWorkbook(string contentType)
680        {           
681            var p=_package.Package;
682            var part = Part;
683            var rels = part.GetRelationships();
684
685            p.DeletePart(WorkbookUri);
686            part = p.CreatePart(WorkbookUri, contentType);
687           
688            foreach (var rel in rels)
689            {
690                p.DeleteRelationship(rel.Id);
691                var newRel=part.CreateRelationship(rel.TargetUri, rel.TargetMode, rel.RelationshipType);
692                if (rel.RelationshipType.EndsWith("worksheet"))
693                {
694                    var sheetNode = (XmlElement)WorkbookXml.SelectSingleNode(string.Format("d:workbook/d:sheets/d:sheet[@r:id='{0}']", rel.Id), NameSpaceManager);
695                    sheetNode.SetAttribute("id", ExcelPackage.schemaRelationships, newRel.Id);
696                }
697                else if (rel.RelationshipType.EndsWith("pivotCacheDefinition"))
698                {
699                    var sheetNode = (XmlElement)WorkbookXml.SelectSingleNode(string.Format("d:workbook/d:pivotCaches/d:pivotCache[@r:id='{0}']", rel.Id), NameSpaceManager);
700                    sheetNode.SetAttribute("id", ExcelPackage.schemaRelationships, newRel.Id);
701                }
702            }
703        }
704
705    private void DeleteCalcChain()
706    {
707      //Remove the calc chain if it exists.
708      Uri uriCalcChain = new Uri("/xl/calcChain.xml", UriKind.Relative);
709      if (_package.Package.PartExists(uriCalcChain))
710      {
711        Uri calcChain = new Uri("calcChain.xml", UriKind.Relative);
712        foreach (PackageRelationship relationship in _package.Workbook.Part.GetRelationships())
713        {
714          if (relationship.TargetUri == calcChain)
715          {
716            _package.Workbook.Part.DeleteRelationship(relationship.Id);
717            break;
718          }
719        }
720        // delete the calcChain part
721        _package.Package.DeletePart(uriCalcChain);
722      }
723    }
724
725    private void ValidateDataValidations()
726    {
727      foreach (var sheet in _package.Workbook.Worksheets)
728      {
729        sheet.DataValidations.ValidateAll();
730      }
731    }
732
733    private void UpdateSharedStringsXml()
734    {
735      PackagePart stringPart;
736      if (_package.Package.PartExists(SharedStringsUri))
737      {
738        stringPart=_package.Package.GetPart(SharedStringsUri);
739      }
740      else
741      {
742        stringPart = _package.Package.CreatePart(SharedStringsUri, @"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml", _package.Compression);
743        Part.CreateRelationship(PackUriHelper.GetRelativeUri(WorkbookUri, SharedStringsUri), TargetMode.Internal, ExcelPackage.schemaRelationships + "/sharedStrings");
744      }
745
746      StreamWriter sw = new StreamWriter(stringPart.GetStream(FileMode.Create, FileAccess.Write));
747      sw.Write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?><sst xmlns=\"http://schemas.openxmlformats.org/spreadsheetml/2006/main\" count=\"{0}\" uniqueCount=\"{0}\">", _sharedStrings.Count);
748      foreach (string t in _sharedStrings.Keys)
749      {
750
751        SharedStringItem ssi = _sharedStrings[t];
752        if (ssi.isRichText)
753        {
754          sw.Write("<si>");
755          ExcelEncodeString(sw, t);
756          sw.Write("</si>");
757        }
758        else
759        {
760          if (t.Length>0 && (t[0] == ' ' || t[t.Length-1] == ' ' || t.Contains("  ") || t.Contains("\t")))
761          {
762            sw.Write("<si><t xml:space=\"preserve\">");
763          }
764          else
765          {
766            sw.Write("<si><t>");
767          }
768          ExcelEncodeString(sw, SecurityElement.Escape(t));
769          sw.Write("</t></si>");
770        }
771      }
772      sw.Write("</sst>");
773      sw.Flush();
774    }
775
776    /// <summary>
777    /// Return true if preserve space attribute is set.
778    /// </summary>
779    /// <param name="sw"></param>
780    /// <param name="t"></param>
781    /// <returns></returns>
782    private void ExcelEncodeString(StreamWriter sw, string t)
783    {
784      if(Regex.IsMatch(t, "(_x[0-9A-F]{4,4}_)"))
785      {
786        var match = Regex.Match(t, "(_x[0-9A-F]{4,4}_)");
787        int indexAdd = 0;
788        while (match.Success)
789        {
790          t=t.Insert(match.Index + indexAdd, "_x005F");
791          indexAdd += 6;
792          match = match.NextMatch();
793        }
794      }
795      for (int i=0;i<t.Length;i++)
796      {
797        if (t[i] <= 0x1f && t[i] != '\t' && t[i] != '\n' && t[i] != '\r') //Not Tab, CR or LF
798        {
799          sw.Write("_x00{0}_", (t[i] < 0xa ? "0" : "") + ((int)t[i]).ToString("X"));                   
800        }
801        else
802        {
803          sw.Write(t[i]);
804        }
805      }
806
807    }
808    private string ExcelDecodeString(string t)
809    {
810      var match = Regex.Match(t, "(_x005F|_x[0-9A-F]{4,4}_)");
811      if(!match.Success) return t;
812
813      bool useNextValue = false;
814      StringBuilder ret=new StringBuilder();
815      int prevIndex=0;
816      while(match.Success)
817      {
818        if (prevIndex < match.Index) ret.Append(t.Substring(prevIndex, match.Index - prevIndex));
819        if (!useNextValue && match.Value == "_x005F")
820        {
821          useNextValue = true;
822        }
823        else
824        {
825          if (useNextValue)
826          {
827            ret.Append(match.Value);
828            useNextValue=false;
829          }
830          else
831          {
832            ret.Append((char)int.Parse(match.Value.Substring(2,4),NumberStyles.AllowHexSpecifier));
833          }
834        }
835        prevIndex=match.Index+match.Length;
836        match = match.NextMatch();
837      }
838      ret.Append(t.Substring(prevIndex, t.Length - prevIndex));
839      return ret.ToString();
840    }
841    private void UpdateDefinedNamesXml()
842    {
843      try
844      {
845        XmlNode top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
846        if (!ExistsNames())
847        {
848          if (top != null) TopNode.RemoveChild(top);
849          return;
850        }
851        else
852        {
853          if (top == null)
854          {
855            CreateNode("d:definedNames");
856            top = WorkbookXml.SelectSingleNode("//d:definedNames", NameSpaceManager);
857          }
858          else
859          {
860            top.RemoveAll();
861          }
862          foreach (ExcelNamedRange name in _names)
863          {
864
865            XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage.schemaMain);
866            top.AppendChild(elem);
867            elem.SetAttribute("name", name.Name);
868            if (name.IsNameHidden) elem.SetAttribute("hidden", "1");
869            if (!string.IsNullOrEmpty(name.NameComment)) elem.SetAttribute("comment", name.NameComment);
870            SetNameElement(name, elem);
871          }
872        }
873        foreach (ExcelWorksheet ws in _worksheets)
874        {
875          foreach (ExcelNamedRange name in ws.Names)
876          {
877
878            XmlElement elem = WorkbookXml.CreateElement("definedName", ExcelPackage.schemaMain);
879            top.AppendChild(elem);
880            elem.SetAttribute("name", name.Name);
881            elem.SetAttribute("localSheetId", name.LocalSheetId.ToString());
882            if (name.IsNameHidden) elem.SetAttribute("hidden", "1");
883            if (!string.IsNullOrEmpty(name.NameComment)) elem.SetAttribute("comment", name.NameComment);
884            SetNameElement(name, elem);
885          }
886        }
887      }
888      catch (Exception ex)
889      {
890        throw new Exception("Internal error updating named ranges ",ex);
891      }
892    }
893
894    private void SetNameElement(ExcelNamedRange name, XmlElement elem)
895    {
896      if (name.IsName)
897      {
898        if (string.IsNullOrEmpty(name.NameFormula))
899        {
900          if ((name.NameValue.GetType().IsPrimitive || name.NameValue is double || name.NameValue is decimal))
901          {
902            elem.InnerText = Convert.ToDouble(name.NameValue, CultureInfo.InvariantCulture).ToString("g15", CultureInfo.InvariantCulture);
903          }
904          else if (name.NameValue is DateTime)
905          {
906            elem.InnerText = ((DateTime)name.NameValue).ToOADate().ToString(CultureInfo.InvariantCulture);
907          }
908          else
909          {
910            elem.InnerText = "\"" + name.NameValue.ToString() + "\"";
911          }                               
912        }
913        else
914        {
915          elem.InnerText = name.NameFormula;
916        }
917      }
918      else
919      {
920                elem.InnerText = name.FullAddressAbsolute;
921      }
922    }
923    /// <summary>
924    /// Is their any names in the workbook or in the sheets.
925    /// </summary>
926    /// <returns>?</returns>
927    private bool ExistsNames()
928    {
929      if (_names.Count == 0)
930      {
931        foreach (ExcelWorksheet ws in Worksheets)
932        {
933          if(ws.Names.Count>0)
934          {
935            return true;
936          }
937        }
938      }
939      else
940      {
941        return true;
942      }
943      return false;
944    }       
945    #endregion
946
947    #endregion
948    internal bool ExistsTableName(string Name)
949    {
950      foreach (var ws in Worksheets)
951      {
952        if(ws.Tables._tableNames.ContainsKey(Name))
953        {
954          return true;
955        }
956      }
957      return false;
958    }
959    internal bool ExistsPivotTableName(string Name)
960    {
961      foreach (var ws in Worksheets)
962      {
963        if (ws.PivotTables._pivotTableNames.ContainsKey(Name))
964        {
965          return true;
966        }
967      }
968      return false;
969    }
970    internal void AddPivotTable(string cacheID, Uri defUri)
971    {
972      CreateNode("d:pivotCaches");
973
974      XmlElement item = WorkbookXml.CreateElement("pivotCache", ExcelPackage.schemaMain);
975      item.SetAttribute("cacheId", cacheID);
976      var rel = Part.CreateRelationship(PackUriHelper.ResolvePartUri(WorkbookUri, defUri), TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotCacheDefinition");
977      item.SetAttribute("id", ExcelPackage.schemaRelationships, rel.Id);
978
979      var pivotCaches = WorkbookXml.SelectSingleNode("//d:pivotCaches", NameSpaceManager);
980      pivotCaches.AppendChild(item);
981    }
982    internal List<string> _externalReferences = new List<string>();
983    internal void GetExternalReferences()
984    {
985      XmlNodeList nl = WorkbookXml.SelectNodes("//d:externalReferences/d:externalReference", NameSpaceManager);
986      if (nl != null)
987      {
988        foreach (XmlElement elem in nl)
989        {
990          string rID = elem.GetAttribute("r:id");
991          PackageRelationship rel = Part.GetRelationship(rID);
992          var part = _package.Package.GetPart(PackUriHelper.ResolvePartUri(rel.SourceUri, rel.TargetUri));
993          XmlDocument xmlExtRef = new XmlDocument();
994                    LoadXmlSafe(xmlExtRef, part.GetStream());
995
996          XmlElement book=xmlExtRef.SelectSingleNode("//d:externalBook", NameSpaceManager) as XmlElement;
997          if(book!=null)
998          {
999            string rId_ExtRef = book.GetAttribute("r:id");
1000            var rel_extRef = part.GetRelationship(rId_ExtRef);
1001            if (rel_extRef != null)
1002            {
1003              _externalReferences.Add(rel_extRef.TargetUri.OriginalString);
1004            }
1005
1006          }
1007        }
1008      }
1009    }
1010    } // end Workbook
1011}
Note: See TracBrowser for help on using the repository browser.