Free cookie consent management tool by TermsFeed Policy Generator

source: branches/ScopedBasicAlgorithm/HeuristicLab.ExtLibs/HeuristicLab.EPPlus/4.0.3/EPPlus-4.0.3/ExcelWorksheets.cs @ 14419

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

#2341: Added EPPlus-4.0.3 to ExtLibs

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