diff --git a/ClosedXML/Excel/XLWorkbook.cs b/ClosedXML/Excel/XLWorkbook.cs
index 62bc96f..ed6398f 100644
--- a/ClosedXML/Excel/XLWorkbook.cs
+++ b/ClosedXML/Excel/XLWorkbook.cs
@@ -1,959 +1,959 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Security.AccessControl;
-using ClosedXML.Excel.CalcEngine;
-using DocumentFormat.OpenXml;
-
-namespace ClosedXML.Excel
-{
- using System.Linq;
- using System.Data;
-
- public enum XLEventTracking { Enabled, Disabled }
- public enum XLCalculateMode
- {
- Auto,
- AutoNoTable,
- Manual,
- Default
- };
-
- public enum XLReferenceStyle
- {
- R1C1,
- A1,
- Default
- };
-
- public enum XLCellSetValueBehavior
- {
- ///
- /// Analyze input string and convert value. For avoid analyzing use escape symbol '
- ///
- Smart = 0,
-
- ///
- /// Direct set value. If value has unsupported type - value will be stored as string returned by
- ///
- Simple = 1,
- }
-
- public partial class XLWorkbook: IDisposable
- {
- #region Static
-
- private static IXLStyle _defaultStyle;
-
- public static IXLStyle DefaultStyle
- {
- get
- {
- return _defaultStyle ?? (_defaultStyle = new XLStyle(null)
- {
- Font = new XLFont(null, null)
- {
- Bold = false,
- Italic = false,
- Underline = XLFontUnderlineValues.None,
- Strikethrough = false,
- VerticalAlignment =
- XLFontVerticalTextAlignmentValues.
- Baseline,
- FontSize = 11,
- FontColor = XLColor.FromArgb(0, 0, 0),
- FontName = "Calibri",
- FontFamilyNumbering =
- XLFontFamilyNumberingValues.Swiss
- },
- Fill = new XLFill(null)
- {
- BackgroundColor = XLColor.FromIndex(64),
- PatternType = XLFillPatternValues.None,
- PatternColor = XLColor.FromIndex(64)
- },
- Border = new XLBorder(null, null)
- {
- BottomBorder =
- XLBorderStyleValues.None,
- DiagonalBorder =
- XLBorderStyleValues.None,
- DiagonalDown = false,
- DiagonalUp = false,
- LeftBorder = XLBorderStyleValues.None,
- RightBorder = XLBorderStyleValues.None,
- TopBorder = XLBorderStyleValues.None,
- BottomBorderColor = XLColor.Black,
- DiagonalBorderColor = XLColor.Black,
- LeftBorderColor = XLColor.Black,
- RightBorderColor = XLColor.Black,
- TopBorderColor = XLColor.Black
- },
- NumberFormat =
- new XLNumberFormat(null, null) {NumberFormatId = 0},
- Alignment = new XLAlignment(null)
- {
- Indent = 0,
- Horizontal =
- XLAlignmentHorizontalValues.
- General,
- JustifyLastLine = false,
- ReadingOrder =
- XLAlignmentReadingOrderValues.
- ContextDependent,
- RelativeIndent = 0,
- ShrinkToFit = false,
- TextRotation = 0,
- Vertical =
- XLAlignmentVerticalValues.
- Bottom,
- WrapText = false
- },
- Protection = new XLProtection(null)
- {
- Locked = true,
- Hidden = false
- }
- });
- }
- }
-
- public static Double DefaultRowHeight { get; private set; }
- public static Double DefaultColumnWidth { get; private set; }
-
- public static IXLPageSetup DefaultPageOptions
- {
- get
- {
- var defaultPageOptions = new XLPageSetup(null, null)
- {
- PageOrientation = XLPageOrientation.Default,
- Scale = 100,
- PaperSize = XLPaperSize.LetterPaper,
- Margins = new XLMargins
- {
- Top = 0.75,
- Bottom = 0.5,
- Left = 0.75,
- Right = 0.75,
- Header = 0.5,
- Footer = 0.75
- },
- ScaleHFWithDocument = true,
- AlignHFWithMargins = true,
- PrintErrorValue = XLPrintErrorValues.Displayed,
- ShowComments = XLShowCommentsValues.None
- };
- return defaultPageOptions;
- }
- }
-
- public static IXLOutline DefaultOutline
- {
- get
- {
- return new XLOutline(null)
- {
- SummaryHLocation = XLOutlineSummaryHLocation.Right,
- SummaryVLocation = XLOutlineSummaryVLocation.Bottom
- };
- }
- }
-
- ///
- /// Behavior for
- ///
- public static XLCellSetValueBehavior CellSetValueBehavior { get; set; }
-
- #endregion
-
- internal readonly List UnsupportedSheets =
- new List();
-
- private readonly Dictionary _stylesById = new Dictionary();
- private readonly Dictionary _stylesByStyle = new Dictionary();
-
- public XLEventTracking EventTracking { get; set; }
-
- internal Int32 GetStyleId(IXLStyle style)
- {
- Int32 cached;
- if (_stylesByStyle.TryGetValue(style, out cached))
- return cached;
-
- var count = _stylesByStyle.Count;
- var styleToUse = new XLStyle(null, style);
- _stylesByStyle.Add(styleToUse, count);
- _stylesById.Add(count, styleToUse);
- return count;
- }
-
- internal IXLStyle GetStyleById(Int32 id)
- {
- return _stylesById[id];
- }
-
- #region Nested Type: XLLoadSource
-
- private enum XLLoadSource
- {
- New,
- File,
- Stream
- };
-
- #endregion
-
- internal XLWorksheets WorksheetsInternal { get; private set; }
-
- ///
- /// Gets an object to manipulate the worksheets.
- ///
- public IXLWorksheets Worksheets
- {
- get { return WorksheetsInternal; }
- }
-
- ///
- /// Gets an object to manipulate this workbook's named ranges.
- ///
- public IXLNamedRanges NamedRanges { get; private set; }
-
- ///
- /// Gets an object to manipulate this workbook's theme.
- ///
- public IXLTheme Theme { get; private set; }
-
- ///
- /// Gets or sets the default style for the workbook.
- /// All new worksheets will use this style.
- ///
- public IXLStyle Style { get; set; }
-
- ///
- /// Gets or sets the default row height for the workbook.
- /// All new worksheets will use this row height.
- ///
- public Double RowHeight { get; set; }
-
- ///
- /// Gets or sets the default column width for the workbook.
- /// All new worksheets will use this column width.
- ///
- public Double ColumnWidth { get; set; }
-
- ///
- /// Gets or sets the default page options for the workbook.
- /// All new worksheets will use these page options.
- ///
- public IXLPageSetup PageOptions { get; set; }
-
- ///
- /// Gets or sets the default outline options for the workbook.
- /// All new worksheets will use these outline options.
- ///
- public IXLOutline Outline { get; set; }
-
- ///
- /// Gets or sets the workbook's properties.
- ///
- public XLWorkbookProperties Properties { get; set; }
-
- ///
- /// Gets or sets the workbook's calculation mode.
- ///
- public XLCalculateMode CalculateMode { get; set; }
-
-
- public Boolean CalculationOnSave { get; set; }
- public Boolean ForceFullCalculation { get; set; }
- public Boolean FullCalculationOnLoad { get; set; }
- public Boolean FullPrecision { get; set; }
-
- ///
- /// Gets or sets the workbook's reference style.
- ///
- public XLReferenceStyle ReferenceStyle { get; set; }
-
- public IXLCustomProperties CustomProperties { get; private set; }
-
- public Boolean ShowFormulas { get; set; }
- public Boolean ShowGridLines { get; set; }
- public Boolean ShowOutlineSymbols { get; set; }
- public Boolean ShowRowColHeaders { get; set; }
- public Boolean ShowRuler { get; set; }
- public Boolean ShowWhiteSpace { get; set; }
- public Boolean ShowZeros { get; set; }
- public Boolean RightToLeft { get; set; }
-
- public Boolean DefaultShowFormulas
- {
- get { return false; }
- }
-
- public Boolean DefaultShowGridLines
- {
- get { return true; }
- }
-
- public Boolean DefaultShowOutlineSymbols
- {
- get { return true; }
- }
-
- public Boolean DefaultShowRowColHeaders
- {
- get { return true; }
- }
-
- public Boolean DefaultShowRuler
- {
- get { return true; }
- }
-
- public Boolean DefaultShowWhiteSpace
- {
- get { return true; }
- }
-
- public Boolean DefaultShowZeros
- {
- get { return true; }
- }
-
- public Boolean DefaultRightToLeft
- {
- get { return false; }
- }
-
- private void InitializeTheme()
- {
- Theme = new XLTheme
- {
- Text1 = XLColor.FromHtml("#FF000000"),
- Background1 = XLColor.FromHtml("#FFFFFFFF"),
- Text2 = XLColor.FromHtml("#FF1F497D"),
- Background2 = XLColor.FromHtml("#FFEEECE1"),
- Accent1 = XLColor.FromHtml("#FF4F81BD"),
- Accent2 = XLColor.FromHtml("#FFC0504D"),
- Accent3 = XLColor.FromHtml("#FF9BBB59"),
- Accent4 = XLColor.FromHtml("#FF8064A2"),
- Accent5 = XLColor.FromHtml("#FF4BACC6"),
- Accent6 = XLColor.FromHtml("#FFF79646"),
- Hyperlink = XLColor.FromHtml("#FF0000FF"),
- FollowedHyperlink = XLColor.FromHtml("#FF800080")
- };
- }
-
- internal XLColor GetXLColor(XLThemeColor themeColor)
- {
- switch (themeColor)
- {
- case XLThemeColor.Text1:
- return Theme.Text1;
- case XLThemeColor.Background1:
- return Theme.Background1;
- case XLThemeColor.Text2:
- return Theme.Text2;
- case XLThemeColor.Background2:
- return Theme.Background2;
- case XLThemeColor.Accent1:
- return Theme.Accent1;
- case XLThemeColor.Accent2:
- return Theme.Accent2;
- case XLThemeColor.Accent3:
- return Theme.Accent3;
- case XLThemeColor.Accent4:
- return Theme.Accent4;
- case XLThemeColor.Accent5:
- return Theme.Accent5;
- case XLThemeColor.Accent6:
- return Theme.Accent6;
- default:
- throw new ArgumentException("Invalid theme color");
- }
- }
-
- public IXLNamedRange NamedRange(String rangeName)
- {
- if (rangeName.Contains("!"))
- {
- var split = rangeName.Split('!');
- var first = split[0];
- var wsName = first.StartsWith("'") ? first.Substring(1, first.Length - 2) : first;
- var name = split[1];
- IXLWorksheet ws;
- if (TryGetWorksheet(wsName, out ws))
- {
- var range = ws.NamedRange(name);
- return range ?? NamedRange(name);
- }
- return null;
- }
- return NamedRanges.NamedRange(rangeName);
- }
-
- public Boolean TryGetWorksheet(String name, out IXLWorksheet worksheet)
- {
- if (Worksheets.Any(w => string.Equals(w.Name, XLWorksheets.TrimSheetName(name), StringComparison.OrdinalIgnoreCase)))
- {
- worksheet = Worksheet(name);
- return true;
- }
-
- worksheet = null;
- return false;
- }
-
- public IXLRange RangeFromFullAddress(String rangeAddress, out IXLWorksheet ws)
- {
- ws = null;
- if (!rangeAddress.Contains('!')) return null;
-
- var split = rangeAddress.Split('!');
- var first = split[0];
- var wsName = first.StartsWith("'") ? first.Substring(1, first.Length - 2) : first;
- var localRange = split[1];
- if (TryGetWorksheet(wsName, out ws))
- {
- return ws.Range(localRange);
- }
- return null;
- }
-
-
- ///
- /// Saves the current workbook.
- ///
- public void Save()
- {
-#if DEBUG
- Save(true, false);
-#else
- Save(false, false);
-#endif
- }
-
- ///
- /// Saves the current workbook and optionally performs validation
- ///
- public void Save(Boolean validate, Boolean evaluateFormulae = false)
- {
- checkForWorksheetsPresent();
- if (_loadSource == XLLoadSource.New)
- throw new Exception("This is a new file, please use one of the SaveAs methods.");
-
- if (_loadSource == XLLoadSource.Stream)
- {
- CreatePackage(_originalStream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
- }
- else
- CreatePackage(_originalFile, _spreadsheetDocumentType, validate, evaluateFormulae);
- }
-
- ///
- /// Saves the current workbook to a file.
- ///
- public void SaveAs(String file)
- {
-#if DEBUG
- SaveAs(file, true, false);
-#else
- SaveAs(file, false, false);
-#endif
- }
-
- ///
- /// Saves the current workbook to a file and optionally validates it.
- ///
- public void SaveAs(String file, Boolean validate, Boolean evaluateFormulae = false)
- {
- checkForWorksheetsPresent();
- PathHelper.CreateDirectory(Path.GetDirectoryName(file));
- if (_loadSource == XLLoadSource.New)
- {
- if (File.Exists(file))
- File.Delete(file);
-
- CreatePackage(file, GetSpreadsheetDocumentType(file), validate, evaluateFormulae);
- }
- else if (_loadSource == XLLoadSource.File)
- {
- if (String.Compare(_originalFile.Trim(), file.Trim(), true) != 0)
- File.Copy(_originalFile, file, true);
-
- CreatePackage(file, GetSpreadsheetDocumentType(file), validate, evaluateFormulae);
- }
- else if (_loadSource == XLLoadSource.Stream)
- {
- _originalStream.Position = 0;
-
- using (var fileStream = File.Create(file))
- {
- CopyStream(_originalStream, fileStream);
- //fileStream.Position = 0;
- CreatePackage(fileStream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
- fileStream.Close();
- }
- }
- }
-
- private static SpreadsheetDocumentType GetSpreadsheetDocumentType(string filePath)
- {
- var extension = Path.GetExtension(filePath);
- if (extension == null) throw new Exception("Empty extension is not supported.");
- extension = extension.Substring(1).ToLowerInvariant();
-
- switch (extension)
- {
- case "xlsm":
- case "xltm":
- return SpreadsheetDocumentType.MacroEnabledWorkbook;
- case "xlsx":
- case "xltx":
- return SpreadsheetDocumentType.Workbook;
- default:
- throw new ArgumentException(String.Format("Extension '{0}' is not supported. Supported extensions are '.xlsx', '.xslm', '.xltx' and '.xltm'.", extension));
-
- }
- }
-
- private void checkForWorksheetsPresent()
- {
- if (Worksheets.Count() == 0)
- throw new Exception("Workbooks need at least one worksheet.");
- }
-
- ///
- /// Saves the current workbook to a stream.
- ///
- public void SaveAs(Stream stream)
- {
-#if DEBUG
- SaveAs(stream, true, false);
-#else
- SaveAs(stream, false, false);
-#endif
- }
-
- ///
- /// Saves the current workbook to a stream and optionally validates it.
- ///
- public void SaveAs(Stream stream, Boolean validate, Boolean evaluateFormulae = false)
- {
- checkForWorksheetsPresent();
- if (_loadSource == XLLoadSource.New)
- {
- // dm 20130422, this method or better the method SpreadsheetDocument.Create which is called
- // inside of 'CreatePackage' need a stream which CanSeek & CanRead
- // and an ordinary Response stream of a webserver can't do this
- // so we have to ask and provide a way around this
- if (stream.CanRead && stream.CanSeek && stream.CanWrite)
- {
- // all is fine the package can be created in a direct way
- CreatePackage(stream, true, _spreadsheetDocumentType, validate, evaluateFormulae);
- }
- else
- {
- // the harder way
- MemoryStream ms = new MemoryStream();
- CreatePackage(ms, true, _spreadsheetDocumentType, validate, evaluateFormulae);
- // not really nessesary, because I changed CopyStream too.
- // but for better understanding and if somebody in the future
- // provide an changed version of CopyStream
- ms.Position = 0;
- CopyStream(ms, stream);
- }
- }
- else if (_loadSource == XLLoadSource.File)
- {
- using (var fileStream = new FileStream(_originalFile, FileMode.Open, FileAccess.Read))
- {
- CopyStream(fileStream, stream);
- fileStream.Close();
- }
- CreatePackage(stream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
- }
- else if (_loadSource == XLLoadSource.Stream)
- {
- _originalStream.Position = 0;
- if (_originalStream != stream)
- CopyStream(_originalStream, stream);
-
- CreatePackage(stream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
- }
- }
-
- internal static void CopyStream(Stream input, Stream output)
- {
- var buffer = new byte[8 * 1024];
- int len;
- // dm 20130422, it is always a good idea to rewind the input stream, or not?
- if (input.CanSeek)
- input.Seek(0, SeekOrigin.Begin);
- while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
- output.Write(buffer, 0, len);
- // dm 20130422, and flushing the output after write
- output.Flush();
-
- }
-
- public IXLWorksheet Worksheet(String name)
- {
- return WorksheetsInternal.Worksheet(name);
- }
-
- public IXLWorksheet Worksheet(Int32 position)
- {
- return WorksheetsInternal.Worksheet(position);
- }
-
- public IXLCustomProperty CustomProperty(String name)
- {
- return CustomProperties.CustomProperty(name);
- }
-
- public IXLCells FindCells(Func predicate)
- {
- var cells = new XLCells(false, false);
- foreach (XLWorksheet ws in WorksheetsInternal)
- {
- foreach (XLCell cell in ws.CellsUsed(true))
- {
- if (predicate(cell))
- cells.Add(cell);
- }
- }
- return cells;
- }
-
- public IXLRows FindRows(Func predicate)
- {
- var rows = new XLRows(null);
- foreach (XLWorksheet ws in WorksheetsInternal)
- {
- foreach (IXLRow row in ws.Rows().Where(predicate))
- rows.Add(row as XLRow);
- }
- return rows;
- }
-
- public IXLColumns FindColumns(Func predicate)
- {
- var columns = new XLColumns(null);
- foreach (XLWorksheet ws in WorksheetsInternal)
- {
- foreach (IXLColumn column in ws.Columns().Where(predicate))
- columns.Add(column as XLColumn);
- }
- return columns;
- }
-
-#region Fields
-
- private readonly XLLoadSource _loadSource = XLLoadSource.New;
- private readonly String _originalFile;
- private readonly Stream _originalStream;
-
-#endregion
-
-#region Constructor
-
-
- ///
- /// Creates a new Excel workbook.
- ///
- public XLWorkbook()
- :this(XLEventTracking.Enabled)
- {
-
- }
-
- public XLWorkbook(XLEventTracking eventTracking)
- {
- EventTracking = eventTracking;
- DefaultRowHeight = 15;
- DefaultColumnWidth = 8.43;
- Style = new XLStyle(null, DefaultStyle);
- RowHeight = DefaultRowHeight;
- ColumnWidth = DefaultColumnWidth;
- PageOptions = DefaultPageOptions;
- Outline = DefaultOutline;
- Properties = new XLWorkbookProperties();
- CalculateMode = XLCalculateMode.Default;
- ReferenceStyle = XLReferenceStyle.Default;
- InitializeTheme();
- ShowFormulas = DefaultShowFormulas;
- ShowGridLines = DefaultShowGridLines;
- ShowOutlineSymbols = DefaultShowOutlineSymbols;
- ShowRowColHeaders = DefaultShowRowColHeaders;
- ShowRuler = DefaultShowRuler;
- ShowWhiteSpace = DefaultShowWhiteSpace;
- ShowZeros = DefaultShowZeros;
- RightToLeft = DefaultRightToLeft;
- WorksheetsInternal = new XLWorksheets(this);
- NamedRanges = new XLNamedRanges(this);
- CustomProperties = new XLCustomProperties(this);
- ShapeIdManager = new XLIdManager();
- Author = Environment.UserName;
- }
-
- ///
- /// Opens an existing workbook from a file.
- ///
- /// The file to open.
- public XLWorkbook(String file)
- : this(file, XLEventTracking.Enabled)
- {
-
- }
-
- public XLWorkbook(String file, XLEventTracking eventTracking)
- : this(eventTracking)
- {
- _loadSource = XLLoadSource.File;
- _originalFile = file;
- _spreadsheetDocumentType = GetSpreadsheetDocumentType(_originalFile);
- Load(file);
- }
-
-
-
- ///
- /// Opens an existing workbook from a stream.
- ///
- /// The stream to open.
- public XLWorkbook(Stream stream):this(stream, XLEventTracking.Enabled)
- {
-
- }
-
- public XLWorkbook(Stream stream, XLEventTracking eventTracking)
- : this(eventTracking)
- {
- _loadSource = XLLoadSource.Stream;
- _originalStream = stream;
- Load(stream);
- }
-
-#endregion
-
-#region Nested type: UnsupportedSheet
-
- internal sealed class UnsupportedSheet
- {
- public Boolean IsActive;
- public UInt32 SheetId;
- public Int32 Position;
- }
-
-#endregion
-
- public IXLCell Cell(String namedCell)
- {
- var namedRange = NamedRange(namedCell);
- if (namedRange == null) return null;
- var range = namedRange.Ranges.FirstOrDefault();
- if (range == null) return null;
- return range.FirstCell();
- }
-
- public IXLCells Cells(String namedCells)
- {
- return Ranges(namedCells).Cells();
- }
-
- public IXLRange Range(String range)
- {
- var namedRange = NamedRange(range);
- if (namedRange != null)
- return namedRange.Ranges.FirstOrDefault();
- else
- {
- IXLWorksheet ws;
- var r = RangeFromFullAddress(range, out ws);
- return r;
- }
- }
-
- public IXLRanges Ranges(String ranges)
- {
- var retVal = new XLRanges();
- var rangePairs = ranges.Split(',');
- foreach (var range in rangePairs.Select(r => Range(r.Trim())).Where(range => range != null))
- {
- retVal.Add(range);
- }
- return retVal;
- }
-
- internal XLIdManager ShapeIdManager { get; private set; }
-
-
- public void Dispose()
- {
- Worksheets.ForEach(w => w.Dispose());
- }
-
- public Boolean Use1904DateSystem { get; set; }
- public XLWorkbook SetUse1904DateSystem()
- {
- return SetUse1904DateSystem(true);
- }
-
- public XLWorkbook SetUse1904DateSystem(Boolean value)
- {
- Use1904DateSystem = value;
- return this;
- }
-
- public IXLWorksheet AddWorksheet(String sheetName)
- {
- return Worksheets.Add(sheetName);
- }
-
- public IXLWorksheet AddWorksheet(String sheetName, Int32 position)
- {
- return Worksheets.Add(sheetName, position);
- }
- public IXLWorksheet AddWorksheet(DataTable dataTable)
- {
- return Worksheets.Add(dataTable);
- }
- public void AddWorksheet(DataSet dataSet)
- {
- Worksheets.Add(dataSet);
- }
-
- public void AddWorksheet(IXLWorksheet worksheet)
- {
- worksheet.CopyTo(this, worksheet.Name);
- }
-
- public IXLWorksheet AddWorksheet(DataTable dataTable, String sheetName)
- {
- return Worksheets.Add(dataTable, sheetName);
- }
-
- private XLCalcEngine _calcEngine;
- private XLCalcEngine CalcEngine
- {
- get { return _calcEngine ?? (_calcEngine = new XLCalcEngine(this)); }
- }
- public Object Evaluate(String expression)
- {
- return CalcEngine.Evaluate(expression);
- }
-
- private static XLCalcEngine _calcEngineExpr;
- private SpreadsheetDocumentType _spreadsheetDocumentType;
-
- private static XLCalcEngine CalcEngineExpr
- {
- get { return _calcEngineExpr ?? (_calcEngineExpr = new XLCalcEngine()); }
- }
- public static Object EvaluateExpr(String expression)
- {
- return CalcEngineExpr.Evaluate(expression);
- }
-
- public String Author { get; set; }
-
- public Boolean LockStructure { get; set; }
- public XLWorkbook SetLockStructure(Boolean value) { LockStructure = value; return this; }
- public Boolean LockWindows { get; set; }
- public XLWorkbook SetLockWindows(Boolean value) { LockWindows = value; return this; }
- internal HexBinaryValue LockPassword { get; set; }
-
- public void Protect(Boolean lockStructure, Boolean lockWindows, String workbookPassword)
- {
- if (workbookPassword != null)
- {
- var hashPassword = GetPasswordHash(workbookPassword);
- if (LockPassword != null)
- {
- if (LockPassword != hashPassword)
- {
- throw new ArgumentException("Invalid password");
- }
- else
- {
- if (lockStructure || lockWindows)
- {
- throw new InvalidOperationException("The workbook is already protected");
- }
- else
- {
- //Unprotect workbook using password.
- LockPassword = null;
- }
- }
- }
- else
- {
- if (lockStructure || lockWindows)
- {
- //Protect workbook using password.
- LockPassword = hashPassword;
- }
- }
- }
- else
- {
- if (LockPassword != null)
- {
- throw new InvalidOperationException("The workbook is password protected");
- }
- }
- LockStructure = lockStructure;
- LockWindows = lockWindows;
- }
-
- public void Protect()
- {
- Protect(true);
- }
-
- public void Protect(string workbookPassword)
- {
- Protect(true, false, workbookPassword);
- }
-
- public void Protect(Boolean lockStructure)
- {
- Protect(lockStructure, false);
- }
-
- public void Protect(Boolean lockStructure, Boolean lockWindows)
- {
- Protect(lockStructure, lockWindows, null);
- }
-
- public void Unprotect()
- {
- Protect(false, false);
- }
-
- public void Unprotect(string workbookPassword)
- {
- Protect(false, false, workbookPassword);
- }
-
- private String GetPasswordHash(String password)
- {
- Int32 pLength = password.Length;
- Int32 hash = 0;
- if (pLength == 0) return String.Empty;
-
- for (Int32 i = pLength - 1; i >= 0; i--)
- {
- hash ^= password[i];
- hash = hash >> 14 & 0x01 | hash << 1 & 0x7fff;
- }
- hash ^= 0x8000 | 'N' << 8 | 'K';
- hash ^= pLength;
- return hash.ToString("X");
- }
- }
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.AccessControl;
+using ClosedXML.Excel.CalcEngine;
+using DocumentFormat.OpenXml;
+
+namespace ClosedXML.Excel
+{
+ using System.Linq;
+ using System.Data;
+
+ public enum XLEventTracking { Enabled, Disabled }
+ public enum XLCalculateMode
+ {
+ Auto,
+ AutoNoTable,
+ Manual,
+ Default
+ };
+
+ public enum XLReferenceStyle
+ {
+ R1C1,
+ A1,
+ Default
+ };
+
+ public enum XLCellSetValueBehavior
+ {
+ ///
+ /// Analyze input string and convert value. For avoid analyzing use escape symbol '
+ ///
+ Smart = 0,
+
+ ///
+ /// Direct set value. If value has unsupported type - value will be stored as string returned by
+ ///
+ Simple = 1,
+ }
+
+ public partial class XLWorkbook: IDisposable
+ {
+ #region Static
+
+ private static IXLStyle _defaultStyle;
+
+ public static IXLStyle DefaultStyle
+ {
+ get
+ {
+ return _defaultStyle ?? (_defaultStyle = new XLStyle(null)
+ {
+ Font = new XLFont(null, null)
+ {
+ Bold = false,
+ Italic = false,
+ Underline = XLFontUnderlineValues.None,
+ Strikethrough = false,
+ VerticalAlignment =
+ XLFontVerticalTextAlignmentValues.
+ Baseline,
+ FontSize = 11,
+ FontColor = XLColor.FromArgb(0, 0, 0),
+ FontName = "Calibri",
+ FontFamilyNumbering =
+ XLFontFamilyNumberingValues.Swiss
+ },
+ Fill = new XLFill(null)
+ {
+ BackgroundColor = XLColor.FromIndex(64),
+ PatternType = XLFillPatternValues.None,
+ PatternColor = XLColor.FromIndex(64)
+ },
+ Border = new XLBorder(null, null)
+ {
+ BottomBorder =
+ XLBorderStyleValues.None,
+ DiagonalBorder =
+ XLBorderStyleValues.None,
+ DiagonalDown = false,
+ DiagonalUp = false,
+ LeftBorder = XLBorderStyleValues.None,
+ RightBorder = XLBorderStyleValues.None,
+ TopBorder = XLBorderStyleValues.None,
+ BottomBorderColor = XLColor.Black,
+ DiagonalBorderColor = XLColor.Black,
+ LeftBorderColor = XLColor.Black,
+ RightBorderColor = XLColor.Black,
+ TopBorderColor = XLColor.Black
+ },
+ NumberFormat =
+ new XLNumberFormat(null, null) {NumberFormatId = 0},
+ Alignment = new XLAlignment(null)
+ {
+ Indent = 0,
+ Horizontal =
+ XLAlignmentHorizontalValues.
+ General,
+ JustifyLastLine = false,
+ ReadingOrder =
+ XLAlignmentReadingOrderValues.
+ ContextDependent,
+ RelativeIndent = 0,
+ ShrinkToFit = false,
+ TextRotation = 0,
+ Vertical =
+ XLAlignmentVerticalValues.
+ Bottom,
+ WrapText = false
+ },
+ Protection = new XLProtection(null)
+ {
+ Locked = true,
+ Hidden = false
+ }
+ });
+ }
+ }
+
+ public static Double DefaultRowHeight { get; private set; }
+ public static Double DefaultColumnWidth { get; private set; }
+
+ public static IXLPageSetup DefaultPageOptions
+ {
+ get
+ {
+ var defaultPageOptions = new XLPageSetup(null, null)
+ {
+ PageOrientation = XLPageOrientation.Default,
+ Scale = 100,
+ PaperSize = XLPaperSize.LetterPaper,
+ Margins = new XLMargins
+ {
+ Top = 0.75,
+ Bottom = 0.5,
+ Left = 0.75,
+ Right = 0.75,
+ Header = 0.5,
+ Footer = 0.75
+ },
+ ScaleHFWithDocument = true,
+ AlignHFWithMargins = true,
+ PrintErrorValue = XLPrintErrorValues.Displayed,
+ ShowComments = XLShowCommentsValues.None
+ };
+ return defaultPageOptions;
+ }
+ }
+
+ public static IXLOutline DefaultOutline
+ {
+ get
+ {
+ return new XLOutline(null)
+ {
+ SummaryHLocation = XLOutlineSummaryHLocation.Right,
+ SummaryVLocation = XLOutlineSummaryVLocation.Bottom
+ };
+ }
+ }
+
+ ///
+ /// Behavior for
+ ///
+ public static XLCellSetValueBehavior CellSetValueBehavior { get; set; }
+
+ #endregion
+
+ internal readonly List UnsupportedSheets =
+ new List();
+
+ private readonly Dictionary _stylesById = new Dictionary();
+ private readonly Dictionary _stylesByStyle = new Dictionary();
+
+ public XLEventTracking EventTracking { get; set; }
+
+ internal Int32 GetStyleId(IXLStyle style)
+ {
+ Int32 cached;
+ if (_stylesByStyle.TryGetValue(style, out cached))
+ return cached;
+
+ var count = _stylesByStyle.Count;
+ var styleToUse = new XLStyle(null, style);
+ _stylesByStyle.Add(styleToUse, count);
+ _stylesById.Add(count, styleToUse);
+ return count;
+ }
+
+ internal IXLStyle GetStyleById(Int32 id)
+ {
+ return _stylesById[id];
+ }
+
+ #region Nested Type: XLLoadSource
+
+ private enum XLLoadSource
+ {
+ New,
+ File,
+ Stream
+ };
+
+ #endregion
+
+ internal XLWorksheets WorksheetsInternal { get; private set; }
+
+ ///
+ /// Gets an object to manipulate the worksheets.
+ ///
+ public IXLWorksheets Worksheets
+ {
+ get { return WorksheetsInternal; }
+ }
+
+ ///
+ /// Gets an object to manipulate this workbook's named ranges.
+ ///
+ public IXLNamedRanges NamedRanges { get; private set; }
+
+ ///
+ /// Gets an object to manipulate this workbook's theme.
+ ///
+ public IXLTheme Theme { get; private set; }
+
+ ///
+ /// Gets or sets the default style for the workbook.
+ /// All new worksheets will use this style.
+ ///
+ public IXLStyle Style { get; set; }
+
+ ///
+ /// Gets or sets the default row height for the workbook.
+ /// All new worksheets will use this row height.
+ ///
+ public Double RowHeight { get; set; }
+
+ ///
+ /// Gets or sets the default column width for the workbook.
+ /// All new worksheets will use this column width.
+ ///
+ public Double ColumnWidth { get; set; }
+
+ ///
+ /// Gets or sets the default page options for the workbook.
+ /// All new worksheets will use these page options.
+ ///
+ public IXLPageSetup PageOptions { get; set; }
+
+ ///
+ /// Gets or sets the default outline options for the workbook.
+ /// All new worksheets will use these outline options.
+ ///
+ public IXLOutline Outline { get; set; }
+
+ ///
+ /// Gets or sets the workbook's properties.
+ ///
+ public XLWorkbookProperties Properties { get; set; }
+
+ ///
+ /// Gets or sets the workbook's calculation mode.
+ ///
+ public XLCalculateMode CalculateMode { get; set; }
+
+
+ public Boolean CalculationOnSave { get; set; }
+ public Boolean ForceFullCalculation { get; set; }
+ public Boolean FullCalculationOnLoad { get; set; }
+ public Boolean FullPrecision { get; set; }
+
+ ///
+ /// Gets or sets the workbook's reference style.
+ ///
+ public XLReferenceStyle ReferenceStyle { get; set; }
+
+ public IXLCustomProperties CustomProperties { get; private set; }
+
+ public Boolean ShowFormulas { get; set; }
+ public Boolean ShowGridLines { get; set; }
+ public Boolean ShowOutlineSymbols { get; set; }
+ public Boolean ShowRowColHeaders { get; set; }
+ public Boolean ShowRuler { get; set; }
+ public Boolean ShowWhiteSpace { get; set; }
+ public Boolean ShowZeros { get; set; }
+ public Boolean RightToLeft { get; set; }
+
+ public Boolean DefaultShowFormulas
+ {
+ get { return false; }
+ }
+
+ public Boolean DefaultShowGridLines
+ {
+ get { return true; }
+ }
+
+ public Boolean DefaultShowOutlineSymbols
+ {
+ get { return true; }
+ }
+
+ public Boolean DefaultShowRowColHeaders
+ {
+ get { return true; }
+ }
+
+ public Boolean DefaultShowRuler
+ {
+ get { return true; }
+ }
+
+ public Boolean DefaultShowWhiteSpace
+ {
+ get { return true; }
+ }
+
+ public Boolean DefaultShowZeros
+ {
+ get { return true; }
+ }
+
+ public Boolean DefaultRightToLeft
+ {
+ get { return false; }
+ }
+
+ private void InitializeTheme()
+ {
+ Theme = new XLTheme
+ {
+ Text1 = XLColor.FromHtml("#FF000000"),
+ Background1 = XLColor.FromHtml("#FFFFFFFF"),
+ Text2 = XLColor.FromHtml("#FF1F497D"),
+ Background2 = XLColor.FromHtml("#FFEEECE1"),
+ Accent1 = XLColor.FromHtml("#FF4F81BD"),
+ Accent2 = XLColor.FromHtml("#FFC0504D"),
+ Accent3 = XLColor.FromHtml("#FF9BBB59"),
+ Accent4 = XLColor.FromHtml("#FF8064A2"),
+ Accent5 = XLColor.FromHtml("#FF4BACC6"),
+ Accent6 = XLColor.FromHtml("#FFF79646"),
+ Hyperlink = XLColor.FromHtml("#FF0000FF"),
+ FollowedHyperlink = XLColor.FromHtml("#FF800080")
+ };
+ }
+
+ internal XLColor GetXLColor(XLThemeColor themeColor)
+ {
+ switch (themeColor)
+ {
+ case XLThemeColor.Text1:
+ return Theme.Text1;
+ case XLThemeColor.Background1:
+ return Theme.Background1;
+ case XLThemeColor.Text2:
+ return Theme.Text2;
+ case XLThemeColor.Background2:
+ return Theme.Background2;
+ case XLThemeColor.Accent1:
+ return Theme.Accent1;
+ case XLThemeColor.Accent2:
+ return Theme.Accent2;
+ case XLThemeColor.Accent3:
+ return Theme.Accent3;
+ case XLThemeColor.Accent4:
+ return Theme.Accent4;
+ case XLThemeColor.Accent5:
+ return Theme.Accent5;
+ case XLThemeColor.Accent6:
+ return Theme.Accent6;
+ default:
+ throw new ArgumentException("Invalid theme color");
+ }
+ }
+
+ public IXLNamedRange NamedRange(String rangeName)
+ {
+ if (rangeName.Contains("!"))
+ {
+ var split = rangeName.Split('!');
+ var first = split[0];
+ var wsName = first.StartsWith("'") ? first.Substring(1, first.Length - 2) : first;
+ var name = split[1];
+ IXLWorksheet ws;
+ if (TryGetWorksheet(wsName, out ws))
+ {
+ var range = ws.NamedRange(name);
+ return range ?? NamedRange(name);
+ }
+ return null;
+ }
+ return NamedRanges.NamedRange(rangeName);
+ }
+
+ public Boolean TryGetWorksheet(String name, out IXLWorksheet worksheet)
+ {
+ if (Worksheets.Any(w => string.Equals(w.Name, XLWorksheets.TrimSheetName(name), StringComparison.OrdinalIgnoreCase)))
+ {
+ worksheet = Worksheet(name);
+ return true;
+ }
+
+ worksheet = null;
+ return false;
+ }
+
+ public IXLRange RangeFromFullAddress(String rangeAddress, out IXLWorksheet ws)
+ {
+ ws = null;
+ if (!rangeAddress.Contains('!')) return null;
+
+ var split = rangeAddress.Split('!');
+ var first = split[0];
+ var wsName = first.StartsWith("'") ? first.Substring(1, first.Length - 2) : first;
+ var localRange = split[1];
+ if (TryGetWorksheet(wsName, out ws))
+ {
+ return ws.Range(localRange);
+ }
+ return null;
+ }
+
+
+ ///
+ /// Saves the current workbook.
+ ///
+ public void Save()
+ {
+#if DEBUG
+ Save(true, false);
+#else
+ Save(false, false);
+#endif
+ }
+
+ ///
+ /// Saves the current workbook and optionally performs validation
+ ///
+ public void Save(Boolean validate, Boolean evaluateFormulae = false)
+ {
+ checkForWorksheetsPresent();
+ if (_loadSource == XLLoadSource.New)
+ throw new Exception("This is a new file, please use one of the SaveAs methods.");
+
+ if (_loadSource == XLLoadSource.Stream)
+ {
+ CreatePackage(_originalStream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ }
+ else
+ CreatePackage(_originalFile, _spreadsheetDocumentType, validate, evaluateFormulae);
+ }
+
+ ///
+ /// Saves the current workbook to a file.
+ ///
+ public void SaveAs(String file)
+ {
+#if DEBUG
+ SaveAs(file, true, false);
+#else
+ SaveAs(file, false, false);
+#endif
+ }
+
+ ///
+ /// Saves the current workbook to a file and optionally validates it.
+ ///
+ public void SaveAs(String file, Boolean validate, Boolean evaluateFormulae = false)
+ {
+ checkForWorksheetsPresent();
+ PathHelper.CreateDirectory(Path.GetDirectoryName(file));
+ if (_loadSource == XLLoadSource.New)
+ {
+ if (File.Exists(file))
+ File.Delete(file);
+
+ CreatePackage(file, GetSpreadsheetDocumentType(file), validate, evaluateFormulae);
+ }
+ else if (_loadSource == XLLoadSource.File)
+ {
+ if (String.Compare(_originalFile.Trim(), file.Trim(), true) != 0)
+ File.Copy(_originalFile, file, true);
+
+ CreatePackage(file, GetSpreadsheetDocumentType(file), validate, evaluateFormulae);
+ }
+ else if (_loadSource == XLLoadSource.Stream)
+ {
+ _originalStream.Position = 0;
+
+ using (var fileStream = File.Create(file))
+ {
+ CopyStream(_originalStream, fileStream);
+ //fileStream.Position = 0;
+ CreatePackage(fileStream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ fileStream.Close();
+ }
+ }
+ }
+
+ private static SpreadsheetDocumentType GetSpreadsheetDocumentType(string filePath)
+ {
+ var extension = Path.GetExtension(filePath);
+ if (extension == null) throw new Exception("Empty extension is not supported.");
+ extension = extension.Substring(1).ToLowerInvariant();
+
+ switch (extension)
+ {
+ case "xlsm":
+ case "xltm":
+ return SpreadsheetDocumentType.MacroEnabledWorkbook;
+ case "xlsx":
+ case "xltx":
+ return SpreadsheetDocumentType.Workbook;
+ default:
+ throw new ArgumentException(String.Format("Extension '{0}' is not supported. Supported extensions are '.xlsx', '.xslm', '.xltx' and '.xltm'.", extension));
+
+ }
+ }
+
+ private void checkForWorksheetsPresent()
+ {
+ if (Worksheets.Count() == 0)
+ throw new Exception("Workbooks need at least one worksheet.");
+ }
+
+ ///
+ /// Saves the current workbook to a stream.
+ ///
+ public void SaveAs(Stream stream)
+ {
+#if DEBUG
+ SaveAs(stream, true, false);
+#else
+ SaveAs(stream, false, false);
+#endif
+ }
+
+ ///
+ /// Saves the current workbook to a stream and optionally validates it.
+ ///
+ public void SaveAs(Stream stream, Boolean validate, Boolean evaluateFormulae = false)
+ {
+ checkForWorksheetsPresent();
+ if (_loadSource == XLLoadSource.New)
+ {
+ // dm 20130422, this method or better the method SpreadsheetDocument.Create which is called
+ // inside of 'CreatePackage' need a stream which CanSeek & CanRead
+ // and an ordinary Response stream of a webserver can't do this
+ // so we have to ask and provide a way around this
+ if (stream.CanRead && stream.CanSeek && stream.CanWrite)
+ {
+ // all is fine the package can be created in a direct way
+ CreatePackage(stream, true, _spreadsheetDocumentType, validate, evaluateFormulae);
+ }
+ else
+ {
+ // the harder way
+ MemoryStream ms = new MemoryStream();
+ CreatePackage(ms, true, _spreadsheetDocumentType, validate, evaluateFormulae);
+ // not really nessesary, because I changed CopyStream too.
+ // but for better understanding and if somebody in the future
+ // provide an changed version of CopyStream
+ ms.Position = 0;
+ CopyStream(ms, stream);
+ }
+ }
+ else if (_loadSource == XLLoadSource.File)
+ {
+ using (var fileStream = new FileStream(_originalFile, FileMode.Open, FileAccess.Read))
+ {
+ CopyStream(fileStream, stream);
+ fileStream.Close();
+ }
+ CreatePackage(stream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ }
+ else if (_loadSource == XLLoadSource.Stream)
+ {
+ _originalStream.Position = 0;
+ if (_originalStream != stream)
+ CopyStream(_originalStream, stream);
+
+ CreatePackage(stream, false, _spreadsheetDocumentType, validate, evaluateFormulae);
+ }
+ }
+
+ internal static void CopyStream(Stream input, Stream output)
+ {
+ var buffer = new byte[8 * 1024];
+ int len;
+ // dm 20130422, it is always a good idea to rewind the input stream, or not?
+ if (input.CanSeek)
+ input.Seek(0, SeekOrigin.Begin);
+ while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
+ output.Write(buffer, 0, len);
+ // dm 20130422, and flushing the output after write
+ output.Flush();
+
+ }
+
+ public IXLWorksheet Worksheet(String name)
+ {
+ return WorksheetsInternal.Worksheet(name);
+ }
+
+ public IXLWorksheet Worksheet(Int32 position)
+ {
+ return WorksheetsInternal.Worksheet(position);
+ }
+
+ public IXLCustomProperty CustomProperty(String name)
+ {
+ return CustomProperties.CustomProperty(name);
+ }
+
+ public IXLCells FindCells(Func predicate)
+ {
+ var cells = new XLCells(false, false);
+ foreach (XLWorksheet ws in WorksheetsInternal)
+ {
+ foreach (XLCell cell in ws.CellsUsed(true))
+ {
+ if (predicate(cell))
+ cells.Add(cell);
+ }
+ }
+ return cells;
+ }
+
+ public IXLRows FindRows(Func predicate)
+ {
+ var rows = new XLRows(null);
+ foreach (XLWorksheet ws in WorksheetsInternal)
+ {
+ foreach (IXLRow row in ws.Rows().Where(predicate))
+ rows.Add(row as XLRow);
+ }
+ return rows;
+ }
+
+ public IXLColumns FindColumns(Func predicate)
+ {
+ var columns = new XLColumns(null);
+ foreach (XLWorksheet ws in WorksheetsInternal)
+ {
+ foreach (IXLColumn column in ws.Columns().Where(predicate))
+ columns.Add(column as XLColumn);
+ }
+ return columns;
+ }
+
+#region Fields
+
+ private readonly XLLoadSource _loadSource = XLLoadSource.New;
+ private readonly String _originalFile;
+ private readonly Stream _originalStream;
+
+#endregion
+
+#region Constructor
+
+
+ ///
+ /// Creates a new Excel workbook.
+ ///
+ public XLWorkbook()
+ :this(XLEventTracking.Enabled)
+ {
+
+ }
+
+ public XLWorkbook(XLEventTracking eventTracking)
+ {
+ EventTracking = eventTracking;
+ DefaultRowHeight = 15;
+ DefaultColumnWidth = 8.43;
+ Style = new XLStyle(null, DefaultStyle);
+ RowHeight = DefaultRowHeight;
+ ColumnWidth = DefaultColumnWidth;
+ PageOptions = DefaultPageOptions;
+ Outline = DefaultOutline;
+ Properties = new XLWorkbookProperties();
+ CalculateMode = XLCalculateMode.Default;
+ ReferenceStyle = XLReferenceStyle.Default;
+ InitializeTheme();
+ ShowFormulas = DefaultShowFormulas;
+ ShowGridLines = DefaultShowGridLines;
+ ShowOutlineSymbols = DefaultShowOutlineSymbols;
+ ShowRowColHeaders = DefaultShowRowColHeaders;
+ ShowRuler = DefaultShowRuler;
+ ShowWhiteSpace = DefaultShowWhiteSpace;
+ ShowZeros = DefaultShowZeros;
+ RightToLeft = DefaultRightToLeft;
+ WorksheetsInternal = new XLWorksheets(this);
+ NamedRanges = new XLNamedRanges(this);
+ CustomProperties = new XLCustomProperties(this);
+ ShapeIdManager = new XLIdManager();
+ Author = Environment.UserName;
+ }
+
+ ///
+ /// Opens an existing workbook from a file.
+ ///
+ /// The file to open.
+ public XLWorkbook(String file)
+ : this(file, XLEventTracking.Enabled)
+ {
+
+ }
+
+ public XLWorkbook(String file, XLEventTracking eventTracking)
+ : this(eventTracking)
+ {
+ _loadSource = XLLoadSource.File;
+ _originalFile = file;
+ _spreadsheetDocumentType = GetSpreadsheetDocumentType(_originalFile);
+ Load(file);
+ }
+
+
+
+ ///
+ /// Opens an existing workbook from a stream.
+ ///
+ /// The stream to open.
+ public XLWorkbook(Stream stream):this(stream, XLEventTracking.Enabled)
+ {
+
+ }
+
+ public XLWorkbook(Stream stream, XLEventTracking eventTracking)
+ : this(eventTracking)
+ {
+ _loadSource = XLLoadSource.Stream;
+ _originalStream = stream;
+ Load(stream);
+ }
+
+#endregion
+
+#region Nested type: UnsupportedSheet
+
+ internal sealed class UnsupportedSheet
+ {
+ public Boolean IsActive;
+ public UInt32 SheetId;
+ public Int32 Position;
+ }
+
+#endregion
+
+ public IXLCell Cell(String namedCell)
+ {
+ var namedRange = NamedRange(namedCell);
+ if (namedRange == null) return null;
+ var range = namedRange.Ranges.FirstOrDefault();
+ if (range == null) return null;
+ return range.FirstCell();
+ }
+
+ public IXLCells Cells(String namedCells)
+ {
+ return Ranges(namedCells).Cells();
+ }
+
+ public IXLRange Range(String range)
+ {
+ var namedRange = NamedRange(range);
+ if (namedRange != null)
+ return namedRange.Ranges.FirstOrDefault();
+ else
+ {
+ IXLWorksheet ws;
+ var r = RangeFromFullAddress(range, out ws);
+ return r;
+ }
+ }
+
+ public IXLRanges Ranges(String ranges)
+ {
+ var retVal = new XLRanges();
+ var rangePairs = ranges.Split(',');
+ foreach (var range in rangePairs.Select(r => Range(r.Trim())).Where(range => range != null))
+ {
+ retVal.Add(range);
+ }
+ return retVal;
+ }
+
+ internal XLIdManager ShapeIdManager { get; private set; }
+
+
+ public void Dispose()
+ {
+ Worksheets.ForEach(w => w.Dispose());
+ }
+
+ public Boolean Use1904DateSystem { get; set; }
+ public XLWorkbook SetUse1904DateSystem()
+ {
+ return SetUse1904DateSystem(true);
+ }
+
+ public XLWorkbook SetUse1904DateSystem(Boolean value)
+ {
+ Use1904DateSystem = value;
+ return this;
+ }
+
+ public IXLWorksheet AddWorksheet(String sheetName)
+ {
+ return Worksheets.Add(sheetName);
+ }
+
+ public IXLWorksheet AddWorksheet(String sheetName, Int32 position)
+ {
+ return Worksheets.Add(sheetName, position);
+ }
+ public IXLWorksheet AddWorksheet(DataTable dataTable)
+ {
+ return Worksheets.Add(dataTable);
+ }
+ public void AddWorksheet(DataSet dataSet)
+ {
+ Worksheets.Add(dataSet);
+ }
+
+ public void AddWorksheet(IXLWorksheet worksheet)
+ {
+ worksheet.CopyTo(this, worksheet.Name);
+ }
+
+ public IXLWorksheet AddWorksheet(DataTable dataTable, String sheetName)
+ {
+ return Worksheets.Add(dataTable, sheetName);
+ }
+
+ private XLCalcEngine _calcEngine;
+ private XLCalcEngine CalcEngine
+ {
+ get { return _calcEngine ?? (_calcEngine = new XLCalcEngine(this)); }
+ }
+ public Object Evaluate(String expression)
+ {
+ return CalcEngine.Evaluate(expression);
+ }
+
+ private static XLCalcEngine _calcEngineExpr;
+ private SpreadsheetDocumentType _spreadsheetDocumentType;
+
+ private static XLCalcEngine CalcEngineExpr
+ {
+ get { return _calcEngineExpr ?? (_calcEngineExpr = new XLCalcEngine()); }
+ }
+ public static Object EvaluateExpr(String expression)
+ {
+ return CalcEngineExpr.Evaluate(expression);
+ }
+
+ public String Author { get; set; }
+
+ public Boolean LockStructure { get; set; }
+ public XLWorkbook SetLockStructure(Boolean value) { LockStructure = value; return this; }
+ public Boolean LockWindows { get; set; }
+ public XLWorkbook SetLockWindows(Boolean value) { LockWindows = value; return this; }
+ internal HexBinaryValue LockPassword { get; set; }
+
+ public void Protect(Boolean lockStructure, Boolean lockWindows, String workbookPassword)
+ {
+ if (workbookPassword != null)
+ {
+ var hashPassword = GetPasswordHash(workbookPassword);
+ if (LockPassword != null)
+ {
+ if (LockPassword != hashPassword)
+ {
+ throw new ArgumentException("Invalid password");
+ }
+ else
+ {
+ if (lockStructure || lockWindows)
+ {
+ throw new InvalidOperationException("The workbook is already protected");
+ }
+ else
+ {
+ //Unprotect workbook using password.
+ LockPassword = null;
+ }
+ }
+ }
+ else
+ {
+ if (lockStructure || lockWindows)
+ {
+ //Protect workbook using password.
+ LockPassword = hashPassword;
+ }
+ }
+ }
+ else
+ {
+ if (LockPassword != null)
+ {
+ throw new InvalidOperationException("The workbook is password protected");
+ }
+ }
+ LockStructure = lockStructure;
+ LockWindows = lockWindows;
+ }
+
+ public void Protect()
+ {
+ Protect(true);
+ }
+
+ public void Protect(string workbookPassword)
+ {
+ Protect(true, false, workbookPassword);
+ }
+
+ public void Protect(Boolean lockStructure)
+ {
+ Protect(lockStructure, false);
+ }
+
+ public void Protect(Boolean lockStructure, Boolean lockWindows)
+ {
+ Protect(lockStructure, lockWindows, null);
+ }
+
+ public void Unprotect()
+ {
+ Protect(false, false);
+ }
+
+ public void Unprotect(string workbookPassword)
+ {
+ Protect(false, false, workbookPassword);
+ }
+
+ private String GetPasswordHash(String password)
+ {
+ Int32 pLength = password.Length;
+ Int32 hash = 0;
+ if (pLength == 0) return String.Empty;
+
+ for (Int32 i = pLength - 1; i >= 0; i--)
+ {
+ hash ^= password[i];
+ hash = hash >> 14 & 0x01 | hash << 1 & 0x7fff;
+ }
+ hash ^= 0x8000 | 'N' << 8 | 'K';
+ hash ^= pLength;
+ return hash.ToString("X");
+ }
+ }
}
\ No newline at end of file
diff --git a/ClosedXML/Excel/XLWorkbook_Load.cs b/ClosedXML/Excel/XLWorkbook_Load.cs
index 8e34514..a23ab4e 100644
--- a/ClosedXML/Excel/XLWorkbook_Load.cs
+++ b/ClosedXML/Excel/XLWorkbook_Load.cs
@@ -1,2402 +1,2402 @@
-#region
-
-using ClosedXML.Utils;
-using DocumentFormat.OpenXml;
-using DocumentFormat.OpenXml.Packaging;
-using DocumentFormat.OpenXml.Spreadsheet;
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Xml.Linq;
-using Ap = DocumentFormat.OpenXml.ExtendedProperties;
-using Op = DocumentFormat.OpenXml.CustomProperties;
-using Xdr = DocumentFormat.OpenXml.Drawing.Spreadsheet;
-
-#endregion
-
-namespace ClosedXML.Excel
-{
- #region
-
- using Ap;
- using Drawings;
- using Op;
- using System.Drawing;
-
- #endregion
-
- public partial class XLWorkbook
- {
- private readonly Dictionary _colorList = new Dictionary();
-
- private void Load(String file)
- {
- LoadSheets(file);
- }
-
- private void Load(Stream stream)
- {
- LoadSheets(stream);
- }
-
- private void LoadSheets(String fileName)
- {
- using (var dSpreadsheet = SpreadsheetDocument.Open(fileName, false))
- LoadSpreadsheetDocument(dSpreadsheet);
- }
-
- private void LoadSheets(Stream stream)
- {
- using (var dSpreadsheet = SpreadsheetDocument.Open(stream, false))
- LoadSpreadsheetDocument(dSpreadsheet);
- }
-
- private void LoadSpreadsheetDocument(SpreadsheetDocument dSpreadsheet)
- {
- ShapeIdManager = new XLIdManager();
- SetProperties(dSpreadsheet);
- //var sharedStrings = dSpreadsheet.WorkbookPart.SharedStringTablePart.SharedStringTable.Elements();
- SharedStringItem[] sharedStrings = null;
- if (dSpreadsheet.WorkbookPart.GetPartsOfType().Count() > 0)
- {
- var shareStringPart = dSpreadsheet.WorkbookPart.GetPartsOfType().First();
- sharedStrings = shareStringPart.SharedStringTable.Elements().ToArray();
- }
-
- if (dSpreadsheet.CustomFilePropertiesPart != null)
- {
- foreach (var m in dSpreadsheet.CustomFilePropertiesPart.Properties.Elements())
- {
- String name = m.Name.Value;
- if (m.VTLPWSTR != null)
- CustomProperties.Add(name, m.VTLPWSTR.Text);
- else if (m.VTFileTime != null)
- {
- CustomProperties.Add(name,
- DateTime.ParseExact(m.VTFileTime.Text, "yyyy'-'MM'-'dd'T'HH':'mm':'ssK",
- CultureInfo.InvariantCulture));
- }
- else if (m.VTDouble != null)
- CustomProperties.Add(name, Double.Parse(m.VTDouble.Text, CultureInfo.InvariantCulture));
- else if (m.VTBool != null)
- CustomProperties.Add(name, m.VTBool.Text == "true");
- }
- }
-
- var wbProps = dSpreadsheet.WorkbookPart.Workbook.WorkbookProperties;
- Use1904DateSystem = wbProps != null && wbProps.Date1904 != null && wbProps.Date1904.Value;
-
- var wbProtection = dSpreadsheet.WorkbookPart.Workbook.WorkbookProtection;
- if (wbProtection != null)
- {
- if (wbProtection.LockStructure != null)
- LockStructure = wbProtection.LockStructure.Value;
- if (wbProtection.LockWindows != null)
- LockWindows = wbProtection.LockWindows.Value;
- if (wbProtection.WorkbookPassword != null)
- LockPassword = wbProtection.WorkbookPassword.Value;
- }
-
- var calculationProperties = dSpreadsheet.WorkbookPart.Workbook.CalculationProperties;
- if (calculationProperties != null)
- {
- var calculateMode = calculationProperties.CalculationMode;
- if (calculateMode != null)
- CalculateMode = calculateMode.Value.ToClosedXml();
-
- var calculationOnSave = calculationProperties.CalculationOnSave;
- if (calculationOnSave != null)
- CalculationOnSave = calculationOnSave.Value;
-
- var forceFullCalculation = calculationProperties.ForceFullCalculation;
- if (forceFullCalculation != null)
- ForceFullCalculation = forceFullCalculation.Value;
-
- var fullCalculationOnLoad = calculationProperties.FullCalculationOnLoad;
- if (fullCalculationOnLoad != null)
- FullCalculationOnLoad = fullCalculationOnLoad.Value;
-
- var fullPrecision = calculationProperties.FullPrecision;
- if (fullPrecision != null)
- FullPrecision = fullPrecision.Value;
-
- var referenceMode = calculationProperties.ReferenceMode;
- if (referenceMode != null)
- ReferenceStyle = referenceMode.Value.ToClosedXml();
- }
-
- var efp = dSpreadsheet.ExtendedFilePropertiesPart;
- if (efp != null && efp.Properties != null)
- {
- if (efp.Properties.Elements().Any())
- Properties.Company = efp.Properties.GetFirstChild().Text;
-
- if (efp.Properties.Elements().Any())
- Properties.Manager = efp.Properties.GetFirstChild().Text;
- }
-
- Stylesheet s = null;
- if (dSpreadsheet.WorkbookPart.WorkbookStylesPart != null &&
- dSpreadsheet.WorkbookPart.WorkbookStylesPart.Stylesheet != null)
- {
- s = dSpreadsheet.WorkbookPart.WorkbookStylesPart.Stylesheet;
- }
-
- NumberingFormats numberingFormats = s == null ? null : s.NumberingFormats;
- Fills fills = s == null ? null : s.Fills;
- Borders borders = s == null ? null : s.Borders;
- Fonts fonts = s == null ? null : s.Fonts;
- Int32 dfCount = 0;
- Dictionary differentialFormats;
- if (s != null && s.DifferentialFormats != null)
- differentialFormats = s.DifferentialFormats.Elements().ToDictionary(k => dfCount++);
- else
- differentialFormats = new Dictionary();
-
- var sheets = dSpreadsheet.WorkbookPart.Workbook.Sheets;
- Int32 position = 0;
- foreach (Sheet dSheet in sheets.OfType())
- {
- position++;
- var sharedFormulasR1C1 = new Dictionary();
-
- var wsPart = dSpreadsheet.WorkbookPart.GetPartById(dSheet.Id) as WorksheetPart;
-
- if (wsPart == null)
- {
- UnsupportedSheets.Add(new UnsupportedSheet { SheetId = dSheet.SheetId.Value, Position = position });
- continue;
- }
-
- var sheetName = dSheet.Name;
-
- var ws = (XLWorksheet)WorksheetsInternal.Add(sheetName, position);
- ws.RelId = dSheet.Id;
- ws.SheetId = (Int32)dSheet.SheetId.Value;
-
- if (dSheet.State != null)
- ws.Visibility = dSheet.State.Value.ToClosedXml();
-
- var styleList = new Dictionary();// {{0, ws.Style}};
- PageSetupProperties pageSetupProperties = null;
-
- using (var reader = OpenXmlReader.Create(wsPart))
- {
- Type[] ignoredElements = new Type[]
- {
- typeof(CustomSheetViews) // Custom sheet views contain its own auto filter data, and more, which should be ignored for now
- };
-
- while (reader.Read())
- {
- while (ignoredElements.Contains(reader.ElementType))
- reader.ReadNextSibling();
-
- if (reader.ElementType == typeof(SheetFormatProperties))
- {
- var sheetFormatProperties = (SheetFormatProperties)reader.LoadCurrentElement();
- if (sheetFormatProperties != null)
- {
- if (sheetFormatProperties.DefaultRowHeight != null)
- ws.RowHeight = sheetFormatProperties.DefaultRowHeight;
-
- ws.RowHeightChanged = (sheetFormatProperties.CustomHeight != null &&
- sheetFormatProperties.CustomHeight.Value);
-
- if (sheetFormatProperties.DefaultColumnWidth != null)
- {
- ws.ColumnWidth = sheetFormatProperties.DefaultColumnWidth;
- }
- }
- }
- else if (reader.ElementType == typeof(SheetViews))
- LoadSheetViews((SheetViews)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(MergeCells))
- {
- var mergedCells = (MergeCells)reader.LoadCurrentElement();
- if (mergedCells != null)
- {
- foreach (MergeCell mergeCell in mergedCells.Elements())
- ws.Range(mergeCell.Reference).Merge(false);
- }
- }
- else if (reader.ElementType == typeof(Columns))
- LoadColumns(s, numberingFormats, fills, borders, fonts, ws,
- (Columns)reader.LoadCurrentElement());
- else if (reader.ElementType == typeof(Row))
- {
- lastRow = 0;
- LoadRows(s, numberingFormats, fills, borders, fonts, ws, sharedStrings, sharedFormulasR1C1,
- styleList, (Row)reader.LoadCurrentElement());
- }
- else if (reader.ElementType == typeof(AutoFilter))
- LoadAutoFilter((AutoFilter)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(SheetProtection))
- LoadSheetProtection((SheetProtection)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(DataValidations))
- LoadDataValidations((DataValidations)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(ConditionalFormatting))
- LoadConditionalFormatting((ConditionalFormatting)reader.LoadCurrentElement(), ws, differentialFormats);
- else if (reader.ElementType == typeof(Hyperlinks))
- LoadHyperlinks((Hyperlinks)reader.LoadCurrentElement(), wsPart, ws);
- else if (reader.ElementType == typeof(PrintOptions))
- LoadPrintOptions((PrintOptions)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(PageMargins))
- LoadPageMargins((PageMargins)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(PageSetup))
- LoadPageSetup((PageSetup)reader.LoadCurrentElement(), ws, pageSetupProperties);
- else if (reader.ElementType == typeof(HeaderFooter))
- LoadHeaderFooter((HeaderFooter)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(SheetProperties))
- LoadSheetProperties((SheetProperties)reader.LoadCurrentElement(), ws, out pageSetupProperties);
- else if (reader.ElementType == typeof(RowBreaks))
- LoadRowBreaks((RowBreaks)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(ColumnBreaks))
- LoadColumnBreaks((ColumnBreaks)reader.LoadCurrentElement(), ws);
- else if (reader.ElementType == typeof(LegacyDrawing))
- ws.LegacyDrawingId = (reader.LoadCurrentElement() as LegacyDrawing).Id.Value;
- }
- reader.Close();
- }
-
- #region LoadTables
-
- foreach (TableDefinitionPart tablePart in wsPart.TableDefinitionParts)
- {
- var dTable = tablePart.Table;
- string reference = dTable.Reference.Value;
- XLTable xlTable = ws.Range(reference).CreateTable(dTable.Name, false) as XLTable;
- if (dTable.HeaderRowCount != null && dTable.HeaderRowCount == 0)
- {
- xlTable._showHeaderRow = false;
- //foreach (var tableColumn in dTable.TableColumns.Cast())
- xlTable.AddFields(dTable.TableColumns.Cast().Select(t => GetTableColumnName(t.Name.Value)));
- }
- else
- {
- xlTable.InitializeAutoFilter();
- }
-
- if (dTable.TotalsRowCount != null && dTable.TotalsRowCount.Value > 0)
- ((XLTable)xlTable)._showTotalsRow = true;
-
- if (dTable.TableStyleInfo != null)
- {
- if (dTable.TableStyleInfo.ShowFirstColumn != null)
- xlTable.EmphasizeFirstColumn = dTable.TableStyleInfo.ShowFirstColumn.Value;
- if (dTable.TableStyleInfo.ShowLastColumn != null)
- xlTable.EmphasizeLastColumn = dTable.TableStyleInfo.ShowLastColumn.Value;
- if (dTable.TableStyleInfo.ShowRowStripes != null)
- xlTable.ShowRowStripes = dTable.TableStyleInfo.ShowRowStripes.Value;
- if (dTable.TableStyleInfo.ShowColumnStripes != null)
- xlTable.ShowColumnStripes = dTable.TableStyleInfo.ShowColumnStripes.Value;
- if (dTable.TableStyleInfo.Name != null)
- {
- var theme = XLTableTheme.FromName(dTable.TableStyleInfo.Name.Value);
- if (theme != null)
- xlTable.Theme = theme;
- else
- xlTable.Theme = new XLTableTheme(dTable.TableStyleInfo.Name.Value);
- }
- else
- xlTable.Theme = XLTableTheme.None;
- }
-
- if (dTable.AutoFilter != null)
- {
- xlTable.ShowAutoFilter = true;
- LoadAutoFilterColumns(dTable.AutoFilter, (xlTable as XLTable).AutoFilter);
- }
- else
- xlTable.ShowAutoFilter = false;
-
- if (xlTable.ShowTotalsRow)
- {
- foreach (var tableColumn in dTable.TableColumns.Cast())
- {
- var tableColumnName = GetTableColumnName(tableColumn.Name.Value);
- if (tableColumn.TotalsRowFunction != null)
- xlTable.Field(tableColumnName).TotalsRowFunction =
- tableColumn.TotalsRowFunction.Value.ToClosedXml();
-
- if (tableColumn.TotalsRowFormula != null)
- xlTable.Field(tableColumnName).TotalsRowFormulaA1 =
- tableColumn.TotalsRowFormula.Text;
-
- if (tableColumn.TotalsRowLabel != null)
- xlTable.Field(tableColumnName).TotalsRowLabel = tableColumn.TotalsRowLabel.Value;
- }
- if (xlTable.AutoFilter != null)
- xlTable.AutoFilter.Range = xlTable.Worksheet.Range(
- xlTable.RangeAddress.FirstAddress.RowNumber, xlTable.RangeAddress.FirstAddress.ColumnNumber,
- xlTable.RangeAddress.LastAddress.RowNumber - 1, xlTable.RangeAddress.LastAddress.ColumnNumber);
- }
- else if (xlTable.AutoFilter != null)
- xlTable.AutoFilter.Range = xlTable.Worksheet.Range(xlTable.RangeAddress);
- }
-
- #endregion
-
- LoadDrawings(wsPart, ws);
-
- #region LoadComments
-
- if (wsPart.WorksheetCommentsPart != null)
- {
- var root = wsPart.WorksheetCommentsPart.Comments;
- var authors = root.GetFirstChild().ChildElements;
- var comments = root.GetFirstChild().ChildElements;
-
- // **** MAYBE FUTURE SHAPE SIZE SUPPORT
- XDocument xdoc = GetCommentVmlFile(wsPart);
-
- foreach (Comment c in comments)
- {
- // find cell by reference
- var cell = ws.Cell(c.Reference);
-
- XLComment xlComment = cell.Comment as XLComment;
- xlComment.Author = authors[(int)c.AuthorId.Value].InnerText;
- //xlComment.ShapeId = (Int32)c.ShapeId.Value;
- //ShapeIdManager.Add(xlComment.ShapeId);
-
- var runs = c.GetFirstChild().Elements();
- foreach (Run run in runs)
- {
- var runProperties = run.RunProperties;
- String text = run.Text.InnerText.FixNewLines();
- var rt = cell.Comment.AddText(text);
- LoadFont(runProperties, rt);
- }
-
- XElement shape = GetCommentShape(xdoc);
-
- LoadShapeProperties(xlComment, shape);
-
- var clientData = shape.Elements().First(e => e.Name.LocalName == "ClientData");
- LoadClientData(xlComment, clientData);
-
- var textBox = shape.Elements().First(e => e.Name.LocalName == "textbox");
- LoadTextBox(xlComment, textBox);
-
- var alt = shape.Attribute("alt");
- if (alt != null) xlComment.Style.Web.SetAlternateText(alt.Value);
-
- LoadColorsAndLines(xlComment, shape);
-
- //var insetmode = (string)shape.Attributes().First(a=> a.Name.LocalName == "insetmode");
- //xlComment.Style.Margins.Automatic = insetmode != null && insetmode.Equals("auto");
-
- shape.Remove();
- }
- }
-
- #endregion
- }
-
- var workbook = dSpreadsheet.WorkbookPart.Workbook;
-
- var bookViews = workbook.BookViews;
- if (bookViews != null && bookViews.Any())
- {
- var workbookView = bookViews.First() as WorkbookView;
- if (workbookView != null && workbookView.ActiveTab != null)
- {
- UnsupportedSheet unsupportedSheet =
- UnsupportedSheets.FirstOrDefault(us => us.Position == (Int32)(workbookView.ActiveTab.Value + 1));
- if (unsupportedSheet != null)
- unsupportedSheet.IsActive = true;
- else
- {
- Worksheet((Int32)(workbookView.ActiveTab.Value + 1)).SetTabActive();
- }
- }
- }
- LoadDefinedNames(workbook);
-
- #region Pivot tables
-
- // Delay loading of pivot tables until all sheets have been loaded
- foreach (Sheet dSheet in sheets.OfType())
- {
- var wsPart = dSpreadsheet.WorkbookPart.GetPartById(dSheet.Id) as WorksheetPart;
-
- if (wsPart != null)
- {
- var ws = (XLWorksheet)WorksheetsInternal.Worksheet(dSheet.Name);
-
- foreach (var pivotTablePart in wsPart.PivotTableParts)
- {
- var pivotTableCacheDefinitionPart = pivotTablePart.PivotTableCacheDefinitionPart;
- var pivotTableDefinition = pivotTablePart.PivotTableDefinition;
-
- var target = ws.FirstCell();
- if (pivotTableDefinition.Location != null && pivotTableDefinition.Location.Reference != null && pivotTableDefinition.Location.Reference.HasValue)
- {
- target = ws.Range(pivotTableDefinition.Location.Reference.Value).FirstCell();
- }
-
- IXLRange source = null;
- if (pivotTableCacheDefinitionPart.PivotCacheDefinition != null
- && pivotTableCacheDefinitionPart.PivotCacheDefinition.CacheSource != null
- && pivotTableCacheDefinitionPart.PivotCacheDefinition.CacheSource.WorksheetSource != null)
- {
- // TODO: Implement other sources besides worksheetSource (e.g. Table source?)
- // But for now assume names and references point directly to a range
- var wss = pivotTableCacheDefinitionPart.PivotCacheDefinition.CacheSource.WorksheetSource;
- string rangeAddress = string.Empty;
- if (wss.Name != null)
- rangeAddress = wss.Name.Value;
- else
- {
- var sourceSheet = wss.Sheet == null ? ws : this.Worksheet(wss.Sheet.Value);
- rangeAddress = sourceSheet.Range(wss.Reference.Value).RangeAddress.ToStringRelative(true);
- }
-
- source = this.Range(rangeAddress);
- if (source == null)
- continue;
- }
-
- if (target != null && source != null)
- {
- var pt = ws.PivotTables.AddNew(pivotTableDefinition.Name, target, source) as XLPivotTable;
- pt.RelId = wsPart.GetIdOfPart(pivotTablePart);
- pt.CacheDefinitionRelId = pivotTablePart.GetIdOfPart(pivotTableCacheDefinitionPart);
- pt.WorkbookCacheRelId = dSpreadsheet.WorkbookPart.GetIdOfPart(pivotTableCacheDefinitionPart);
-
- if (pivotTableDefinition.MergeItem != null) pt.MergeAndCenterWithLabels = pivotTableDefinition.MergeItem.Value;
- if (pivotTableDefinition.Indent != null) pt.RowLabelIndent = (int)pivotTableDefinition.Indent.Value;
- if (pivotTableDefinition.PageOverThenDown != null) pt.FilterAreaOrder = pivotTableDefinition.PageOverThenDown.Value ? XLFilterAreaOrder.OverThenDown : XLFilterAreaOrder.DownThenOver;
- if (pivotTableDefinition.PageWrap != null) pt.FilterFieldsPageWrap = (int)pivotTableDefinition.PageWrap.Value;
- if (pivotTableDefinition.UseAutoFormatting != null) pt.AutofitColumns = pivotTableDefinition.UseAutoFormatting.Value;
- if (pivotTableDefinition.PreserveFormatting != null) pt.PreserveCellFormatting = pivotTableDefinition.PreserveFormatting.Value;
- if (pivotTableDefinition.RowGrandTotals != null) pt.ShowGrandTotalsRows = pivotTableDefinition.RowGrandTotals.Value;
- if (pivotTableDefinition.ColumnGrandTotals != null) pt.ShowGrandTotalsColumns = pivotTableDefinition.ColumnGrandTotals.Value;
- if (pivotTableDefinition.SubtotalHiddenItems != null) pt.FilteredItemsInSubtotals = pivotTableDefinition.SubtotalHiddenItems.Value;
- if (pivotTableDefinition.MultipleFieldFilters != null) pt.AllowMultipleFilters = pivotTableDefinition.MultipleFieldFilters.Value;
- if (pivotTableDefinition.CustomListSort != null) pt.UseCustomListsForSorting = pivotTableDefinition.CustomListSort.Value;
- if (pivotTableDefinition.ShowDrill != null) pt.ShowExpandCollapseButtons = pivotTableDefinition.ShowDrill.Value;
- if (pivotTableDefinition.ShowDataTips != null) pt.ShowContextualTooltips = pivotTableDefinition.ShowDataTips.Value;
- if (pivotTableDefinition.ShowMemberPropertyTips != null) pt.ShowPropertiesInTooltips = pivotTableDefinition.ShowMemberPropertyTips.Value;
- if (pivotTableDefinition.ShowHeaders != null) pt.DisplayCaptionsAndDropdowns = pivotTableDefinition.ShowHeaders.Value;
- if (pivotTableDefinition.GridDropZones != null) pt.ClassicPivotTableLayout = pivotTableDefinition.GridDropZones.Value;
- if (pivotTableDefinition.ShowEmptyRow != null) pt.ShowEmptyItemsOnRows = pivotTableDefinition.ShowEmptyRow.Value;
- if (pivotTableDefinition.ShowEmptyColumn != null) pt.ShowEmptyItemsOnColumns = pivotTableDefinition.ShowEmptyColumn.Value;
- if (pivotTableDefinition.ShowItems != null) pt.DisplayItemLabels = pivotTableDefinition.ShowItems.Value;
- if (pivotTableDefinition.FieldListSortAscending != null) pt.SortFieldsAtoZ = pivotTableDefinition.FieldListSortAscending.Value;
- if (pivotTableDefinition.PrintDrill != null) pt.PrintExpandCollapsedButtons = pivotTableDefinition.PrintDrill.Value;
- if (pivotTableDefinition.ItemPrintTitles != null) pt.RepeatRowLabels = pivotTableDefinition.ItemPrintTitles.Value;
- if (pivotTableDefinition.FieldPrintTitles != null) pt.PrintTitles = pivotTableDefinition.FieldPrintTitles.Value;
- if (pivotTableDefinition.EnableDrill != null) pt.EnableShowDetails = pivotTableDefinition.EnableDrill.Value;
-
- if (pivotTableDefinition.ShowMissing != null && pivotTableDefinition.MissingCaption != null)
- pt.EmptyCellReplacement = pivotTableDefinition.MissingCaption.Value;
-
- if (pivotTableDefinition.ShowError != null && pivotTableDefinition.ErrorCaption != null)
- pt.ErrorValueReplacement = pivotTableDefinition.ErrorCaption.Value;
-
- // Row labels
- if (pivotTableDefinition.RowFields != null)
- {
- foreach (var rf in pivotTableDefinition.RowFields.Cast())
- {
- if (rf.Index < pivotTableDefinition.PivotFields.Count)
- {
- IXLPivotField pivotField = null;
- if (rf.Index.Value == -2)
- pivotField = pt.RowLabels.Add(XLConstants.PivotTableValuesSentinalLabel);
- else
- {
- var pf = pivotTableDefinition.PivotFields.ElementAt(rf.Index.Value) as PivotField;
- if (pf == null)
- continue;
-
- var cacheField = pivotTableCacheDefinitionPart.PivotCacheDefinition.CacheFields.ElementAt(rf.Index.Value) as CacheField;
- if (pf.Name != null)
- pivotField = pt.RowLabels.Add(pf.Name.Value);
- else if (cacheField.Name != null)
- pivotField = pt.RowLabels.Add(cacheField.Name.Value);
- else
- continue;
-
- if (pivotField != null)
- {
- var items = pf.Items.OfType- ().Where(i => i.Index != null && i.Index.HasValue);
- if (!items.Any(i => i.HideDetails == null || BooleanValue.ToBoolean(i.HideDetails)))
- pivotField.SetCollapsed();
- }
- }
- }
- }
- }
-
- // Column labels
- if (pivotTableDefinition.ColumnFields != null)
- {
- foreach (var cf in pivotTableDefinition.ColumnFields.Cast())
- {
- IXLPivotField pivotField = null;
- if (cf.Index.Value == -2)
- pivotField = pt.ColumnLabels.Add(XLConstants.PivotTableValuesSentinalLabel);
- else if (cf.Index < pivotTableDefinition.PivotFields.Count)
- {
- var pf = pivotTableDefinition.PivotFields.ElementAt(cf.Index.Value) as PivotField;
- if (pf == null)
- continue;
-
- var cacheField = pivotTableCacheDefinitionPart.PivotCacheDefinition.CacheFields.ElementAt(cf.Index.Value) as CacheField;
- if (pf.Name != null)
- pivotField = pt.ColumnLabels.Add(pf.Name.Value);
- else if (cacheField.Name != null)
- pivotField = pt.ColumnLabels.Add(cacheField.Name.Value);
- else
- continue;
-
- if (pivotField != null)
- {
- var items = pf.Items.OfType
- ().Where(i => i.Index != null && i.Index.HasValue);
- if (!items.Any(i => i.HideDetails == null || BooleanValue.ToBoolean(i.HideDetails)))
- pivotField.SetCollapsed();
- }
- }
- }
- }
-
- // Values
- if (pivotTableDefinition.DataFields != null)
- {
- foreach (var df in pivotTableDefinition.DataFields.Cast())
- {
- IXLPivotValue pivotValue = null;
- if ((int)df.Field.Value == -2)
- pivotValue = pt.Values.Add(XLConstants.PivotTableValuesSentinalLabel);
- else if (df.Field.Value < pivotTableDefinition.PivotFields.Count)
- {
- var pf = pivotTableDefinition.PivotFields.ElementAt((int)df.Field.Value) as PivotField;
- if (pf == null)
- continue;
-
- var cacheField = pivotTableCacheDefinitionPart.PivotCacheDefinition.CacheFields.ElementAt((int)df.Field.Value) as CacheField;
-
- if (pf.Name != null)
- pivotValue = pt.Values.Add(pf.Name.Value, df.Name.Value);
- else if (cacheField.Name != null)
- pivotValue = pt.Values.Add(cacheField.Name.Value, df.Name.Value);
- else
- continue;
-
- if (df.NumberFormatId != null) pivotValue.NumberFormat.SetNumberFormatId((int)df.NumberFormatId.Value);
- if (df.Subtotal != null) pivotValue = pivotValue.SetSummaryFormula(df.Subtotal.Value.ToClosedXml());
- if (df.ShowDataAs != null)
- {
- var calculation = pivotValue.Calculation;
- calculation = df.ShowDataAs.Value.ToClosedXml();
- pivotValue = pivotValue.SetCalculation(calculation);
- }
-
- if (df.BaseField != null)
- {
- var col = pt.SourceRange.Column(df.BaseField.Value + 1);
-
- var items = col.CellsUsed()
- .Select(c => c.Value)
- .Skip(1) // Skip header column
- .Distinct().ToList();
-
- pivotValue.BaseField = col.FirstCell().GetValue();
- if (df.BaseItem != null) pivotValue.BaseItem = items[(int)df.BaseItem.Value].ToString();
- }
- }
- }
- }
- }
- }
- }
- }
-
- #endregion
- }
-
- private void LoadDrawings(WorksheetPart wsPart, IXLWorksheet ws)
- {
- if (wsPart.DrawingsPart != null)
- {
- var drawingsPart = wsPart.DrawingsPart;
-
- foreach (var anchor in drawingsPart.WorksheetDrawing.ChildElements)
- {
- var imgId = GetImageRelIdFromAnchor(anchor);
-
- //If imgId is null, we're probably dealing with a TextBox (or another shape) instead of a picture
- if (imgId == null) continue;
-
- var imagePart = drawingsPart.GetPartById(imgId);
- using (var stream = imagePart.GetStream())
- {
- var vsdp = GetPropertiesFromAnchor(anchor);
-
- var picture = ws.AddPicture(stream, vsdp.Name) as XLPicture;
- picture.RelId = imgId;
-
- Xdr.ShapeProperties spPr = anchor.Descendants().First();
- picture.Placement = XLPicturePlacement.FreeFloating;
- picture.Width = ConvertFromEnglishMetricUnits(spPr.Transform2D.Extents.Cx, GraphicsUtils.Graphics.DpiX);
- picture.Height = ConvertFromEnglishMetricUnits(spPr.Transform2D.Extents.Cy, GraphicsUtils.Graphics.DpiY);
-
- if (anchor is Xdr.AbsoluteAnchor)
- {
- var absoluteAnchor = anchor as Xdr.AbsoluteAnchor;
- picture.MoveTo(
- ConvertFromEnglishMetricUnits(absoluteAnchor.Position.X.Value, GraphicsUtils.Graphics.DpiX),
- ConvertFromEnglishMetricUnits(absoluteAnchor.Position.Y.Value, GraphicsUtils.Graphics.DpiY)
- );
- }
- else if (anchor is Xdr.OneCellAnchor)
- {
- var oneCellAnchor = anchor as Xdr.OneCellAnchor;
- var from = LoadMarker(ws, oneCellAnchor.FromMarker);
- picture.MoveTo(from.Address, from.Offset);
- }
- else if (anchor is Xdr.TwoCellAnchor)
- {
- var twoCellAnchor = anchor as Xdr.TwoCellAnchor;
- var from = LoadMarker(ws, twoCellAnchor.FromMarker);
- var to = LoadMarker(ws, twoCellAnchor.ToMarker);
-
- if (twoCellAnchor.EditAs == null || !twoCellAnchor.EditAs.HasValue || twoCellAnchor.EditAs.Value == Xdr.EditAsValues.TwoCell)
- {
- picture.MoveTo(from.Address, from.Offset, to.Address, to.Offset);
- }
- else if (twoCellAnchor.EditAs.Value == Xdr.EditAsValues.Absolute)
- {
- var shapeProperties = twoCellAnchor.Descendants().FirstOrDefault();
- if (shapeProperties != null)
- {
- picture.MoveTo(
- ConvertFromEnglishMetricUnits(spPr.Transform2D.Offset.X, GraphicsUtils.Graphics.DpiX),
- ConvertFromEnglishMetricUnits(spPr.Transform2D.Offset.Y, GraphicsUtils.Graphics.DpiY)
- );
- }
- }
- else if (twoCellAnchor.EditAs.Value == Xdr.EditAsValues.OneCell)
- {
- picture.MoveTo(from.Address, from.Offset);
- }
- }
- }
- }
- }
- }
-
- private static Int32 ConvertFromEnglishMetricUnits(long emu, float resolution)
- {
- return Convert.ToInt32(emu * resolution / 914400);
- }
-
- private static IXLMarker LoadMarker(IXLWorksheet ws, Xdr.MarkerType marker)
- {
- return new XLMarker(
- ws.Cell(Convert.ToInt32(marker.RowId.InnerText) + 1, Convert.ToInt32(marker.ColumnId.InnerText) + 1).Address,
- new Point(
- ConvertFromEnglishMetricUnits(Convert.ToInt32(marker.ColumnOffset.InnerText), GraphicsUtils.Graphics.DpiX),
- ConvertFromEnglishMetricUnits(Convert.ToInt32(marker.RowOffset.InnerText), GraphicsUtils.Graphics.DpiY)
- )
- );
- }
-
- #region Comment Helpers
-
- private XDocument GetCommentVmlFile(WorksheetPart wsPart)
- {
- XDocument xdoc = null;
-
- foreach (var vmlPart in wsPart.VmlDrawingParts)
- {
- xdoc = XDocumentExtensions.Load(vmlPart.GetStream(FileMode.Open));
-
- //Probe for comments
- if (xdoc.Root == null) continue;
- var shape = GetCommentShape(xdoc);
- if (shape != null) break;
- }
-
- if (xdoc == null) throw new Exception("Could not load comments file");
- return xdoc;
- }
-
- private static XElement GetCommentShape(XDocument xdoc)
- {
- var xml = xdoc.Root.Element("xml");
-
- XElement shape;
- if (xml != null)
- shape =
- xml.Elements().FirstOrDefault(e => (string)e.Attribute("type") == XLConstants.Comment.ShapeTypeId);
- else
- shape = xdoc.Root.Elements().FirstOrDefault(e =>
- (string)e.Attribute("type") ==
- XLConstants.Comment.ShapeTypeId ||
- (string)e.Attribute("type") ==
- XLConstants.Comment.AlternateShapeTypeId);
- return shape;
- }
-
- #endregion
-
- private String GetTableColumnName(string name)
- {
- return name.Replace("_x000a_", Environment.NewLine).Replace("_x005f_x000a_", "_x000a_");
- }
-
- // This may be part of XLHelper or XLColor
- // Leaving it here for now. Can't decide what to call it and where to put it.
- private XLColor ExtractColor(String color)
- {
- if (color.IndexOf("[") >= 0)
- {
- int start = color.IndexOf("[") + 1;
- int end = color.IndexOf("]", start);
- return XLColor.FromIndex(Int32.Parse(color.Substring(start, end - start)));
- }
- else
- {
- return XLColor.FromHtml(color);
- }
- }
-
- private void LoadColorsAndLines(IXLDrawing drawing, XElement shape)
- {
- var strokeColor = shape.Attribute("strokecolor");
- if (strokeColor != null) drawing.Style.ColorsAndLines.LineColor = ExtractColor(strokeColor.Value);
-
- var strokeWeight = shape.Attribute("strokeweight");
- if (strokeWeight != null)
- drawing.Style.ColorsAndLines.LineWeight = GetPtValue(strokeWeight.Value);
-
- var fillColor = shape.Attribute("fillcolor");
- if (fillColor != null && !fillColor.Value.ToLower().Contains("infobackground")) drawing.Style.ColorsAndLines.FillColor = ExtractColor(fillColor.Value);
-
- var fill = shape.Elements().FirstOrDefault(e => e.Name.LocalName == "fill");
- if (fill != null)
- {
- var opacity = fill.Attribute("opacity");
- if (opacity != null)
- {
- String opacityVal = opacity.Value;
- if (opacityVal.EndsWith("f"))
- drawing.Style.ColorsAndLines.FillTransparency =
- Double.Parse(opacityVal.Substring(0, opacityVal.Length - 1), CultureInfo.InvariantCulture) / 65536.0;
- else
- drawing.Style.ColorsAndLines.FillTransparency = Double.Parse(opacityVal, CultureInfo.InvariantCulture);
- }
- }
-
- var stroke = shape.Elements().FirstOrDefault(e => e.Name.LocalName == "stroke");
- if (stroke != null)
- {
- var opacity = stroke.Attribute("opacity");
- if (opacity != null)
- {
- String opacityVal = opacity.Value;
- if (opacityVal.EndsWith("f"))
- drawing.Style.ColorsAndLines.LineTransparency =
- Double.Parse(opacityVal.Substring(0, opacityVal.Length - 1), CultureInfo.InvariantCulture) / 65536.0;
- else
- drawing.Style.ColorsAndLines.LineTransparency = Double.Parse(opacityVal, CultureInfo.InvariantCulture);
- }
-
- var dashStyle = stroke.Attribute("dashstyle");
- if (dashStyle != null)
- {
- String dashStyleVal = dashStyle.Value.ToLower();
- if (dashStyleVal == "1 1" || dashStyleVal == "shortdot")
- {
- var endCap = stroke.Attribute("endcap");
- if (endCap != null && endCap.Value == "round")
- drawing.Style.ColorsAndLines.LineDash = XLDashStyle.RoundDot;
- else
- drawing.Style.ColorsAndLines.LineDash = XLDashStyle.SquareDot;
- }
- else
- {
- switch (dashStyleVal)
- {
- case "dash": drawing.Style.ColorsAndLines.LineDash = XLDashStyle.Dash; break;
- case "dashdot": drawing.Style.ColorsAndLines.LineDash = XLDashStyle.DashDot; break;
- case "longdash": drawing.Style.ColorsAndLines.LineDash = XLDashStyle.LongDash; break;
- case "longdashdot": drawing.Style.ColorsAndLines.LineDash = XLDashStyle.LongDashDot; break;
- case "longdashdotdot": drawing.Style.ColorsAndLines.LineDash = XLDashStyle.LongDashDotDot; break;
- }
- }
- }
-
- var lineStyle = stroke.Attribute("linestyle");
- if (lineStyle != null)
- {
- String lineStyleVal = lineStyle.Value.ToLower();
- switch (lineStyleVal)
- {
- case "single": drawing.Style.ColorsAndLines.LineStyle = XLLineStyle.Single; break;
- case "thickbetweenthin": drawing.Style.ColorsAndLines.LineStyle = XLLineStyle.ThickBetweenThin; break;
- case "thickthin": drawing.Style.ColorsAndLines.LineStyle = XLLineStyle.ThickThin; break;
- case "thinthick": drawing.Style.ColorsAndLines.LineStyle = XLLineStyle.ThinThick; break;
- case "thinthin": drawing.Style.ColorsAndLines.LineStyle = XLLineStyle.ThinThin; break;
- }
- }
- }
- }
-
- private void LoadTextBox(IXLDrawing xlDrawing, XElement textBox)
- {
- var attStyle = textBox.Attribute("style");
- if (attStyle != null) LoadTextBoxStyle(xlDrawing, attStyle);
-
- var attInset = textBox.Attribute("inset");
- if (attInset != null) LoadTextBoxInset(xlDrawing, attInset);
- }
-
- private void LoadTextBoxInset(IXLDrawing xlDrawing, XAttribute attInset)
- {
- var split = attInset.Value.Split(',');
- xlDrawing.Style.Margins.Left = GetInsetValue(split[0]);
- xlDrawing.Style.Margins.Top = GetInsetValue(split[1]);
- xlDrawing.Style.Margins.Right = GetInsetValue(split[2]);
- xlDrawing.Style.Margins.Bottom = GetInsetValue(split[3]);
- }
-
- private double GetInsetValue(string value)
- {
- String v = value.Trim();
- if (v.EndsWith("pt"))
- return Double.Parse(v.Substring(0, v.Length - 2), CultureInfo.InvariantCulture) / 72.0;
- else
- return Double.Parse(v.Substring(0, v.Length - 2), CultureInfo.InvariantCulture);
- }
-
- private static void LoadTextBoxStyle(IXLDrawing xlDrawing, XAttribute attStyle)
- {
- var style = attStyle.Value;
- var attributes = style.Split(';');
- foreach (String pair in attributes)
- {
- var split = pair.Split(':');
- if (split.Length != 2) continue;
-
- var attribute = split[0].Trim().ToLower();
- var value = split[1].Trim();
- Boolean isVertical = false;
- switch (attribute)
- {
- case "mso-fit-shape-to-text": xlDrawing.Style.Size.SetAutomaticSize(value.Equals("t")); break;
- case "mso-layout-flow-alt":
- if (value.Equals("bottom-to-top")) xlDrawing.Style.Alignment.SetOrientation(XLDrawingTextOrientation.BottomToTop);
- else if (value.Equals("top-to-bottom")) xlDrawing.Style.Alignment.SetOrientation(XLDrawingTextOrientation.Vertical);
- break;
-
- case "layout-flow": isVertical = value.Equals("vertical"); break;
- case "mso-direction-alt": if (value == "auto") xlDrawing.Style.Alignment.Direction = XLDrawingTextDirection.Context; break;
- case "direction": if (value == "RTL") xlDrawing.Style.Alignment.Direction = XLDrawingTextDirection.RightToLeft; break;
- }
- if (isVertical && xlDrawing.Style.Alignment.Orientation == XLDrawingTextOrientation.LeftToRight)
- xlDrawing.Style.Alignment.Orientation = XLDrawingTextOrientation.TopToBottom;
- }
- }
-
- private void LoadClientData(IXLDrawing drawing, XElement clientData)
- {
- var anchor = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "Anchor");
- if (anchor != null) LoadClientDataAnchor(drawing, anchor);
-
- LoadDrawingPositioning(drawing, clientData);
- LoadDrawingProtection(drawing, clientData);
-
- var visible = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "Visible");
- drawing.Visible = visible != null && visible.Value.ToLower().StartsWith("t");
-
- LoadDrawingHAlignment(drawing, clientData);
- LoadDrawingVAlignment(drawing, clientData);
- }
-
- private void LoadDrawingHAlignment(IXLDrawing drawing, XElement clientData)
- {
- var textHAlign = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "TextHAlign");
- if (textHAlign != null)
- drawing.Style.Alignment.Horizontal = (XLDrawingHorizontalAlignment)Enum.Parse(typeof(XLDrawingHorizontalAlignment), textHAlign.Value.ToProper());
- }
-
- private void LoadDrawingVAlignment(IXLDrawing drawing, XElement clientData)
- {
- var textVAlign = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "TextVAlign");
- if (textVAlign != null)
- drawing.Style.Alignment.Vertical = (XLDrawingVerticalAlignment)Enum.Parse(typeof(XLDrawingVerticalAlignment), textVAlign.Value.ToProper());
- }
-
- private void LoadDrawingProtection(IXLDrawing drawing, XElement clientData)
- {
- var lockedElement = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "Locked");
- var lockTextElement = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "LockText");
- Boolean locked = lockedElement != null && lockedElement.Value.ToLower() == "true";
- Boolean lockText = lockTextElement != null && lockTextElement.Value.ToLower() == "true";
- drawing.Style.Protection.Locked = locked;
- drawing.Style.Protection.LockText = lockText;
- }
-
- private static void LoadDrawingPositioning(IXLDrawing drawing, XElement clientData)
- {
- var moveWithCellsElement = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "MoveWithCells");
- var sizeWithCellsElement = clientData.Elements().FirstOrDefault(e => e.Name.LocalName == "SizeWithCells");
- Boolean moveWithCells = !(moveWithCellsElement != null && moveWithCellsElement.Value.ToLower() == "true");
- Boolean sizeWithCells = !(sizeWithCellsElement != null && sizeWithCellsElement.Value.ToLower() == "true");
- if (moveWithCells && !sizeWithCells)
- drawing.Style.Properties.Positioning = XLDrawingAnchor.MoveWithCells;
- else if (moveWithCells && sizeWithCells)
- drawing.Style.Properties.Positioning = XLDrawingAnchor.MoveAndSizeWithCells;
- else
- drawing.Style.Properties.Positioning = XLDrawingAnchor.Absolute;
- }
-
- private static void LoadClientDataAnchor(IXLDrawing drawing, XElement anchor)
- {
- var location = anchor.Value.Split(',');
- drawing.Position.Column = int.Parse(location[0]) + 1;
- drawing.Position.ColumnOffset = Double.Parse(location[1], CultureInfo.InvariantCulture) / 7.2;
- drawing.Position.Row = int.Parse(location[2]) + 1;
- drawing.Position.RowOffset = Double.Parse(location[3], CultureInfo.InvariantCulture);
- }
-
- private void LoadShapeProperties(IXLDrawing xlDrawing, XElement shape)
- {
- var attStyle = shape.Attribute("style");
- if (attStyle == null) return;
-
- var style = attStyle.Value;
- var attributes = style.Split(';');
- foreach (String pair in attributes)
- {
- var split = pair.Split(':');
- if (split.Length != 2) continue;
-
- var attribute = split[0].Trim().ToLower();
- var value = split[1].Trim();
-
- switch (attribute)
- {
- case "visibility": xlDrawing.Visible = value.ToLower().Equals("visible"); break;
- case "width": xlDrawing.Style.Size.Width = GetPtValue(value) / 7.5; break;
- case "height": xlDrawing.Style.Size.Height = GetPtValue(value); break;
- case "z-index": xlDrawing.ZOrder = Int32.Parse(value); break;
- }
- }
- }
-
- private readonly Dictionary knownUnits = new Dictionary
- {
- {"pt", 1.0},
- {"in", 72.0},
- {"mm", 72.0/25.4}
- };
-
- private double GetPtValue(string value)
- {
- var knownUnit = knownUnits.FirstOrDefault(ku => value.Contains(ku.Key));
-
- if (knownUnit.Key == null)
- return Double.Parse(value);
-
- return Double.Parse(value.Replace(knownUnit.Key, String.Empty), CultureInfo.InvariantCulture) * knownUnit.Value;
- }
-
- private void LoadDefinedNames(Workbook workbook)
- {
- if (workbook.DefinedNames == null) return;
-
- foreach (var definedName in workbook.DefinedNames.OfType())
- {
- var name = definedName.Name;
- var visible = true;
- if (definedName.Hidden != null) visible = !BooleanValue.ToBoolean(definedName.Hidden);
- if (name == "_xlnm.Print_Area")
- {
- var fixedNames = validateDefinedNames(definedName.Text.Split(','));
- foreach (string area in fixedNames)
- {
- if (area.Contains("["))
- {
- var ws = Worksheets.FirstOrDefault(w => (w as XLWorksheet).SheetId == definedName.LocalSheetId + 1);
- if (ws != null)
- {
- ws.PageSetup.PrintAreas.Add(area);
- }
- }
- else
- {
- string sheetName, sheetArea;
- ParseReference(area, out sheetName, out sheetArea);
- if (!(sheetArea.Equals("#REF") || sheetArea.EndsWith("#REF!") || sheetArea.Length == 0))
- WorksheetsInternal.Worksheet(sheetName).PageSetup.PrintAreas.Add(sheetArea);
- }
- }
- }
- else if (name == "_xlnm.Print_Titles")
- {
- LoadPrintTitles(definedName);
- }
- else
- {
- string text = definedName.Text;
-
- if (!(text.Equals("#REF") || text.EndsWith("#REF!")))
- {
- var localSheetId = definedName.LocalSheetId;
- var comment = definedName.Comment;
- if (localSheetId == null)
- {
- if (!NamedRanges.Any(nr => nr.Name == name))
- (NamedRanges as XLNamedRanges).Add(name, text, comment, true).Visible = visible;
- }
- else
- {
- if (!Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges.Any(nr => nr.Name == name))
- Worksheet(Int32.Parse(localSheetId) + 1).NamedRanges.Add(name, text, comment).Visible = visible;
- }
- }
- }
- }
- }
-
- private static Regex definedNameRegex = new Regex(@"\A'.*'!.*\z", RegexOptions.Compiled);
-
- private IEnumerable validateDefinedNames(IEnumerable definedNames)
- {
- var fixedNames = new List();
- var sb = new StringBuilder();
- foreach (string testName in definedNames)
- {
- if (sb.Length > 0)
- sb.Append(',');
-
- sb.Append(testName);
-
- Match matchedValidPattern = definedNameRegex.Match(sb.ToString());
- if (matchedValidPattern.Success)
- {
- yield return sb.ToString();
- sb = new StringBuilder();
- }
- }
-
- if (sb.Length > 0)
- yield return sb.ToString();
- }
-
- private void LoadPrintTitles(DefinedName definedName)
- {
- var areas = validateDefinedNames(definedName.Text.Split(','));
- foreach (var item in areas)
- {
- if (this.Range(item) != null)
- SetColumnsOrRowsToRepeat(item);
- }
- }
-
- private void SetColumnsOrRowsToRepeat(string area)
- {
- string sheetName, sheetArea;
- ParseReference(area, out sheetName, out sheetArea);
- if (sheetArea.Equals("#REF")) return;
- if (IsColReference(sheetArea))
- WorksheetsInternal.Worksheet(sheetName).PageSetup.SetColumnsToRepeatAtLeft(sheetArea);
- if (IsRowReference(sheetArea))
- WorksheetsInternal.Worksheet(sheetName).PageSetup.SetRowsToRepeatAtTop(sheetArea);
- }
-
- // either $A:$X => true or $1:$99 => false
- private static bool IsColReference(string sheetArea)
- {
- char c = sheetArea[0] == '$' ? sheetArea[1] : sheetArea[0];
- return char.IsLetter(c);
- }
-
- private static bool IsRowReference(string sheetArea)
- {
- char c = sheetArea[0] == '$' ? sheetArea[1] : sheetArea[0];
- return char.IsNumber(c);
- }
-
- private static void ParseReference(string item, out string sheetName, out string sheetArea)
- {
- var sections = item.Trim().Split('!');
- if (sections.Count() == 1)
- {
- sheetName = string.Empty;
- sheetArea = item;
- }
- else
- {
- sheetName = sections[0].Replace("\'", "");
- sheetArea = sections[1];
- }
- }
-
- private Int32 lastCell;
-
- private void LoadCells(SharedStringItem[] sharedStrings, Stylesheet s, NumberingFormats numberingFormats,
- Fills fills, Borders borders, Fonts fonts, Dictionary sharedFormulasR1C1,
- XLWorksheet ws, Dictionary styleList, Cell cell, Int32 rowIndex)
- {
- Int32 styleIndex = cell.StyleIndex != null ? Int32.Parse(cell.StyleIndex.InnerText) : 0;
-
- String cellReference = cell.CellReference == null
- ? XLHelper.GetColumnLetterFromNumber(++lastCell) + rowIndex
- : cell.CellReference.Value;
- var xlCell = ws.CellFast(cellReference);
-
- if (styleList.ContainsKey(styleIndex))
- {
- xlCell.Style = styleList[styleIndex];
- }
- else
- {
- ApplyStyle(xlCell, styleIndex, s, fills, borders, fonts, numberingFormats);
- styleList.Add(styleIndex, xlCell.Style);
- }
-
- if (cell.CellFormula != null && cell.CellFormula.SharedIndex != null && cell.CellFormula.Reference != null)
- {
- String formula;
- if (cell.CellFormula.FormulaType != null && cell.CellFormula.FormulaType == CellFormulaValues.Array)
- formula = "{" + cell.CellFormula.Text + "}";
- else
- formula = cell.CellFormula.Text;
-
- if (cell.CellFormula.Reference != null)
- xlCell.FormulaReference = ws.Range(cell.CellFormula.Reference.Value).RangeAddress;
-
- xlCell.FormulaA1 = formula;
- sharedFormulasR1C1.Add(cell.CellFormula.SharedIndex.Value, xlCell.FormulaR1C1);
-
- if (cell.CellValue != null)
- xlCell.ValueCached = cell.CellValue.Text;
- }
- else if (cell.CellFormula != null)
- {
- if (cell.CellFormula.SharedIndex != null)
- xlCell.FormulaR1C1 = sharedFormulasR1C1[cell.CellFormula.SharedIndex.Value];
- else
- {
- String formula;
- if (cell.CellFormula.FormulaType != null && cell.CellFormula.FormulaType == CellFormulaValues.Array)
- formula = "{" + cell.CellFormula.Text + "}";
- else
- formula = cell.CellFormula.Text;
-
- xlCell.FormulaA1 = formula;
- }
-
- if (cell.CellFormula.Reference != null)
- xlCell.FormulaReference = ws.Range(cell.CellFormula.Reference.Value).RangeAddress;
-
- if (cell.CellValue != null)
- xlCell.ValueCached = cell.CellValue.Text;
- }
- else if (cell.DataType != null)
- {
- if (cell.DataType == CellValues.InlineString)
- {
- if (cell.InlineString != null)
- {
- if (cell.InlineString.Text != null)
- xlCell._cellValue = cell.InlineString.Text.Text.FixNewLines();
- else
- ParseCellValue(cell.InlineString, xlCell);
- }
- else
- xlCell._cellValue = String.Empty;
-
- xlCell._dataType = XLCellValues.Text;
- xlCell.ShareString = false;
- }
- else if (cell.DataType == CellValues.SharedString)
- {
- if (cell.CellValue != null && !XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
- {
- var sharedString = sharedStrings[Int32.Parse(cell.CellValue.Text, XLHelper.NumberStyle, XLHelper.ParseCulture)];
- ParseCellValue(sharedString, xlCell);
- }
- else
- xlCell._cellValue = String.Empty;
-
- xlCell._dataType = XLCellValues.Text;
- }
- else if (cell.DataType == CellValues.Date)
- {
- if (cell.CellValue != null && !XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
- xlCell._cellValue = Double.Parse(cell.CellValue.Text, XLHelper.NumberStyle, XLHelper.ParseCulture).ToInvariantString();
- xlCell._dataType = XLCellValues.DateTime;
- }
- else if (cell.DataType == CellValues.Boolean)
- {
- if (cell.CellValue != null)
- xlCell._cellValue = cell.CellValue.Text;
- xlCell._dataType = XLCellValues.Boolean;
- }
- else if (cell.DataType == CellValues.Number)
- {
- if (cell.CellValue != null && !XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
- xlCell._cellValue = Double.Parse(cell.CellValue.Text, XLHelper.NumberStyle, XLHelper.ParseCulture).ToInvariantString();
-
- if (s == null)
- xlCell._dataType = XLCellValues.Number;
- else
- xlCell.DataType = GetDataTypeFromCell(xlCell.Style.NumberFormat);
- }
- }
- else if (cell.CellValue != null)
- {
- if (s == null)
- {
- xlCell._dataType = XLCellValues.Number;
- }
- else
- {
- var numberFormatId = ((CellFormat)(s.CellFormats).ElementAt(styleIndex)).NumberFormatId;
- if (!XLHelper.IsNullOrWhiteSpace(cell.CellValue.Text))
- xlCell._cellValue = Double.Parse(cell.CellValue.Text, CultureInfo.InvariantCulture).ToInvariantString();
-
- if (s.NumberingFormats != null &&
- s.NumberingFormats.Any(nf => ((NumberingFormat)nf).NumberFormatId.Value == numberFormatId))
- {
- xlCell.Style.NumberFormat.Format =
- ((NumberingFormat)s.NumberingFormats
- .First(
- nf => ((NumberingFormat)nf).NumberFormatId.Value == numberFormatId)
- ).FormatCode.Value;
- }
- else
- xlCell.Style.NumberFormat.NumberFormatId = Int32.Parse(numberFormatId);
-
- xlCell.DataType = GetDataTypeFromCell(xlCell.Style.NumberFormat);
- }
- }
- }
-
- ///
- /// Parses the cell value for normal or rich text
- /// Input element should either be a shared string or inline string
- ///
- /// The element (either a shared string or inline string)
- /// The cell.
- private void ParseCellValue(RstType element, XLCell xlCell)
- {
- var runs = element.Elements();
- var phoneticRuns = element.Elements();
- var phoneticProperties = element.Elements();
- Boolean hasRuns = false;
- foreach (Run run in runs)
- {
- var runProperties = run.RunProperties;
- String text = run.Text.InnerText.FixNewLines();
-
- if (runProperties == null)
- xlCell.RichText.AddText(text, xlCell.Style.Font);
- else
- {
- var rt = xlCell.RichText.AddText(text);
- LoadFont(runProperties, rt);
- }
- if (!hasRuns)
- hasRuns = true;
- }
-
- if (!hasRuns)
- xlCell._cellValue = XmlEncoder.DecodeString(element.Text.InnerText);
-
- #region Load PhoneticProperties
-
- var pp = phoneticProperties.FirstOrDefault();
- if (pp != null)
- {
- if (pp.Alignment != null)
- xlCell.RichText.Phonetics.Alignment = pp.Alignment.Value.ToClosedXml();
- if (pp.Type != null)
- xlCell.RichText.Phonetics.Type = pp.Type.Value.ToClosedXml();
-
- LoadFont(pp, xlCell.RichText.Phonetics);
- }
-
- #endregion
-
- #region Load Phonetic Runs
-
- foreach (PhoneticRun pr in phoneticRuns)
- {
- xlCell.RichText.Phonetics.Add(pr.Text.InnerText.FixNewLines(), (Int32)pr.BaseTextStartIndex.Value,
- (Int32)pr.EndingBaseIndex.Value);
- }
-
- #endregion
- }
-
- private void LoadNumberFormat(NumberingFormat nfSource, IXLNumberFormat nf)
- {
- if (nfSource == null) return;
-
- if (nfSource.FormatCode != null)
- nf.Format = nfSource.FormatCode.Value;
- //if (nfSource.NumberFormatId != null)
- // nf.NumberFormatId = (Int32)nfSource.NumberFormatId.Value;
- }
-
- private void LoadBorder(Border borderSource, IXLBorder border)
- {
- if (borderSource == null) return;
-
- LoadBorderValues(borderSource.DiagonalBorder, border.SetDiagonalBorder, border.SetDiagonalBorderColor);
-
- if (borderSource.DiagonalUp != null)
- border.DiagonalUp = borderSource.DiagonalUp.Value;
- if (borderSource.DiagonalDown != null)
- border.DiagonalDown = borderSource.DiagonalDown.Value;
-
- LoadBorderValues(borderSource.LeftBorder, border.SetLeftBorder, border.SetLeftBorderColor);
- LoadBorderValues(borderSource.RightBorder, border.SetRightBorder, border.SetRightBorderColor);
- LoadBorderValues(borderSource.TopBorder, border.SetTopBorder, border.SetTopBorderColor);
- LoadBorderValues(borderSource.BottomBorder, border.SetBottomBorder, border.SetBottomBorderColor);
- }
-
- private void LoadBorderValues(BorderPropertiesType source, Func setBorder, Func setColor)
- {
- if (source != null)
- {
- if (source.Style != null)
- setBorder(source.Style.Value.ToClosedXml());
- if (source.Color != null)
- setColor(GetColor(source.Color));
- }
- }
-
- private void LoadFill(Fill fillSource, IXLFill fill)
- {
- if (fillSource == null) return;
-
- if (fillSource.PatternFill != null)
- {
- if (fillSource.PatternFill.PatternType != null)
- fill.PatternType = fillSource.PatternFill.PatternType.Value.ToClosedXml();
- else
- fill.PatternType = XLFillPatternValues.Solid;
-
- if (fillSource.PatternFill.ForegroundColor != null)
- fill.PatternColor = GetColor(fillSource.PatternFill.ForegroundColor);
- if (fillSource.PatternFill.BackgroundColor != null)
- fill.PatternBackgroundColor = GetColor(fillSource.PatternFill.BackgroundColor);
- }
- }
-
- private void LoadFont(OpenXmlElement fontSource, IXLFontBase fontBase)
- {
- if (fontSource == null) return;
-
- fontBase.Bold = GetBoolean(fontSource.Elements().FirstOrDefault());
- var fontColor = GetColor(fontSource.Elements().FirstOrDefault());
- if (fontColor.HasValue)
- fontBase.FontColor = fontColor;
-
- var fontFamilyNumbering =
- fontSource.Elements().FirstOrDefault();
- if (fontFamilyNumbering != null && fontFamilyNumbering.Val != null)
- fontBase.FontFamilyNumbering =
- (XLFontFamilyNumberingValues)Int32.Parse(fontFamilyNumbering.Val.ToString());
- var runFont = fontSource.Elements().FirstOrDefault();
- if (runFont != null)
- {
- if (runFont.Val != null)
- fontBase.FontName = runFont.Val;
- }
- var fontSize = fontSource.Elements().FirstOrDefault();
- if (fontSize != null)
- {
- if ((fontSize).Val != null)
- fontBase.FontSize = (fontSize).Val;
- }
-
- fontBase.Italic = GetBoolean(fontSource.Elements().FirstOrDefault());
- fontBase.Shadow = GetBoolean(fontSource.Elements().FirstOrDefault());
- fontBase.Strikethrough = GetBoolean(fontSource.Elements
().FirstOrDefault());
-
- var underline = fontSource.Elements().FirstOrDefault();
- if (underline != null)
- {
- fontBase.Underline = underline.Val != null ? underline.Val.Value.ToClosedXml() : XLFontUnderlineValues.Single;
- }
-
- var verticalTextAlignment = fontSource.Elements().FirstOrDefault();
-
- if (verticalTextAlignment == null) return;
-
- fontBase.VerticalAlignment = verticalTextAlignment.Val != null ? verticalTextAlignment.Val.Value.ToClosedXml() : XLFontVerticalTextAlignmentValues.Baseline;
- }
-
- private Int32 lastRow;
-
- private void LoadRows(Stylesheet s, NumberingFormats numberingFormats, Fills fills, Borders borders, Fonts fonts,
- XLWorksheet ws, SharedStringItem[] sharedStrings,
- Dictionary sharedFormulasR1C1, Dictionary styleList,
- Row row)
- {
- Int32 rowIndex = row.RowIndex == null ? ++lastRow : (Int32)row.RowIndex.Value;
- var xlRow = ws.Row(rowIndex, false);
-
- if (row.Height != null)
- xlRow.Height = row.Height;
- else
- {
- xlRow.Loading = true;
- xlRow.Height = ws.RowHeight;
- xlRow.Loading = false;
- }
-
- if (row.Hidden != null && row.Hidden)
- xlRow.Hide();
-
- if (row.Collapsed != null && row.Collapsed)
- xlRow.Collapsed = true;
-
- if (row.OutlineLevel != null && row.OutlineLevel > 0)
- xlRow.OutlineLevel = row.OutlineLevel;
-
- if (row.CustomFormat != null)
- {
- Int32 styleIndex = row.StyleIndex != null ? Int32.Parse(row.StyleIndex.InnerText) : -1;
- if (styleIndex > 0)
- {
- ApplyStyle(xlRow, styleIndex, s, fills, borders, fonts, numberingFormats);
- }
- else
- {
- xlRow.Style = DefaultStyle;
- }
- }
-
- lastCell = 0;
- foreach (Cell cell in row.Elements| ())
- LoadCells(sharedStrings, s, numberingFormats, fills, borders, fonts, sharedFormulasR1C1, ws, styleList,
- cell, rowIndex);
- }
-
- private void LoadColumns(Stylesheet s, NumberingFormats numberingFormats, Fills fills, Borders borders,
- Fonts fonts, XLWorksheet ws, Columns columns)
- {
- if (columns == null) return;
-
- var wsDefaultColumn =
- columns.Elements().Where(c => c.Max == XLHelper.MaxColumnNumber).FirstOrDefault();
-
- if (wsDefaultColumn != null && wsDefaultColumn.Width != null)
- ws.ColumnWidth = wsDefaultColumn.Width - ColumnWidthOffset;
-
- Int32 styleIndexDefault = wsDefaultColumn != null && wsDefaultColumn.Style != null
- ? Int32.Parse(wsDefaultColumn.Style.InnerText)
- : -1;
- if (styleIndexDefault >= 0)
- ApplyStyle(ws, styleIndexDefault, s, fills, borders, fonts, numberingFormats);
-
- foreach (Column col in columns.Elements())
- {
- //IXLStylized toApply;
- if (col.Max == XLHelper.MaxColumnNumber) continue;
-
- var xlColumns = (XLColumns)ws.Columns(col.Min, col.Max);
- if (col.Width != null)
- {
- Double width = col.Width - ColumnWidthOffset;
- //if (width < 0) width = 0;
- xlColumns.Width = width;
- }
- else
- xlColumns.Width = ws.ColumnWidth;
-
- if (col.Hidden != null && col.Hidden)
- xlColumns.Hide();
-
- if (col.Collapsed != null && col.Collapsed)
- xlColumns.CollapseOnly();
-
- if (col.OutlineLevel != null)
- {
- var outlineLevel = col.OutlineLevel;
- xlColumns.ForEach(c => c.OutlineLevel = outlineLevel);
- }
-
- Int32 styleIndex = col.Style != null ? Int32.Parse(col.Style.InnerText) : -1;
- if (styleIndex > 0)
- {
- ApplyStyle(xlColumns, styleIndex, s, fills, borders, fonts, numberingFormats);
- }
- else
- {
- xlColumns.Style = DefaultStyle;
- }
- }
- }
-
- private static XLCellValues GetDataTypeFromCell(IXLNumberFormat numberFormat)
- {
- var numberFormatId = numberFormat.NumberFormatId;
- if (numberFormatId == 46U)
- return XLCellValues.TimeSpan;
- else if ((numberFormatId >= 14 && numberFormatId <= 22) ||
- (numberFormatId >= 45 && numberFormatId <= 47))
- return XLCellValues.DateTime;
- else if (numberFormatId == 49)
- return XLCellValues.Text;
- else
- {
- if (!XLHelper.IsNullOrWhiteSpace(numberFormat.Format))
- {
- var dataType = GetDataTypeFromFormat(numberFormat.Format);
- return dataType.HasValue ? dataType.Value : XLCellValues.Number;
- }
- else
- return XLCellValues.Number;
- }
- }
-
- private static XLCellValues? GetDataTypeFromFormat(String format)
- {
- int length = format.Length;
- String f = format.ToLower();
- for (Int32 i = 0; i < length; i++)
- {
- Char c = f[i];
- if (c == '"')
- i = f.IndexOf('"', i + 1);
- else if (c == '0' || c == '#' || c == '?')
- return XLCellValues.Number;
- else if (c == 'y' || c == 'm' || c == 'd' || c == 'h' || c == 's')
- return XLCellValues.DateTime;
- }
- return null;
- }
-
- private static void LoadAutoFilter(AutoFilter af, XLWorksheet ws)
- {
- if (af != null)
- {
- ws.Range(af.Reference.Value).SetAutoFilter();
- var autoFilter = ws.AutoFilter;
- LoadAutoFilterSort(af, ws, autoFilter);
- LoadAutoFilterColumns(af, autoFilter);
- }
- }
-
- private static void LoadAutoFilterColumns(AutoFilter af, XLAutoFilter autoFilter)
- {
- foreach (var filterColumn in af.Elements())
- {
- Int32 column = (int)filterColumn.ColumnId.Value + 1;
- if (filterColumn.CustomFilters != null)
- {
- var filterList = new List();
- autoFilter.Column(column).FilterType = XLFilterType.Custom;
- autoFilter.Filters.Add(column, filterList);
- XLConnector connector = filterColumn.CustomFilters.And != null && filterColumn.CustomFilters.And.Value ? XLConnector.And : XLConnector.Or;
-
- Boolean isText = false;
- foreach (CustomFilter filter in filterColumn.CustomFilters)
- {
- Double dTest;
- String val = filter.Val.Value;
- if (!Double.TryParse(val, out dTest))
- {
- isText = true;
- break;
- }
- }
-
- foreach (CustomFilter filter in filterColumn.CustomFilters)
- {
- var xlFilter = new XLFilter { Value = filter.Val.Value, Connector = connector };
- if (isText)
- xlFilter.Value = filter.Val.Value;
- else
- xlFilter.Value = Double.Parse(filter.Val.Value, CultureInfo.InvariantCulture);
-
- if (filter.Operator != null)
- xlFilter.Operator = filter.Operator.Value.ToClosedXml();
- else
- xlFilter.Operator = XLFilterOperator.Equal;
-
- Func |