Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/3.1.3/EPPlus-3.1.3/ExcelWorksheets.cs @ 9658

Last change on this file since 9658 was 9580, checked in by sforsten, 11 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: 44.0 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          2009-10-01
30 * Jan Källman        License changed GPL-->LGPL 2011-12-27
31 *******************************************************************************/
32using System;
33using System.Collections;
34using System.Collections.Generic;
35using System.Text;
36using System.Xml;
37using System.IO;
38using System.IO.Packaging;
39using OfficeOpenXml.Style;
40using OfficeOpenXml.Drawing;
41using OfficeOpenXml.Drawing.Chart;
42using OfficeOpenXml.Style.XmlAccess;
43using OfficeOpenXml.Drawing.Vml;
44using OfficeOpenXml.VBA;
45namespace OfficeOpenXml
46{
47  /// <summary>
48  /// The collection of worksheets for the workbook
49  /// </summary>
50  public class ExcelWorksheets : XmlHelper, IEnumerable<ExcelWorksheet>
51  {
52    #region Private Properties
53        private ExcelPackage _pck;
54        private Dictionary<int, ExcelWorksheet> _worksheets;
55    private XmlNamespaceManager _namespaceManager;
56    #endregion
57    #region ExcelWorksheets Constructor
58    internal ExcelWorksheets(ExcelPackage pck, XmlNamespaceManager nsm, XmlNode topNode) :
59            base(nsm, topNode)
60    {
61      _pck = pck;
62            _namespaceManager = nsm;
63      _worksheets = new Dictionary<int, ExcelWorksheet>();
64      int positionID = 1;
65
66            foreach (XmlNode sheetNode in topNode.ChildNodes)
67      {
68        string name = sheetNode.Attributes["name"].Value;
69        //Get the relationship id
70        string relId = sheetNode.Attributes["r:id"].Value;
71        int sheetID = Convert.ToInt32(sheetNode.Attributes["sheetId"].Value);
72               
73                //Hidden property
74                eWorkSheetHidden hidden = eWorkSheetHidden.Visible;
75        XmlNode attr = sheetNode.Attributes["state"];
76        if (attr != null)
77          hidden = TranslateHidden(attr.Value);
78
79        PackageRelationship sheetRelation = pck.Workbook.Part.GetRelationship(relId);
80        Uri uriWorksheet = PackUriHelper.ResolvePartUri(pck.Workbook.WorkbookUri, sheetRelation.TargetUri);
81       
82        //add the worksheet
83                _worksheets.Add(positionID, new ExcelWorksheet(_namespaceManager, _pck, relId, uriWorksheet, name, sheetID, positionID, hidden));
84        positionID++;
85      }
86    }
87
88        private eWorkSheetHidden TranslateHidden(string value)
89        {
90            switch (value)
91            {
92                case "hidden":
93                    return eWorkSheetHidden.Hidden;
94                case "veryHidden":
95                    return eWorkSheetHidden.VeryHidden;
96                default:
97                    return eWorkSheetHidden.Visible;
98            }
99        }
100    #endregion
101
102    #region ExcelWorksheets Public Properties
103    /// <summary>
104    /// Returns the number of worksheets in the workbook
105    /// </summary>
106    public int Count
107    {
108      get { return (_worksheets.Count); }
109    }
110    #endregion
111        private const string ERR_DUP_WORKSHEET = "A worksheet with this name already exists in the workbook";
112        internal const string WORKSHEET_CONTENTTYPE = @"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml";
113    #region ExcelWorksheets Public Methods
114    /// <summary>
115        /// Foreach support
116    /// </summary>
117    /// <returns>An enumerator</returns>
118    public IEnumerator<ExcelWorksheet> GetEnumerator()
119    {
120      return (_worksheets.Values.GetEnumerator());
121        }
122        #region IEnumerable Members
123
124        IEnumerator IEnumerable.GetEnumerator()
125        {
126            return (_worksheets.Values.GetEnumerator());
127        }
128
129        #endregion
130
131
132    #region Add Worksheet
133    /// <summary>
134    /// Adds a new blank worksheet.
135    /// </summary>
136    /// <param name="Name">The name of the workbook</param>
137    public ExcelWorksheet Add(string Name)
138    {
139            int sheetID;
140            Uri uriWorksheet;
141            if (GetByName(Name) != null)
142            {
143                throw (new InvalidOperationException(ERR_DUP_WORKSHEET));
144            }
145            GetSheetURI(ref Name, out sheetID, out uriWorksheet);
146            PackagePart worksheetPart = _pck.Package.CreatePart(uriWorksheet, WORKSHEET_CONTENTTYPE, _pck.Compression);
147
148      //Create the new, empty worksheet and save it to the package
149      StreamWriter streamWorksheet = new StreamWriter(worksheetPart.GetStream(FileMode.Create, FileAccess.Write));
150      XmlDocument worksheetXml = CreateNewWorksheet();
151      worksheetXml.Save(streamWorksheet);
152      streamWorksheet.Close();
153      _pck.Package.Flush();
154
155            string rel = CreateWorkbookRel(Name, sheetID, uriWorksheet);
156
157            int positionID = _worksheets.Count + 1;
158            ExcelWorksheet worksheet = new ExcelWorksheet(_namespaceManager, _pck, rel, uriWorksheet, Name, sheetID, positionID, eWorkSheetHidden.Visible);
159
160      _worksheets.Add(positionID, worksheet);
161            if (_pck.Workbook.VbaProject != null)
162            {
163                _pck.Workbook.VbaProject.Modules.Add(new VBA.ExcelVBAModule(worksheet.CodeNameChange) { Name = Name, Code = "", Attributes = _pck.Workbook.VbaProject.GetDocumentAttributes(Name, "0{00020820-0000-0000-C000-000000000046}"), Type = eModuleType.Document, HelpContext = 0 });
164                worksheet.CodeModuleName = Name;
165
166            }
167      return worksheet;
168    }
169        /// <summary>
170        /// Adds a copy of a worksheet
171        /// </summary>
172        /// <param name="Name">The name of the workbook</param>
173        /// <param name="Copy">The worksheet to be copied</param>
174        public ExcelWorksheet Add(string Name, ExcelWorksheet Copy)
175        {
176            int sheetID;
177            Uri uriWorksheet;
178
179            if (GetByName(Name) != null)
180            {
181                throw (new InvalidOperationException(ERR_DUP_WORKSHEET));
182            }
183
184            GetSheetURI(ref Name, out sheetID, out uriWorksheet);
185
186            //Create a copy of the worksheet XML
187            PackagePart worksheetPart = _pck.Package.CreatePart(uriWorksheet, WORKSHEET_CONTENTTYPE, _pck.Compression);
188            StreamWriter streamWorksheet = new StreamWriter(worksheetPart.GetStream(FileMode.Create, FileAccess.Write));
189            XmlDocument worksheetXml = new XmlDocument();
190            worksheetXml.LoadXml(Copy.WorksheetXml.OuterXml);
191            worksheetXml.Save(streamWorksheet);
192            streamWorksheet.Close();
193            _pck.Package.Flush();
194
195
196            //Create a relation to the workbook
197            string relID = CreateWorkbookRel(Name, sheetID, uriWorksheet);
198            ExcelWorksheet added = new ExcelWorksheet(_namespaceManager, _pck, relID, uriWorksheet, Name, sheetID, _worksheets.Count + 1, eWorkSheetHidden.Visible);
199
200            //Copy comments
201            if (Copy.Comments.Count > 0)
202            {
203                CopyComment(Copy, added);
204            }
205            else if (Copy.VmlDrawingsComments.Count > 0)    //Vml drawings are copied as part of the comments.
206            {
207                CopyVmlDrawing(Copy, added);
208            }
209
210            //Copy HeaderFooter
211            CopyHeaderFooterPictures(Copy, added);
212
213            //Copy all relationships
214            //CopyRelationShips(Copy, added);
215            if (Copy.Drawings.Count > 0)
216            {
217                CopyDrawing(Copy, added);
218            }
219      if (Copy.Tables.Count > 0)
220            {
221                CopyTable(Copy, added);
222            }
223            if (Copy.PivotTables.Count > 0)
224            {
225                CopyPivotTable(Copy, added);
226            }
227            if (Copy.Names.Count > 0)
228            {
229                CopySheetNames(Copy, added);
230            }
231
232            //Copy all cells
233            CloneCells(Copy, added);
234
235            _worksheets.Add(_worksheets.Count + 1, added);
236
237            //Remove any relation to printersettings.
238            XmlNode pageSetup = added.WorksheetXml.SelectSingleNode("//d:pageSetup", _namespaceManager);
239            if (pageSetup != null)
240            {
241                XmlAttribute attr = (XmlAttribute)pageSetup.Attributes.GetNamedItem("id", ExcelPackage.schemaRelationships);
242                if (attr != null)
243                {
244                    relID = attr.Value;
245                    // first delete the attribute from the XML
246                    pageSetup.Attributes.Remove(attr);
247                }
248            }
249
250            return added;
251        }
252
253        private void CopySheetNames(ExcelWorksheet Copy, ExcelWorksheet added)
254        {
255            foreach (var name in Copy.Names)
256            {
257                ExcelNamedRange newName;
258                if (!name.IsName)
259                {
260                    if (name.WorkSheet == Copy.Name)
261                    {
262                        newName = added.Names.Add(name.Name, added.Cells[name.FirstAddress]);
263                    }
264                    else
265                    {
266                        newName = added.Names.Add(name.Name, added.Workbook.Worksheets[name.WorkSheet].Cells[name.FirstAddress]);
267                    }
268                }
269                else if (!string.IsNullOrEmpty(name.NameFormula))
270                {
271                    newName=added.Names.AddFormula(name.Name, name.Formula);
272                }
273                else
274                {
275                    newName=added.Names.AddValue(name.Name, name.Value);
276                }
277               newName.NameComment = name.NameComment;
278            }
279        }
280
281        private void CopyTable(ExcelWorksheet Copy, ExcelWorksheet added)
282        {
283            string prevName = "";
284            //First copy the table XML
285            foreach (var tbl in Copy.Tables)
286            {
287                string xml=tbl.TableXml.OuterXml;
288                int Id = _pck.Workbook._nextTableID++;
289                string name;
290                if (prevName == "")
291                {
292                    name = Copy.Tables.GetNewTableName();
293                }
294                else
295                {
296                    int ix = int.Parse(prevName.Substring(5)) + 1;
297                    name = string.Format("Table{0}", ix);
298                    while (_pck.Workbook.ExistsPivotTableName(name))
299                    {
300                        name = string.Format("Table{0}", ++ix);
301                    }
302                }
303                prevName = name;
304                XmlDocument xmlDoc = new XmlDocument();
305                xmlDoc.LoadXml(xml);
306                xmlDoc.SelectSingleNode("//d:table/@id", tbl.NameSpaceManager).Value = Id.ToString();
307                xmlDoc.SelectSingleNode("//d:table/@name", tbl.NameSpaceManager).Value = name;
308                xmlDoc.SelectSingleNode("//d:table/@displayName", tbl.NameSpaceManager).Value = name;
309                xml = xmlDoc.OuterXml;
310
311                var uriTbl = new Uri(string.Format("/xl/tables/table{0}.xml", Id), UriKind.Relative);
312                var part = _pck.Package.CreatePart(uriTbl, "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml", _pck.Compression);
313                StreamWriter streamTbl = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
314                streamTbl.Write(xml);
315                streamTbl.Close();
316
317                //create the relationship and add the ID to the worksheet xml.
318                var rel = added.Part.CreateRelationship(PackUriHelper.GetRelativeUri(added.WorksheetUri,uriTbl), TargetMode.Internal, ExcelPackage.schemaRelationships + "/table");
319
320                if (tbl.RelationshipID == null)
321                {
322                    var topNode = added.WorksheetXml.SelectSingleNode("//d:tableParts", tbl.NameSpaceManager);
323                    if (topNode == null)
324                    {
325                        added.CreateNode("d:tableParts");
326                        topNode = added.WorksheetXml.SelectSingleNode("//d:tableParts", tbl.NameSpaceManager);
327                    }
328                    XmlElement elem = added.WorksheetXml.CreateElement("tablePart", ExcelPackage.schemaMain);
329                    topNode.AppendChild(elem);
330                    elem.SetAttribute("id",ExcelPackage.schemaRelationships, rel.Id);
331                }
332                else
333                {
334                    XmlAttribute relAtt;
335                    relAtt = added.WorksheetXml.SelectSingleNode(string.Format("//d:tableParts/d:tablePart/@r:id[.='{0}']", tbl.RelationshipID), tbl.NameSpaceManager) as XmlAttribute;
336                    relAtt.Value = rel.Id;
337                }
338            }
339        }
340        private void CopyPivotTable(ExcelWorksheet Copy, ExcelWorksheet added)
341        {
342            string prevName = "";
343            foreach (var tbl in Copy.PivotTables)
344            {
345                string xml = tbl.PivotTableXml.OuterXml;
346                int Id = _pck.Workbook._nextPivotTableID++;
347
348                string name;
349                if (prevName == "")
350                {
351                    name = Copy.PivotTables.GetNewTableName();
352                }
353                else
354                {
355                    int ix=int.Parse(prevName.Substring(10))+1;
356                    name = string.Format("PivotTable{0}", ix);
357                    while (_pck.Workbook.ExistsPivotTableName(name))
358                    {
359                        name = string.Format("PivotTable{0}", ++ix);
360                    }
361                }
362                prevName=name;
363                XmlDocument xmlDoc = new XmlDocument();
364                Copy.Save();    //Save the worksheet first
365                xmlDoc.LoadXml(xml);
366                //xmlDoc.SelectSingleNode("//d:table/@id", tbl.NameSpaceManager).Value = Id.ToString();
367                xmlDoc.SelectSingleNode("//d:pivotTableDefinition/@name", tbl.NameSpaceManager).Value = name;
368                xml = xmlDoc.OuterXml;
369
370                var uriTbl = new Uri(string.Format("/xl/pivotTables/pivotTable{0}.xml", Id), UriKind.Relative);
371                var part = _pck.Package.CreatePart(uriTbl, ExcelPackage.schemaPivotTable , _pck.Compression);
372                StreamWriter streamTbl = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
373                streamTbl.Write(xml);
374                streamTbl.Close();
375
376                //create the relationship and add the ID to the worksheet xml.
377                added.Part.CreateRelationship(PackUriHelper.ResolvePartUri(added.WorksheetUri, uriTbl), TargetMode.Internal, ExcelPackage.schemaRelationships + "/pivotTable");
378                part.CreateRelationship(PackUriHelper.ResolvePartUri(tbl.Relationship.SourceUri, tbl.CacheDefinition.Relationship.TargetUri), tbl.CacheDefinition.Relationship.TargetMode, tbl.CacheDefinition.Relationship.RelationshipType);
379            }
380        }
381        private void CopyHeaderFooterPictures(ExcelWorksheet Copy, ExcelWorksheet added)
382        {
383            if (Copy._headerFooter == null) return;
384            //Copy the texts
385            CopyText(Copy.HeaderFooter._oddHeader, added.HeaderFooter.OddHeader);
386            CopyText(Copy.HeaderFooter._oddFooter, added.HeaderFooter.OddFooter);
387            CopyText(Copy.HeaderFooter._evenHeader, added.HeaderFooter.EvenHeader);
388            CopyText(Copy.HeaderFooter._evenFooter, added.HeaderFooter.EvenFooter);
389            CopyText(Copy.HeaderFooter._firstHeader, added.HeaderFooter.FirstHeader);
390            CopyText(Copy.HeaderFooter._firstFooter, added.HeaderFooter.FirstFooter);
391           
392            //Copy any images;
393            if (Copy.HeaderFooter.Pictures.Count > 0)
394            {
395                Uri source = Copy.HeaderFooter.Pictures.Uri;
396                Uri dest = XmlHelper.GetNewUri(_pck.Package, @"/xl/drawings/vmlDrawing{0}.vml");
397               
398                var part = _pck.Package.CreatePart(dest, "application/vnd.openxmlformats-officedocument.vmlDrawing", _pck.Compression);
399                foreach (ExcelVmlDrawingPicture pic in Copy.HeaderFooter.Pictures)
400                {
401                    var item = added.HeaderFooter.Pictures.Add(pic.Id, pic.ImageUri, pic.Title, pic.Width, pic.Height);
402                    foreach (XmlAttribute att in pic.TopNode.Attributes)
403                    {
404                        (item.TopNode as XmlElement).SetAttribute(att.Name, att.Value);
405                    }
406                    item.TopNode.InnerXml = pic.TopNode.InnerXml;
407                }
408            }
409        }
410
411        private void CopyText(ExcelHeaderFooterText from, ExcelHeaderFooterText to)
412        {
413            if (from == null) return;
414            to.LeftAlignedText=from.LeftAlignedText;
415            to.CenteredText = from.CenteredText;
416            to.RightAlignedText = from.RightAlignedText;
417        }
418        private void CloneCells(ExcelWorksheet Copy, ExcelWorksheet added)
419        {
420            bool sameWorkbook=(Copy.Workbook == _pck.Workbook);
421
422            bool doAdjust = _pck.DoAdjustDrawings;
423            _pck.DoAdjustDrawings = false;
424            added.MergedCells.List.AddRange(Copy.MergedCells.List);
425            //Formulas
426            foreach (IRangeID f in Copy._formulaCells)
427            {
428                added._formulaCells.Add(f);
429            }
430            //Shared Formulas
431            foreach (int key in Copy._sharedFormulas.Keys)
432            {
433                added._sharedFormulas.Add(key, Copy._sharedFormulas[key]);
434            }
435           
436            Dictionary<int, int> styleCashe = new Dictionary<int, int>();
437            //Cells
438            foreach (ExcelCell cell in Copy._cells)
439            {               
440                if (sameWorkbook)   //Same workbook == same styles
441                {
442                    added._cells.Add(cell.Clone(added));
443                }
444                else
445                {
446                    ExcelCell addedCell=cell.Clone(added);
447                    if (styleCashe.ContainsKey(cell.StyleID))
448                    {
449                        addedCell.StyleID = styleCashe[cell.StyleID];
450                    }
451                    else
452                    {
453                        addedCell.StyleID = added.Workbook.Styles.CloneStyle(Copy.Workbook.Styles,  cell.StyleID);
454                        if (cell.StyleName != "") //Named styles
455                        {
456                            if (!Copy.Workbook.Styles.NamedStyles.ExistsKey(cell.StyleName))
457                            {
458                               var ns=Copy.Workbook.Styles.CreateNamedStyle(cell.StyleName);
459                               ns.StyleXfId  = addedCell.StyleID;
460                            }
461                           
462                        }
463                        styleCashe.Add(cell.StyleID, addedCell.StyleID);
464                    }
465                    added._cells.Add(addedCell);
466                }
467            }
468            //Rows
469            foreach (ExcelRow row in Copy._rows)
470            {
471                row.Clone(added);
472                if (!sameWorkbook)   //Same workbook == same styles
473                {
474                    ExcelRow addedRow = added.Row(row.Row) as ExcelRow;
475                    if (styleCashe.ContainsKey(row.StyleID))
476                    {
477                        addedRow.StyleID = styleCashe[row.StyleID];
478                    }
479                    else
480                    {
481                        addedRow.StyleID = added.Workbook.Styles.CloneStyle(Copy.Workbook.Styles, addedRow.StyleID);
482                        if (row.StyleName != "") //Named styles
483                        {
484                            if (!Copy.Workbook.Styles.NamedStyles.ExistsKey(row.StyleName))
485                            {
486                                var ns = Copy.Workbook.Styles.CreateNamedStyle(row.StyleName);
487                                ns.StyleXfId = addedRow.StyleID;
488                            }
489
490                        }
491                        styleCashe.Add(row.StyleID, addedRow.StyleID);
492                    }
493                }               
494            }
495            //Columns
496            foreach (ExcelColumn col in Copy._columns)
497            {
498                col.Clone(added);
499                if (!sameWorkbook)   //Same workbook == same styles
500                {
501                    ExcelColumn addedCol = added.Column(col.ColumnMin) as ExcelColumn;
502                    if (styleCashe.ContainsKey(col.StyleID))
503                    {
504                        addedCol.StyleID = styleCashe[col.StyleID];
505                    }
506                    else
507                    {
508                        addedCol.StyleID = added.Workbook.Styles.CloneStyle(Copy.Workbook.Styles, addedCol.StyleID);
509                        if (col.StyleName != "") //Named styles
510                        {
511                            if (!Copy.Workbook.Styles.NamedStyles.ExistsKey(col.StyleName))
512                            {
513                                var ns = Copy.Workbook.Styles.CreateNamedStyle(col.StyleName);
514                                ns.StyleXfId = addedCol.StyleID;
515                            }
516
517                        }
518                        styleCashe.Add(col.StyleID, addedCol.StyleID);
519                    }
520                }
521            }
522            added._package.DoAdjustDrawings = doAdjust;
523        }
524        private void CopyComment(ExcelWorksheet Copy, ExcelWorksheet workSheet)
525        {
526            //First copy the drawing XML
527            string xml = Copy.Comments.CommentXml.InnerXml;
528            var uriComment = new Uri(string.Format("/xl/comments{0}.xml", workSheet.SheetID), UriKind.Relative);
529            if (_pck.Package.PartExists(uriComment))
530            {
531                uriComment = XmlHelper.GetNewUri(_pck.Package, "/xl/drawings/vmldrawing{0}.vml");
532            }
533
534            var part = _pck.Package.CreatePart(uriComment, "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml", _pck.Compression);
535
536            StreamWriter streamDrawing = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
537            streamDrawing.Write(xml);
538            streamDrawing.Close();
539
540            //Add the relationship ID to the worksheet xml.
541            PackageRelationship commentRelation = workSheet.Part.CreateRelationship(PackUriHelper.GetRelativeUri(workSheet.WorksheetUri,uriComment), TargetMode.Internal, ExcelPackage.schemaRelationships + "/comments");
542
543            xml = Copy.VmlDrawingsComments.VmlDrawingXml.InnerXml;
544
545            var uriVml = new Uri(string.Format("/xl/drawings/vmldrawing{0}.vml", workSheet.SheetID), UriKind.Relative);
546            if (_pck.Package.PartExists(uriVml))
547            {
548                uriVml = XmlHelper.GetNewUri(_pck.Package, "/xl/drawings/vmldrawing{0}.vml");
549            }
550
551            var vmlPart = _pck.Package.CreatePart(uriVml, "application/vnd.openxmlformats-officedocument.vmlDrawing", _pck.Compression);
552            StreamWriter streamVml = new StreamWriter(vmlPart.GetStream(FileMode.Create, FileAccess.Write));
553            streamVml.Write(xml);
554            streamVml.Close();
555
556            PackageRelationship newVmlRel = workSheet.Part.CreateRelationship(PackUriHelper.GetRelativeUri(workSheet.WorksheetUri,uriVml), TargetMode.Internal, ExcelPackage.schemaRelationships + "/vmlDrawing");
557
558            //Add the relationship ID to the worksheet xml.
559            XmlElement e = workSheet.WorksheetXml.SelectSingleNode("//d:legacyDrawing", _namespaceManager) as XmlElement;
560            if (e == null)
561            {
562                workSheet.CreateNode("d:legacyDrawing");
563                e = workSheet.WorksheetXml.SelectSingleNode("//d:legacyDrawing", _namespaceManager) as XmlElement;
564            }
565
566            e.SetAttribute("id", ExcelPackage.schemaRelationships, newVmlRel.Id);
567        }
568        private void CopyDrawing(ExcelWorksheet Copy, ExcelWorksheet workSheet/*, PackageRelationship r*/)
569        {
570           
571            //Check if the worksheet has drawings
572            //if(_xlPackage.Package.PartExists(r.TargetUri))
573            //{
574                //First copy the drawing XML               
575                string xml = Copy.Drawings.DrawingXml.OuterXml;           
576                var uriDraw=new Uri(string.Format("/xl/drawings/drawing{0}.xml", workSheet.SheetID),  UriKind.Relative);
577                var part= _pck.Package.CreatePart(uriDraw,"application/vnd.openxmlformats-officedocument.drawing+xml", _pck.Compression);
578                StreamWriter streamDrawing = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
579                streamDrawing.Write(xml);
580                streamDrawing.Close();
581
582                XmlDocument drawXml = new XmlDocument();
583                drawXml.LoadXml(xml);
584                //Add the relationship ID to the worksheet xml.
585                PackageRelationship drawRelation = workSheet.Part.CreateRelationship(PackUriHelper.GetRelativeUri(workSheet.WorksheetUri,uriDraw), TargetMode.Internal, ExcelPackage.schemaRelationships + "/drawing");
586                XmlElement e = workSheet.WorksheetXml.SelectSingleNode("//d:drawing", _namespaceManager) as XmlElement;
587                e.SetAttribute("id",ExcelPackage.schemaRelationships, drawRelation.Id);
588
589                foreach (ExcelDrawing draw in Copy.Drawings)
590                {
591                    if (draw is ExcelChart)
592                    {
593                        ExcelChart chart = draw as ExcelChart;
594                        xml = chart.ChartXml.InnerXml;
595
596                        var UriChart = XmlHelper.GetNewUri(_pck.Package, "/xl/charts/chart{0}.xml");
597                        var chartPart = _pck.Package.CreatePart(UriChart, "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", _pck.Compression);
598                        StreamWriter streamChart = new StreamWriter(chartPart.GetStream(FileMode.Create, FileAccess.Write));
599                        streamChart.Write(xml);
600                        streamChart.Close();
601                        //Now create the new relationship to the copied chart xml
602                        var prevRelID=draw.TopNode.SelectSingleNode("xdr:graphicFrame/a:graphic/a:graphicData/c:chart/@r:id", Copy.Drawings.NameSpaceManager).Value;
603                        var rel = part.CreateRelationship(PackUriHelper.GetRelativeUri(uriDraw,UriChart), TargetMode.Internal, ExcelPackage.schemaRelationships + "/chart");
604                        XmlAttribute relAtt = drawXml.SelectSingleNode(string.Format("//c:chart/@r:id[.='{0}']", prevRelID), Copy.Drawings.NameSpaceManager) as XmlAttribute;
605                        relAtt.Value=rel.Id;
606                    }
607                    else if (draw is ExcelPicture)
608                    {
609                        ExcelPicture pic = draw as ExcelPicture;
610                        var uri = pic.UriPic;
611                        if(!workSheet.Workbook._package.Package.PartExists(uri))
612                        {
613                            var picPart = workSheet.Workbook._package.Package.CreatePart(uri, pic.ContentType, CompressionOption.NotCompressed);
614                            pic.Image.Save(picPart.GetStream(FileMode.Create, FileAccess.Write), pic.ImageFormat);
615                        }
616
617                        var prevRelID = draw.TopNode.SelectSingleNode("xdr:pic/xdr:blipFill/a:blip/@r:embed", Copy.Drawings.NameSpaceManager).Value;
618                        var rel = part.CreateRelationship(PackUriHelper.GetRelativeUri(workSheet.WorksheetUri, uri), TargetMode.Internal, ExcelPackage.schemaRelationships + "/image");
619                        XmlAttribute relAtt = drawXml.SelectSingleNode(string.Format("//xdr:pic/xdr:blipFill/a:blip/@r:embed[.='{0}']", prevRelID), Copy.Drawings.NameSpaceManager) as XmlAttribute;
620                        relAtt.Value = rel.Id;
621                    }
622                }
623                //rewrite the drawing xml with the new relID's
624                streamDrawing = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write));
625                streamDrawing.Write(drawXml.OuterXml);
626                streamDrawing.Close();
627            //}
628        }
629
630    private void CopyVmlDrawing(ExcelWorksheet origSheet, ExcelWorksheet newSheet)
631    {
632      var xml = origSheet.VmlDrawingsComments.VmlDrawingXml.OuterXml;
633      var vmlUri = new Uri(string.Format("/xl/drawings/vmlDrawing{0}.vml", newSheet.SheetID), UriKind.Relative);
634      var part = _pck.Package.CreatePart(vmlUri, "application/vnd.openxmlformats-officedocument.vmlDrawing", _pck.Compression);
635      using (var streamDrawing = new StreamWriter(part.GetStream(FileMode.Create, FileAccess.Write)))
636      {
637        streamDrawing.Write(xml);
638      }
639
640      //Add the relationship ID to the worksheet xml.
641      PackageRelationship vmlRelation = newSheet.Part.CreateRelationship(PackUriHelper.GetRelativeUri(newSheet.WorksheetUri,vmlUri), TargetMode.Internal, ExcelPackage.schemaRelationships + "/vmlDrawing");
642      var e = newSheet.WorksheetXml.SelectSingleNode("//d:legacyDrawing", _namespaceManager) as XmlElement;
643      if (e == null)
644      {
645        e = newSheet.WorksheetXml.CreateNode(XmlNodeType.Entity, "//d:legacyDrawing", _namespaceManager.LookupNamespace("d")) as XmlElement;
646      }
647      if (e != null)
648      {
649        e.SetAttribute("id", ExcelPackage.schemaRelationships, vmlRelation.Id);
650      }
651    }
652
653    string CreateWorkbookRel(string Name, int sheetID, Uri uriWorksheet)
654        {
655            //Create the relationship between the workbook and the new worksheet
656            PackageRelationship rel = _pck.Workbook.Part.CreateRelationship(PackUriHelper.GetRelativeUri(_pck.Workbook.WorkbookUri, uriWorksheet), TargetMode.Internal, ExcelPackage.schemaRelationships + "/worksheet");
657            _pck.Package.Flush();
658
659            //Create the new sheet node
660            XmlElement worksheetNode = _pck.Workbook.WorkbookXml.CreateElement("sheet", ExcelPackage.schemaMain);
661            worksheetNode.SetAttribute("name", Name);
662            worksheetNode.SetAttribute("sheetId", sheetID.ToString());
663            worksheetNode.SetAttribute("id", ExcelPackage.schemaRelationships, rel.Id);
664
665            TopNode.AppendChild(worksheetNode);
666            return rel.Id;
667        }
668        private void GetSheetURI(ref string Name, out int sheetID, out Uri uriWorksheet)
669        {
670            Name = ValidateFixSheetName(Name);
671
672            //First find maximum existing sheetID
673            sheetID = 0;
674            foreach(var ws in this)
675            {               
676                if (ws.SheetID > sheetID)
677                {
678                    sheetID = ws.SheetID;
679                }
680            }
681            // we now have the max existing values, so add one
682            sheetID++;
683
684            // add the new worksheet to the package
685            uriWorksheet = new Uri("/xl/worksheets/sheet" + sheetID.ToString() + ".xml", UriKind.Relative);
686        }
687
688        internal string ValidateFixSheetName(string Name)
689        {
690            //remove invalid characters
691            if (ValidateName(Name))
692            {
693                if (Name.IndexOf(':') > -1) Name = Name.Replace(":", " ");
694                if (Name.IndexOf('/') > -1) Name = Name.Replace("/", " ");
695                if (Name.IndexOf('\\') > -1) Name = Name.Replace("\\", " ");
696                if (Name.IndexOf('?') > -1) Name = Name.Replace("?", " ");
697                if (Name.IndexOf('[') > -1) Name = Name.Replace("[", " ");
698                if (Name.IndexOf(']') > -1) Name = Name.Replace("]", " ");
699            }
700
701            if (Name.Trim() == "")
702            {
703                throw new ArgumentException("The worksheet can not have an empty name");
704            }
705            if (Name.Length > 31) Name = Name.Substring(0, 31);   //A sheet can have max 31 char's
706            return Name;
707        }
708        /// <summary>
709        /// Validate the sheetname
710        /// </summary>
711        /// <param name="Name">The Name</param>
712        /// <returns>True if valid</returns>
713        private bool ValidateName(string Name)
714        {
715            return System.Text.RegularExpressions.Regex.IsMatch(Name, @":|\?|/|\\|\[|\]");
716        }
717
718    /// <summary>
719    /// Creates the XML document representing a new empty worksheet
720    /// </summary>
721    /// <returns></returns>
722    internal XmlDocument CreateNewWorksheet()
723    {
724      XmlDocument xmlDoc = new XmlDocument();
725            XmlElement elemWs = xmlDoc.CreateElement("worksheet", ExcelPackage.schemaMain);
726            elemWs.SetAttribute("xmlns:r", ExcelPackage.schemaRelationships);
727            xmlDoc.AppendChild(elemWs);
728
729            XmlElement elemSheetViews = xmlDoc.CreateElement("sheetViews", ExcelPackage.schemaMain);
730            elemWs.AppendChild(elemSheetViews);
731
732            XmlElement elemSheetView = xmlDoc.CreateElement("sheetView", ExcelPackage.schemaMain);
733            elemSheetView.SetAttribute("workbookViewId", "0");
734            elemSheetViews.AppendChild(elemSheetView);
735
736            XmlElement elemSheetFormatPr = xmlDoc.CreateElement("sheetFormatPr", ExcelPackage.schemaMain);
737            elemSheetFormatPr.SetAttribute("defaultRowHeight", "15");
738            elemWs.AppendChild(elemSheetFormatPr);
739
740            XmlElement elemSheetData = xmlDoc.CreateElement("sheetData", ExcelPackage.schemaMain);
741            elemWs.AppendChild(elemSheetData);
742            return xmlDoc;
743    }
744    #endregion
745
746    #region Delete Worksheet
747    /// <summary>
748    /// Deletes a worksheet from the collection
749    /// </summary>
750    /// <param name="Index">The position of the worksheet in the workbook</param>
751    public void Delete(int Index)
752    {
753      ExcelWorksheet worksheet = _worksheets[Index];
754            if (worksheet.Drawings.Count > 0)
755            {
756                worksheet.Drawings.Clear();
757            }
758            //Delete the worksheet part and relation from the package
759      _pck.Package.DeletePart(worksheet.WorksheetUri);
760      _pck.Workbook.Part.DeleteRelationship(worksheet.RelationshipID);
761
762            //Delete worksheet from the workbook XML
763      XmlNode sheetsNode = _pck.Workbook.WorkbookXml.SelectSingleNode("//d:workbook/d:sheets", _namespaceManager);
764      if (sheetsNode != null)
765      {
766        XmlNode sheetNode = sheetsNode.SelectSingleNode(string.Format("./d:sheet[@sheetId={0}]", worksheet.SheetID), _namespaceManager);
767        if (sheetNode != null)
768        {
769          sheetsNode.RemoveChild(sheetNode);
770        }
771      }
772      _worksheets.Remove(Index);
773            if (_pck.Workbook.VbaProject != null)
774            {
775                _pck.Workbook.VbaProject.Modules.Remove(worksheet.CodeModule);
776            }
777      ReindexWorksheetDictionary();
778    }
779
780    /// <summary>
781    /// Deletes a worksheet from the collection
782    /// </summary>
783    /// <param name="name">The name of the worksheet in the workbook</param>
784    public void Delete(string name)
785    {
786      var sheet = this[name];
787      if (sheet == null)
788      {
789        throw new ArgumentException(string.Format("Could not find worksheet to delete '{0}'", name));
790      }
791      Delete(sheet.PositionID);
792    }
793    /// <summary>
794        /// Delete a worksheet from the collection
795        /// </summary>
796        /// <param name="Worksheet">The worksheet to delete</param>
797        public void Delete(ExcelWorksheet Worksheet)
798    {
799            if (Worksheet.PositionID <= _worksheets.Count && Worksheet == _worksheets[Worksheet.PositionID])
800            {
801                Delete(Worksheet.PositionID);
802            }
803            else
804            {
805                throw (new ArgumentException("Worksheet is not in the collection."));
806            }
807        }
808        #endregion
809
810    private void ReindexWorksheetDictionary()
811    {
812      var index = 1;
813      var worksheets = new Dictionary<int, ExcelWorksheet>();
814      foreach (var entry in _worksheets)
815      {
816        entry.Value.PositionID = index;
817        worksheets.Add(index++, entry.Value);
818      }
819      _worksheets = worksheets;
820    }
821
822    /// <summary>
823    /// Returns the worksheet at the specified position. 
824    /// </summary>
825    /// <param name="PositionID">The position of the worksheet. 1-base</param>
826    /// <returns></returns>
827    public ExcelWorksheet this[int PositionID]
828    {
829      get
830      {
831                return (_worksheets[PositionID]);
832      }
833    }
834
835    /// <summary>
836    /// Returns the worksheet matching the specified name
837    /// </summary>
838    /// <param name="Name">The name of the worksheet</param>
839    /// <returns></returns>
840    public ExcelWorksheet this[string Name]
841    {
842      get
843      {
844                return GetByName(Name);
845      }
846    }
847    /// <summary>
848    /// Copies the named worksheet and creates a new worksheet in the same workbook
849    /// </summary>
850    /// <param name="Name">The name of the existing worksheet</param>
851    /// <param name="NewName">The name of the new worksheet to create</param>
852    /// <returns>The new copy added to the end of the worksheets collection</returns>
853    public ExcelWorksheet Copy(string Name, string NewName)
854    {
855            ExcelWorksheet Copy = this[Name];
856            if (Copy == null)
857                throw new ArgumentException(string.Format("Copy worksheet error: Could not find worksheet to copy '{0}'", Name));
858
859            ExcelWorksheet added = Add(NewName, Copy);
860            return added;
861        }
862    #endregion
863
864        internal ExcelWorksheet GetBySheetID(int localSheetID)
865        {
866            foreach (ExcelWorksheet ws in this)
867            {
868                if (ws.SheetID == localSheetID)
869                {
870                    return ws;
871                }
872            }
873            return null;
874        }
875        private ExcelWorksheet GetByName(string Name)
876        {
877            if (string.IsNullOrEmpty(Name)) return null;
878            ExcelWorksheet xlWorksheet = null;
879            foreach (ExcelWorksheet worksheet in _worksheets.Values)
880            {
881                if (worksheet.Name.ToLower() == Name.ToLower())
882                    xlWorksheet = worksheet;
883            }
884            return (xlWorksheet);
885        }
886    #region MoveBefore and MoveAfter Methods
887    /// <summary>
888    /// Moves the source worksheet to the position before the target worksheet
889    /// </summary>
890    /// <param name="sourceName">The name of the source worksheet</param>
891    /// <param name="targetName">The name of the target worksheet</param>
892    public void MoveBefore(string sourceName, string targetName)
893    {
894      Move(sourceName, targetName, false);
895    }
896
897    /// <summary>
898    /// Moves the source worksheet to the position before the target worksheet
899    /// </summary>
900    /// <param name="sourcePositionId">The id of the source worksheet</param>
901    /// <param name="targetPositionId">The id of the target worksheet</param>
902    public void MoveBefore(int sourcePositionId, int targetPositionId)
903    {
904      Move(sourcePositionId, targetPositionId, false);
905    }
906
907    /// <summary>
908    /// Moves the source worksheet to the position after the target worksheet
909    /// </summary>
910    /// <param name="sourceName">The name of the source worksheet</param>
911    /// <param name="targetName">The name of the target worksheet</param>
912    public void MoveAfter(string sourceName, string targetName)
913    {
914      Move(sourceName, targetName, true);
915    }
916
917    /// <summary>
918    /// Moves the source worksheet to the position after the target worksheet
919    /// </summary>
920    /// <param name="sourcePositionId">The id of the source worksheet</param>
921    /// <param name="targetPositionId">The id of the target worksheet</param>
922    public void MoveAfter(int sourcePositionId, int targetPositionId)
923    {
924      Move(sourcePositionId, targetPositionId, true);
925    }
926
927    /// <summary>
928    ///
929    /// </summary>
930    /// <param name="sourceName"></param>
931    public void MoveToStart(string sourceName)
932    {
933      var sourceSheet = this[sourceName];
934      if (sourceSheet == null)
935      {
936        throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", sourceName));
937      }
938      Move(sourceSheet.PositionID, 1, false);
939    }
940
941    /// <summary>
942    ///
943    /// </summary>
944    /// <param name="sourcePositionId"></param>
945    public void MoveToStart(int sourcePositionId)
946    {
947      Move(sourcePositionId, 1, false);
948    }
949
950    /// <summary>
951    ///
952    /// </summary>
953    /// <param name="sourceName"></param>
954    public void MoveToEnd(string sourceName)
955    {
956      var sourceSheet = this[sourceName];
957      if (sourceSheet == null)
958      {
959        throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", sourceName));
960      }
961      Move(sourceSheet.PositionID, _worksheets.Count, true);
962    }
963
964    /// <summary>
965    ///
966    /// </summary>
967    /// <param name="sourcePositionId"></param>
968    public void MoveToEnd(int sourcePositionId)
969    {
970      Move(sourcePositionId, _worksheets.Count, true);
971    }
972
973    private void Move(string sourceName, string targetName, bool placeAfter)
974    {
975      var sourceSheet = this[sourceName];
976      if (sourceSheet == null)
977      {
978        throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", sourceName));
979      }
980      var targetSheet = this[targetName];
981      if (targetSheet == null)
982      {
983        throw new Exception(string.Format("Move worksheet error: Could not find worksheet to move '{0}'", targetName));
984      }
985      Move(sourceSheet.PositionID, targetSheet.PositionID, placeAfter);
986    }
987
988    private void Move(int sourcePositionId, int targetPositionId, bool placeAfter)
989    {
990      var sourceSheet = this[sourcePositionId];
991      if (sourceSheet == null)
992      {
993        throw new Exception(string.Format("Move worksheet error: Could not find worksheet at position '{0}'", sourcePositionId));
994      }
995      var targetSheet = this[targetPositionId];
996      if (targetSheet == null)
997      {
998        throw new Exception(string.Format("Move worksheet error: Could not find worksheet at position '{0}'", targetPositionId));
999      }
1000      if (_worksheets.Count < 2)
1001      {
1002        return;   //--- no reason to attempt to re-arrange a single item with itself
1003      }
1004
1005      var index = 1;
1006      var newOrder = new Dictionary<int, ExcelWorksheet>();
1007      foreach (var entry in _worksheets)
1008      {
1009        if (entry.Key == targetPositionId)
1010        {
1011          if (!placeAfter)
1012          {
1013            sourceSheet.PositionID = index;
1014            newOrder.Add(index++, sourceSheet);
1015          }
1016
1017          entry.Value.PositionID = index;
1018          newOrder.Add(index++, entry.Value);
1019
1020          if (placeAfter)
1021          {
1022            sourceSheet.PositionID = index;
1023            newOrder.Add(index++, sourceSheet);
1024          }
1025        }
1026        else if (entry.Key == sourcePositionId)
1027        {
1028          //--- do nothing
1029        }
1030        else
1031        {
1032          entry.Value.PositionID = index;
1033          newOrder.Add(index++, entry.Value);
1034        }
1035      }
1036      _worksheets = newOrder;
1037
1038      MoveSheetXmlNode(sourceSheet, targetSheet, placeAfter);
1039    }
1040
1041    private void MoveSheetXmlNode(ExcelWorksheet sourceSheet, ExcelWorksheet targetSheet, bool placeAfter)
1042    {
1043      var sourceNode = TopNode.SelectSingleNode(string.Format("d:sheet[@sheetId = '{0}']", sourceSheet.SheetID), _namespaceManager);
1044            var targetNode = TopNode.SelectSingleNode(string.Format("d:sheet[@sheetId = '{0}']", targetSheet.SheetID), _namespaceManager);
1045      if (sourceNode == null || targetNode == null)
1046      {
1047        throw new Exception("Source SheetId and Target SheetId must be valid");
1048      }
1049      if (placeAfter)
1050      {
1051                TopNode.InsertAfter(sourceNode, targetNode);
1052      }
1053      else
1054      {
1055                TopNode.InsertBefore(sourceNode, targetNode);
1056      }
1057    }
1058
1059    #endregion
1060  } // end class Worksheets
1061}
1062
Note: See TracBrowser for help on using the repository browser.