diff --git a/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj b/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj index 04c68da..7ee3db4 100644 --- a/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj +++ b/ClosedXML/ClosedXML/ClosedXML/ClosedXML.csproj @@ -163,10 +163,10 @@ - - + + diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs index e5a162c..00d1c88 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/IXLCell.cs @@ -85,7 +85,7 @@ /// TimeSpan GetTimeSpan(); - IXLRichString GetRichText(); + IXLRichText GetRichText(); /// /// Clears the contents of this cell (including styles). @@ -176,7 +176,7 @@ String ValueCached { get; } - IXLRichString RichText { get; } + IXLRichText RichText { get; } Boolean HasRichText { get; } } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs index 90c8638..88cc20f 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Cells/XLCell.cs @@ -13,7 +13,7 @@ public static readonly DateTime BaseDate = new DateTime(1899, 12, 30); #region Private fields private readonly XLWorksheet m_worksheet; - private XLRichString m_richText; + private XLRichText m_richText; private XLHyperlink m_hyperlink; #endregion #region Constructor @@ -139,7 +139,7 @@ return (T)Convert.ChangeType(Value.ToString(), typeof(T)); else return (T)Value; - else if (Value is IXLRichString) + else if (Value is IXLRichText) return (T)RichText; else return (T)Convert.ChangeType(Value, typeof(T)); @@ -164,7 +164,7 @@ { return GetValue(); } - public IXLRichString GetRichText() + public IXLRichText GetRichText() { return RichText; } @@ -322,7 +322,7 @@ private bool SetRichText(object value) { - var asRichString = value as XLRichString; + var asRichString = value as XLRichText; if (asRichString == null) { return false; @@ -751,24 +751,18 @@ m_cellValue = val; } #region IXLStylized Members - private Boolean m_initialStyle = true; - public void SetStyle(XLStyle style) - { - m_style = style; - } + private IXLStyle m_style; public IXLStyle Style { get { - if (m_initialStyle) - { m_style = new XLStyle(this, m_style); - m_initialStyle = false; - } return m_style; } - set { m_style = new XLStyle(this, value); } + set { + m_style = new XLStyle(this, value); + } } public IEnumerable Styles @@ -798,7 +792,9 @@ internal XLCellValues m_dataType; public XLCellValues DataType { - get { return m_dataType; } + get { + return m_dataType; + } set { if (m_dataType != value) @@ -1852,7 +1848,7 @@ public String ValueCached { get; internal set; } - public IXLRichString RichText + public IXLRichText RichText { get { @@ -1860,10 +1856,10 @@ { if (StringExtensions.IsNullOrWhiteSpace(m_cellValue)) { - m_richText = new XLRichString(m_style.Font); + m_richText = new XLRichText(m_style.Font); } else - m_richText = new XLRichString(GetFormattedString(), m_style.Font); + m_richText = new XLRichText(GetFormattedString(), m_style.Font); m_dataType = XLCellValues.Text; if (!Style.Alignment.WrapText) diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/XLColumn.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/XLColumn.cs index 9f763d1..592e814 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/XLColumn.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Columns/XLColumn.cs @@ -321,158 +321,7 @@ } public IXLColumn AdjustToContents(Int32 startRow, Int32 endRow) { - Double colMaxWidth = 0; - foreach (var c in CellsUsed().Where(cell => cell.Address.RowNumber >= startRow && cell.Address.RowNumber <= endRow)) - { - Boolean isMerged = false; - var cellAsRange = c.AsRange(); - foreach (var m in (Worksheet as XLWorksheet).Internals.MergedRanges) - { - if (cellAsRange.Intersects(m)) - { - isMerged = true; - break; - } - } - if (!isMerged) - { - Int32 textRotation = c.Style.Alignment.TextRotation; - List> kpList = new List>(); - - if (c.HasRichText) - { - foreach (var rt in c.RichText) - { - String formattedString = rt.Text; - var arr = formattedString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); - Int32 arrCount = arr.Count(); - for (Int32 i = 0; i < arrCount; i++) - { - String s = arr[i]; - if (i < arrCount - 1) - s += Environment.NewLine; - kpList.Add(new KeyValuePair(c.Style.Font, s)); - } - } - } - else - { - String formattedString = c.GetFormattedString(); - var arr = formattedString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); - Int32 arrCount = arr.Count(); - for (Int32 i = 0; i < arrCount; i++) - { - String s = arr[i]; - if (i < arrCount - 1) - s += Environment.NewLine; - kpList.Add(new KeyValuePair(c.Style.Font, s)); - } - } - - Double thisWidthMax = 0; - Double runningWidth = 0; - Boolean rotated = false; - Double rotationAdd = 0; - Double rotationMod = 0; - Double rotationIncrement = 0; - foreach (var kp in kpList) - { - IXLFontBase f = kp.Key; - String formattedString = kp.Value; - - Int32 newLinePosition = formattedString.IndexOf(Environment.NewLine); - if (textRotation == 0) - { - if (newLinePosition >= 0) - { - if (newLinePosition > 0) - runningWidth += f.GetWidth(formattedString.Substring(0, newLinePosition)); - - if (runningWidth > thisWidthMax) - thisWidthMax = runningWidth; - - if (newLinePosition < formattedString.Length - 2) - runningWidth = f.GetWidth(formattedString.Substring(newLinePosition + 2)); - else - runningWidth = 0; - } - else - { - runningWidth += f.GetWidth(formattedString); - } - } - else - { - if (textRotation == 255) - { - if (runningWidth == 0) - runningWidth = f.GetWidth("X"); - - if (newLinePosition >= 0) - runningWidth += f.GetWidth("X"); - } - else - { - rotated = true; - Double vWidth = f.GetWidth("X"); - if (vWidth > rotationAdd) - rotationAdd = vWidth; - - if (newLinePosition >= 0) - { - rotationIncrement += 0.5; - rotationMod += 2 + rotationIncrement; - - if (newLinePosition > 0) - runningWidth += f.GetWidth(formattedString.Substring(0, newLinePosition)); - - if (runningWidth > thisWidthMax) - thisWidthMax = runningWidth; - - if (newLinePosition < formattedString.Length - 2) - runningWidth = f.GetWidth(formattedString.Substring(newLinePosition + 2)); - else - runningWidth = 0; - - } - else - { - runningWidth += f.GetWidth(formattedString); - } - } - } - } - - if (runningWidth > thisWidthMax) - thisWidthMax = runningWidth; - - if (rotated) - { - Int32 rotation; - if (textRotation == 90 || textRotation == 180 || textRotation == 255) - rotation = 90; - else - rotation = textRotation % 90; - - Double r = DegreeToRadian(rotation); - if (rotationMod == 0) - rotationMod = 1; - thisWidthMax = (thisWidthMax * Math.Cos(r) + (Math.Sin(r) * rotationAdd * rotationMod)) + 1; - } - - - - if (thisWidthMax > colMaxWidth) - colMaxWidth = thisWidthMax + 1; - } - } - - if (colMaxWidth == 0) - colMaxWidth = Worksheet.ColumnWidth; - - Width = colMaxWidth; - - return this; + return AdjustToContents(startRow, endRow, 0, Double.MaxValue); } private double DegreeToRadian(double angle) @@ -491,66 +340,189 @@ public IXLColumn AdjustToContents(Int32 startRow, Int32 endRow, Double minWidth, Double maxWidth) { Double colMaxWidth = minWidth; - foreach (var c in CellsUsed().Where(cell => cell.Address.RowNumber >= startRow && cell.Address.RowNumber <= endRow)) + foreach (var cell in Column(startRow, endRow).CellsUsed()) { - Boolean isMerged = false; - var cellAsRange = c.AsRange(); - foreach (var m in (Worksheet).Internals.MergedRanges) - { - if (cellAsRange.Intersects(m)) - { - isMerged = true; - break; - } - } + var c = cell as XLCell; + Boolean isMerged = CellIsMerged(c); + if (!isMerged) { + Double thisWidthMax = 0; Int32 textRotation = c.Style.Alignment.TextRotation; - var f = (XLFont) c.Style.Font; - Double thisWidth; - if (textRotation == 0) + if (c.HasRichText || textRotation != 0 || c.InnerText.Contains(Environment.NewLine)) { - thisWidth = f.GetWidth(c.GetFormattedString()); - } - else - { - if (textRotation == 255) + + List> kpList = new List>(); + + #region if (c.HasRichText) + + if (c.HasRichText) { - thisWidth = f.GetWidth("X"); + foreach (var rt in c.RichText) + { + String formattedString = rt.Text; + var arr = formattedString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + Int32 arrCount = arr.Count(); + for (Int32 i = 0; i < arrCount; i++) + { + String s = arr[i]; + if (i < arrCount - 1) + s += Environment.NewLine; + kpList.Add(new KeyValuePair(rt, s)); + } + } } else { - Int32 rotation; - if (textRotation == 90 || textRotation == 180 || textRotation == 255) + String formattedString = c.GetFormattedString(); + var arr = formattedString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + Int32 arrCount = arr.Count(); + for (Int32 i = 0; i < arrCount; i++) { - rotation = 90; + String s = arr[i]; + if (i < arrCount - 1) + s += Environment.NewLine; + kpList.Add(new KeyValuePair(c.Style.Font, s)); + } + } + #endregion + + #region foreach (var kp in kpList) + + + Double runningWidth = 0; + Boolean rotated = false; + Double maxLineWidth = 0; + Int32 lineCount = 1; + foreach (var kp in kpList) + { + IXLFontBase f = kp.Key; + String formattedString = kp.Value; + + Int32 newLinePosition = formattedString.IndexOf(Environment.NewLine); + if (textRotation == 0) + { + #region if (newLinePosition >= 0) + + if (newLinePosition >= 0) + { + if (newLinePosition > 0) + runningWidth += f.GetWidth(formattedString.Substring(0, newLinePosition)); + + if (runningWidth > thisWidthMax) + thisWidthMax = runningWidth; + + if (newLinePosition < formattedString.Length - 2) + runningWidth = f.GetWidth(formattedString.Substring(newLinePosition + 2)); + else + runningWidth = 0; + } + else + { + runningWidth += f.GetWidth(formattedString); + } + #endregion } else { - rotation = textRotation%90; + #region if (textRotation == 255) + if (textRotation == 255) + { + if (runningWidth == 0) + runningWidth = f.GetWidth("X"); + + if (newLinePosition >= 0) + runningWidth += f.GetWidth("X"); + } + else + { + rotated = true; + Double vWidth = f.GetWidth("X"); + if (vWidth > maxLineWidth) + maxLineWidth = vWidth; + + if (newLinePosition >= 0) + { + lineCount++; + + if (newLinePosition > 0) + runningWidth += f.GetWidth(formattedString.Substring(0, newLinePosition)); + + if (runningWidth > thisWidthMax) + thisWidthMax = runningWidth; + + if (newLinePosition < formattedString.Length - 2) + runningWidth = f.GetWidth(formattedString.Substring(newLinePosition + 2)); + else + runningWidth = 0; + + } + else + { + runningWidth += f.GetWidth(formattedString); + } + } + #endregion } + } + #endregion + if (runningWidth > thisWidthMax) + thisWidthMax = runningWidth; + + #region if (rotated) + if (rotated) + { + Int32 rotation; + if (textRotation == 90 || textRotation == 180 || textRotation == 255) + rotation = 90; + else + rotation = textRotation % 90; Double r = DegreeToRadian(rotation); - thisWidth = f.GetWidth(c.GetFormattedString())*Math.Cos(r) + Math.Sin(r)*f.GetWidth("X"); + + thisWidthMax = (thisWidthMax * Math.Cos(r)) + (maxLineWidth * lineCount) ; } + #endregion } - - if (thisWidth >= maxWidth) + else + { + thisWidthMax = c.Style.Font.GetWidth(c.GetFormattedString()); + } + if (thisWidthMax >= maxWidth) { colMaxWidth = maxWidth; break; } - else if (thisWidth > colMaxWidth) + else if (thisWidthMax > colMaxWidth) { - colMaxWidth = thisWidth; + colMaxWidth = thisWidthMax + 1; } } } + if (colMaxWidth == 0) + colMaxWidth = Worksheet.ColumnWidth; + Width = colMaxWidth; + return this; } + private Boolean CellIsMerged(IXLCell c) + { + Boolean isMerged = false; + var cellAsRange = c.AsRange(); + foreach (var m in Worksheet.Internals.MergedRanges) + { + if (cellAsRange.Intersects(m)) + { + isMerged = true; + break; + } + } + return isMerged; + } + public void Hide() { IsHidden = true; diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/IXLHFItem.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/IXLHFItem.cs index ffedbca..9883434 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/IXLHFItem.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/IXLHFItem.cs @@ -23,27 +23,27 @@ /// Adds the given text to this header/footer item. /// /// The text to add to this header/footer item. - IXLRichText AddText(String text); + IXLRichString AddText(String text); /// /// Adds the given predefined text to this header/footer item. /// /// The predefined text to add to this header/footer item. - IXLRichText AddText(XLHFPredefinedText predefinedText); + IXLRichString AddText(XLHFPredefinedText predefinedText); /// /// Adds the given text to this header/footer item. /// /// The text to add to this header/footer item. /// The occurrence for the text. - IXLRichText AddText(String text, XLHFOccurrence occurrence); + IXLRichString AddText(String text, XLHFOccurrence occurrence); /// /// Adds the given predefined text to this header/footer item. /// /// The predefined text to add to this header/footer item. /// The occurrence for the predefined text. - IXLRichText AddText(XLHFPredefinedText predefinedText, XLHFOccurrence occurrence); + IXLRichString AddText(XLHFPredefinedText predefinedText, XLHFOccurrence occurrence); /// Clears the text/formats of this header/footer item. /// The occurrence to clear. diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFItem.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFItem.cs index f046dff..5c9f504 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFItem.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFItem.cs @@ -25,18 +25,18 @@ return sb.ToString(); } - public IXLRichText AddText(String text) + public IXLRichString AddText(String text) { return AddText(text, XLHFOccurrence.AllPages); } - public IXLRichText AddText(XLHFPredefinedText predefinedText) + public IXLRichString AddText(XLHFPredefinedText predefinedText) { return AddText(predefinedText, XLHFOccurrence.AllPages); } - public IXLRichText AddText(String text, XLHFOccurrence occurrence) + public IXLRichString AddText(String text, XLHFOccurrence occurrence) { - IXLRichText richText = new XLRichText(text, XLWorkbook.DefaultStyle.Font); + IXLRichString richText = new XLRichString(text, XLWorkbook.DefaultStyle.Font); var hfText = new XLHFText(richText); if (occurrence == XLHFOccurrence.AllPages) @@ -61,7 +61,7 @@ texts.Add(occurrence, new List() { hfText }); } - public IXLRichText AddText(XLHFPredefinedText predefinedText, XLHFOccurrence occurrence) + public IXLRichString AddText(XLHFPredefinedText predefinedText, XLHFOccurrence occurrence) { String hfText; switch (predefinedText) diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFText.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFText.cs index d4a078e..90ff3c7 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFText.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/PageSetup/XLHFText.cs @@ -4,11 +4,11 @@ { internal class XLHFText { - public XLHFText(IXLRichText richText) + public XLHFText(IXLRichString richText) { RichText = richText; } - public IXLRichText RichText { get; private set; } + public IXLRichString RichText { get; private set; } public String HFText { @@ -38,7 +38,7 @@ } } - private String GetHFFontBoldItalic(IXLRichText xlFont) + private String GetHFFontBoldItalic(IXLRichString xlFont) { String retVal = String.Empty; if (xlFont.Bold && xlFont.Italic) diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichString.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichString.cs index 2aae75e..989bd27 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichString.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichString.cs @@ -1,20 +1,11 @@ using System; -using System.Collections.Generic; namespace ClosedXML.Excel { - public interface IXLRichString : IEnumerable + public interface IXLRichString: IXLFontBase, IEquatable { - Boolean Bold { set; } - Boolean Italic { set; } - XLFontUnderlineValues Underline { set; } - Boolean Strikethrough { set; } - XLFontVerticalTextAlignmentValues VerticalAlignment { set; } - Boolean Shadow { set; } - Double FontSize { set; } - IXLColor FontColor { set; } - String FontName { set; } - XLFontFamilyNumberingValues FontFamilyNumbering { set; } + String Text { get; } + IXLRichString Apply(IXLFontBase font); IXLRichString SetBold(); IXLRichString SetBold(Boolean value); IXLRichString SetItalic(); IXLRichString SetItalic(Boolean value); @@ -26,15 +17,5 @@ IXLRichString SetFontColor(IXLColor value); IXLRichString SetFontName(String value); IXLRichString SetFontFamilyNumbering(XLFontFamilyNumberingValues value); - - IXLRichText AddText(String text); - IXLRichText AddText(String text, IXLFontBase font); - IXLRichString Clear(); - IXLRichString Substring(Int32 index); - IXLRichString Substring(Int32 index, Int32 length); - Int32 Count { get; } - Int32 Length { get; } - - } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichText.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichText.cs index ebec6d2..8a0ab6b 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichText.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/IXLRichText.cs @@ -1,11 +1,20 @@ using System; +using System.Collections.Generic; namespace ClosedXML.Excel { - public interface IXLRichText: IXLFontBase, IEquatable + public interface IXLRichText : IEnumerable { - String Text { get; } - IXLRichText Apply(IXLFontBase font); + Boolean Bold { set; } + Boolean Italic { set; } + XLFontUnderlineValues Underline { set; } + Boolean Strikethrough { set; } + XLFontVerticalTextAlignmentValues VerticalAlignment { set; } + Boolean Shadow { set; } + Double FontSize { set; } + IXLColor FontColor { set; } + String FontName { set; } + XLFontFamilyNumberingValues FontFamilyNumbering { set; } IXLRichText SetBold(); IXLRichText SetBold(Boolean value); IXLRichText SetItalic(); IXLRichText SetItalic(Boolean value); @@ -17,5 +26,15 @@ IXLRichText SetFontColor(IXLColor value); IXLRichText SetFontName(String value); IXLRichText SetFontFamilyNumbering(XLFontFamilyNumberingValues value); + + IXLRichString AddText(String text); + IXLRichString AddText(String text, IXLFontBase font); + IXLRichText Clear(); + IXLRichText Substring(Int32 index); + IXLRichText Substring(Int32 index, Int32 length); + Int32 Count { get; } + Int32 Length { get; } + + } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichString.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichString.cs index 6524a0f..74aa26a 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichString.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichString.cs @@ -1,134 +1,42 @@ using System; -using System.Collections.Generic; -using System.Text; -using System.Linq; namespace ClosedXML.Excel { - internal class XLRichString: IXLRichString, IEquatable + internal class XLRichString: IXLRichString { - List richTexts = new List(); - IXLFontBase m_defaultFont; - public XLRichString(IXLFontBase defaultFont) + public XLRichString(String text, IXLFontBase font) { - m_defaultFont = defaultFont; + Text = text; + Apply(font); } - public XLRichString(String text, IXLFontBase defaultFont) - :this(defaultFont) - { - AddText(text); - } - - public Int32 Count { get { return richTexts.Count; } } - private Int32 m_length = 0; - public Int32 Length - { - get - { - return m_length; - } - } - public IXLRichText AddText(String text) - { - return AddText(text, m_defaultFont); - } - public IXLRichText AddText(String text, IXLFontBase font) - { - var richText = new XLRichText(text, font); - return AddText(richText); - } - - public IXLRichText AddText(IXLRichText richText) - { - richTexts.Add(richText); - m_length += richText.Text.Length; - return richText; - } - public IXLRichString Clear() - { - richTexts.Clear(); - m_length = 0; + public String Text { get; private set; } + public IXLRichString Apply(IXLFontBase font) + { + Bold = font.Bold; + Italic = font.Italic; + Underline = font.Underline; + Strikethrough = font.Strikethrough; + VerticalAlignment = font.VerticalAlignment; + Shadow = font.Shadow; + FontSize = font.FontSize; + FontColor = new XLColor(font.FontColor); + FontName = font.FontName; + FontFamilyNumbering = font.FontFamilyNumbering; return this; } - public override string ToString() - { - var sb = new StringBuilder(richTexts.Count); - richTexts.ForEach(rt => sb.Append(rt.Text)); - return sb.ToString(); - } - - public IXLRichString Substring(Int32 index) - { - return Substring(index, m_length - index); - } - public IXLRichString Substring(Int32 index, Int32 length) - { - if (index + 1 > m_length || (m_length - index + 1) < length || length <= 0) - throw new IndexOutOfRangeException("Index and length must refer to a location within the string."); - - List newRichTexts = new List(); - XLRichString retVal = new XLRichString(m_defaultFont); - - Int32 lastPosition = 0; - foreach (var rt in richTexts) - { - if (lastPosition >= index + 1 + length) // We already have what we need - { - newRichTexts.Add(rt); - } - else if (lastPosition + rt.Text.Length >= index + 1) // Eureka! - { - Int32 startIndex = index - lastPosition; - - if (startIndex > 0) - newRichTexts.Add(new XLRichText(rt.Text.Substring(0, startIndex), rt)); - else if (startIndex < 0) - startIndex = 0; - - Int32 leftToTake = length - retVal.Length; - if (leftToTake > rt.Text.Length - startIndex) - leftToTake = rt.Text.Length - startIndex; - - XLRichText newRT = new XLRichText(rt.Text.Substring(startIndex, leftToTake), rt); - newRichTexts.Add(newRT); - retVal.AddText(newRT); - - if (startIndex + leftToTake < rt.Text.Length) - newRichTexts.Add(new XLRichText(rt.Text.Substring(startIndex + leftToTake), rt)); - } - else // We haven't reached the desired position yet - { - newRichTexts.Add(rt); - } - lastPosition += rt.Text.Length; - } - richTexts = newRichTexts; - return retVal; - } - - public IEnumerator GetEnumerator() - { - return richTexts.GetEnumerator(); - } - - System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - public Boolean Bold { set { richTexts.ForEach(rt => rt.Bold = value); } } - public Boolean Italic { set { richTexts.ForEach(rt => rt.Italic = value); } } - public XLFontUnderlineValues Underline { set { richTexts.ForEach(rt => rt.Underline = value); } } - public Boolean Strikethrough { set { richTexts.ForEach(rt => rt.Strikethrough = value); } } - public XLFontVerticalTextAlignmentValues VerticalAlignment { set { richTexts.ForEach(rt => rt.VerticalAlignment = value); } } - public Boolean Shadow { set { richTexts.ForEach(rt => rt.Shadow = value); } } - public Double FontSize { set { richTexts.ForEach(rt => rt.FontSize = value); } } - public IXLColor FontColor { set { richTexts.ForEach(rt => rt.FontColor = value); } } - public String FontName { set { richTexts.ForEach(rt => rt.FontName = value); } } - public XLFontFamilyNumberingValues FontFamilyNumbering { set { richTexts.ForEach(rt => rt.FontFamilyNumbering = value); } } + public Boolean Bold { get; set; } + public Boolean Italic { get; set; } + public XLFontUnderlineValues Underline { get; set; } + public Boolean Strikethrough { get; set; } + public XLFontVerticalTextAlignmentValues VerticalAlignment { get; set; } + public Boolean Shadow { get; set; } + public Double FontSize { get; set; } + public IXLColor FontColor { get; set; } + public String FontName { get; set; } + public XLFontFamilyNumberingValues FontFamilyNumbering { get; set; } public IXLRichString SetBold() { Bold = true; return this; } public IXLRichString SetBold(Boolean value) { Bold = value; return this; } public IXLRichString SetItalic() { Italic = true; return this; } public IXLRichString SetItalic(Boolean value) { Italic = value; return this; } @@ -141,19 +49,41 @@ public IXLRichString SetFontName(String value) { FontName = value; return this; } public IXLRichString SetFontFamilyNumbering(XLFontFamilyNumberingValues value) { FontFamilyNumbering = value; return this; } - public bool Equals(IXLRichString other) + public Boolean Equals(IXLRichString other) { - Int32 count = Count; - if (count != other.Count) - return false; + return + Text == other.Text + && this.Bold.Equals(other.Bold) + && this.Italic.Equals(other.Italic) + && this.Underline.Equals(other.Underline) + && this.Strikethrough.Equals(other.Strikethrough) + && this.VerticalAlignment.Equals(other.VerticalAlignment) + && this.Shadow.Equals(other.Shadow) + && this.FontSize.Equals(other.FontSize) + && this.FontColor.Equals(other.FontColor) + && this.FontName.Equals(other.FontName) + && this.FontFamilyNumbering.Equals(other.FontFamilyNumbering) + ; + } - for (Int32 i = 0; i < count; i++) - { - if (richTexts.ElementAt(i) != other.ElementAt(i)) - return false; - } + public override bool Equals(object obj) + { + return this.Equals((XLRichString)obj); + } - return true; + public override int GetHashCode() + { + return Text.GetHashCode() + ^ Bold.GetHashCode() + ^ Italic.GetHashCode() + ^ (Int32)Underline + ^ Strikethrough.GetHashCode() + ^ (Int32)VerticalAlignment + ^ Shadow.GetHashCode() + ^ FontSize.GetHashCode() + ^ FontColor.GetHashCode() + ^ FontName.GetHashCode() + ^ (Int32)FontFamilyNumbering; } } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichText.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichText.cs index 9c999a5..f834a47 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichText.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/RichText/XLRichText.cs @@ -1,42 +1,134 @@ using System; +using System.Collections.Generic; +using System.Text; +using System.Linq; namespace ClosedXML.Excel { - internal class XLRichText: IXLRichText + internal class XLRichText: IXLRichText, IEquatable { + List richTexts = new List(); - public XLRichText(String text, IXLFontBase font) + IXLFontBase m_defaultFont; + public XLRichText(IXLFontBase defaultFont) { - Text = text; - Apply(font); + m_defaultFont = defaultFont; } - public String Text { get; private set; } - public IXLRichText Apply(IXLFontBase font) - { - Bold = font.Bold; - Italic = font.Italic; - Underline = font.Underline; - Strikethrough = font.Strikethrough; - VerticalAlignment = font.VerticalAlignment; - Shadow = font.Shadow; - FontSize = font.FontSize; - FontColor = new XLColor(font.FontColor); - FontName = font.FontName; - FontFamilyNumbering = font.FontFamilyNumbering; + public XLRichText(String text, IXLFontBase defaultFont) + :this(defaultFont) + { + AddText(text); + } + + public Int32 Count { get { return richTexts.Count; } } + private Int32 m_length = 0; + public Int32 Length + { + get + { + return m_length; + } + } + public IXLRichString AddText(String text) + { + return AddText(text, m_defaultFont); + } + public IXLRichString AddText(String text, IXLFontBase font) + { + var richText = new XLRichString(text, font); + return AddText(richText); + } + + public IXLRichString AddText(IXLRichString richText) + { + richTexts.Add(richText); + m_length += richText.Text.Length; + return richText; + } + public IXLRichText Clear() + { + richTexts.Clear(); + m_length = 0; return this; } - public Boolean Bold { get; set; } - public Boolean Italic { get; set; } - public XLFontUnderlineValues Underline { get; set; } - public Boolean Strikethrough { get; set; } - public XLFontVerticalTextAlignmentValues VerticalAlignment { get; set; } - public Boolean Shadow { get; set; } - public Double FontSize { get; set; } - public IXLColor FontColor { get; set; } - public String FontName { get; set; } - public XLFontFamilyNumberingValues FontFamilyNumbering { get; set; } + public override string ToString() + { + var sb = new StringBuilder(richTexts.Count); + richTexts.ForEach(rt => sb.Append(rt.Text)); + return sb.ToString(); + } + + public IXLRichText Substring(Int32 index) + { + return Substring(index, m_length - index); + } + public IXLRichText Substring(Int32 index, Int32 length) + { + if (index + 1 > m_length || (m_length - index + 1) < length || length <= 0) + throw new IndexOutOfRangeException("Index and length must refer to a location within the string."); + + List newRichTexts = new List(); + XLRichText retVal = new XLRichText(m_defaultFont); + + Int32 lastPosition = 0; + foreach (var rt in richTexts) + { + if (lastPosition >= index + 1 + length) // We already have what we need + { + newRichTexts.Add(rt); + } + else if (lastPosition + rt.Text.Length >= index + 1) // Eureka! + { + Int32 startIndex = index - lastPosition; + + if (startIndex > 0) + newRichTexts.Add(new XLRichString(rt.Text.Substring(0, startIndex), rt)); + else if (startIndex < 0) + startIndex = 0; + + Int32 leftToTake = length - retVal.Length; + if (leftToTake > rt.Text.Length - startIndex) + leftToTake = rt.Text.Length - startIndex; + + XLRichString newRT = new XLRichString(rt.Text.Substring(startIndex, leftToTake), rt); + newRichTexts.Add(newRT); + retVal.AddText(newRT); + + if (startIndex + leftToTake < rt.Text.Length) + newRichTexts.Add(new XLRichString(rt.Text.Substring(startIndex + leftToTake), rt)); + } + else // We haven't reached the desired position yet + { + newRichTexts.Add(rt); + } + lastPosition += rt.Text.Length; + } + richTexts = newRichTexts; + return retVal; + } + + public IEnumerator GetEnumerator() + { + return richTexts.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public Boolean Bold { set { richTexts.ForEach(rt => rt.Bold = value); } } + public Boolean Italic { set { richTexts.ForEach(rt => rt.Italic = value); } } + public XLFontUnderlineValues Underline { set { richTexts.ForEach(rt => rt.Underline = value); } } + public Boolean Strikethrough { set { richTexts.ForEach(rt => rt.Strikethrough = value); } } + public XLFontVerticalTextAlignmentValues VerticalAlignment { set { richTexts.ForEach(rt => rt.VerticalAlignment = value); } } + public Boolean Shadow { set { richTexts.ForEach(rt => rt.Shadow = value); } } + public Double FontSize { set { richTexts.ForEach(rt => rt.FontSize = value); } } + public IXLColor FontColor { set { richTexts.ForEach(rt => rt.FontColor = value); } } + public String FontName { set { richTexts.ForEach(rt => rt.FontName = value); } } + public XLFontFamilyNumberingValues FontFamilyNumbering { set { richTexts.ForEach(rt => rt.FontFamilyNumbering = value); } } public IXLRichText SetBold() { Bold = true; return this; } public IXLRichText SetBold(Boolean value) { Bold = value; return this; } public IXLRichText SetItalic() { Italic = true; return this; } public IXLRichText SetItalic(Boolean value) { Italic = value; return this; } @@ -49,41 +141,19 @@ public IXLRichText SetFontName(String value) { FontName = value; return this; } public IXLRichText SetFontFamilyNumbering(XLFontFamilyNumberingValues value) { FontFamilyNumbering = value; return this; } - public Boolean Equals(IXLRichText other) + public bool Equals(IXLRichText other) { - return - Text == other.Text - && this.Bold.Equals(other.Bold) - && this.Italic.Equals(other.Italic) - && this.Underline.Equals(other.Underline) - && this.Strikethrough.Equals(other.Strikethrough) - && this.VerticalAlignment.Equals(other.VerticalAlignment) - && this.Shadow.Equals(other.Shadow) - && this.FontSize.Equals(other.FontSize) - && this.FontColor.Equals(other.FontColor) - && this.FontName.Equals(other.FontName) - && this.FontFamilyNumbering.Equals(other.FontFamilyNumbering) - ; - } + Int32 count = Count; + if (count != other.Count) + return false; - public override bool Equals(object obj) - { - return this.Equals((XLRichText)obj); - } + for (Int32 i = 0; i < count; i++) + { + if (richTexts.ElementAt(i) != other.ElementAt(i)) + return false; + } - public override int GetHashCode() - { - return Text.GetHashCode() - ^ Bold.GetHashCode() - ^ Italic.GetHashCode() - ^ (Int32)Underline - ^ Strikethrough.GetHashCode() - ^ (Int32)VerticalAlignment - ^ Shadow.GetHashCode() - ^ FontSize.GetHashCode() - ^ FontColor.GetHashCode() - ^ FontName.GetHashCode() - ^ (Int32)FontFamilyNumbering; + return true; } } } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/XLRow.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/XLRow.cs index 5653f22..3690bcd 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/XLRow.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/Rows/XLRow.cs @@ -214,70 +214,7 @@ } public IXLRow AdjustToContents(Int32 startColumn, Int32 endColumn) { - Double maxHeight = 0; - foreach (var c in CellsUsed().Where(cell => cell.Address.ColumnNumber >= startColumn && cell.Address.ColumnNumber <= endColumn)) - { - Boolean isMerged = false; - var cellAsRange = c.AsRange(); - foreach (var m in (Worksheet).Internals.MergedRanges) - { - if (cellAsRange.Intersects(m)) - { - isMerged = true; - break; - } - } - if (!isMerged) - { - //var thisHeight = ((XLFont)c.Style.Font).GetHeight(); - - Int32 textRotation = c.Style.Alignment.TextRotation; - var f = (XLFont) c.Style.Font; - Double thisHeight; - if (textRotation == 0) - { - thisHeight = f.GetHeight(); - } - else - { - if (textRotation == 255) - { - thisHeight = f.GetHeight()*c.GetFormattedString().Length; - } - else - { - Int32 rotation; - if (textRotation == 90 || textRotation == 180 || textRotation == 255) - { - rotation = 90; - } - else - { - rotation = textRotation%90; - } - - Double r = DegreeToRadian(rotation); - Double b = f.GetHeight(); - Double m = f.GetHeight()*c.GetFormattedString().Length; - Double t = m - b; - thisHeight = (rotation/90)*t; - } - } - - if (thisHeight > maxHeight) - { - maxHeight = thisHeight; - } - } - } - - if (maxHeight == 0) - { - maxHeight = Worksheet.RowHeight; - } - - Height = maxHeight; - return this; + return AdjustToContents(startColumn, endColumn, 0, Double.MaxValue); } public IXLRow AdjustToContents(Double minHeight, Double maxHeight) @@ -291,11 +228,12 @@ public IXLRow AdjustToContents(Int32 startColumn, Int32 endColumn, Double minHeight, Double maxHeight) { Double rowMaxHeight = minHeight; - foreach (var c in CellsUsed().Where(cell => cell.Address.ColumnNumber >= startColumn && cell.Address.ColumnNumber <= endColumn)) + foreach (var cell in Row(startColumn, endColumn).CellsUsed()) { + var c = cell as XLCell; Boolean isMerged = false; var cellAsRange = c.AsRange(); - foreach (var m in (Worksheet).Internals.MergedRanges) + foreach (var m in Worksheet.Internals.MergedRanges) { if (cellAsRange.Intersects(m)) { @@ -305,38 +243,74 @@ } if (!isMerged) { - Int32 textRotation = c.Style.Alignment.TextRotation; - var f = (XLFont) c.Style.Font; Double thisHeight; - if (textRotation == 0) + Int32 textRotation = c.Style.Alignment.TextRotation; + if (c.HasRichText || textRotation != 0 || c.InnerText.Contains(Environment.NewLine)) { - thisHeight = f.GetHeight(); - } - else - { - if (textRotation == 255) + List> kpList = new List>(); + if (c.HasRichText) { - thisHeight = f.GetHeight()*c.GetFormattedString().Length; + foreach (var rt in c.RichText) + { + String formattedString = rt.Text; + var arr = formattedString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + Int32 arrCount = arr.Count(); + for (Int32 i = 0; i < arrCount; i++) + { + String s = arr[i]; + if (i < arrCount - 1) + s += Environment.NewLine; + kpList.Add(new KeyValuePair(rt, s)); + } + } } else { - Int32 rotation; - if (textRotation == 90 || textRotation == 180 || textRotation == 255) + String formattedString = c.GetFormattedString(); + var arr = formattedString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + Int32 arrCount = arr.Count(); + for (Int32 i = 0; i < arrCount; i++) { - rotation = 90; + String s = arr[i]; + if (i < arrCount - 1) + s += Environment.NewLine; + kpList.Add(new KeyValuePair(c.Style.Font, s)); + } + } + + Double maxLongCol = kpList.Max(kp => kp.Value.Length); + Double maxHeightCol = kpList.Max(kp => kp.Key.GetHeight()); + Int32 lineCount = kpList.Count(kp => kp.Value.Contains(Environment.NewLine)); + if (textRotation == 0) + { + thisHeight = maxHeightCol * lineCount; + } + else + { + if (textRotation == 255) + { + thisHeight = maxLongCol * maxHeightCol; } else { - rotation = textRotation%90; - } + Double rotation; + if (textRotation == 90 || textRotation == 180 || textRotation == 255) + { + rotation = 90; + } + else + { + rotation = textRotation % 90; + } - Double r = DegreeToRadian(rotation); - Double b = f.GetHeight(); - Double m = f.GetHeight()*c.GetFormattedString().Length; - Double t = m - b; - thisHeight = (rotation/90)*t; + thisHeight = (rotation / 90.0) * maxHeightCol * maxLongCol * 0.5; + } } } + else + { + thisHeight = c.Style.Font.GetHeight(); + } if (thisHeight >= maxHeight) { @@ -350,6 +324,9 @@ } } + if (rowMaxHeight == 0) + rowMaxHeight = Worksheet.RowHeight; + Height = rowMaxHeight; return this; } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs index a8258e6..fc2468d 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Load.cs @@ -311,7 +311,7 @@ var xlCell = (XLCell)ws.Cell(dCell.CellReference); if (styleList.ContainsKey(styleIndex)) - xlCell.SetStyle((XLStyle)styleList[styleIndex]); + xlCell.Style = styleList[styleIndex]; else { ApplyStyle(xlCell, styleIndex, s, fills, borders, fonts, numberingFormats); @@ -366,7 +366,70 @@ if (dCell.CellValue != null) { if (!StringExtensions.IsNullOrWhiteSpace(dCell.CellValue.Text)) - xlCell.m_cellValue = sharedStrings[Int32.Parse(dCell.CellValue.Text)].InnerText; + { + SharedStringItem sharedString = sharedStrings[Int32.Parse(dCell.CellValue.Text)]; + var runElements = sharedString.Elements(); + if (runElements.Any()) + { + foreach (var run in runElements) + { + var runProperties = run.RunProperties; + String text = run.Text.InnerText; + + if (runProperties == null) + { + xlCell.RichText.AddText(text, xlCell.Style.Font); + } + else + { + var rt = xlCell.RichText.AddText(text); + rt.Bold = GetBoolean(runProperties.Elements().FirstOrDefault()); + var fontColor = GetColor(runProperties.Elements().FirstOrDefault()); + if (fontColor.HasValue) + rt.FontColor = fontColor; + + var fontFamilyNumbering = runProperties.Elements().FirstOrDefault(); + if (fontFamilyNumbering != null && fontFamilyNumbering.Val != null) + rt.FontFamilyNumbering = (XLFontFamilyNumberingValues)Int32.Parse(fontFamilyNumbering.Val.ToString()); + var runFont = runProperties.Elements().FirstOrDefault(); + if (runFont != null) + { + if (runFont.Val != null) + rt.FontName = runFont.Val; + } + var fontSize = runProperties.Elements().FirstOrDefault(); + if (fontSize != null) + { + if (((FontSize)fontSize).Val != null) + rt.FontSize = ((FontSize)fontSize).Val; + } + + rt.Italic = GetBoolean(runProperties.Elements().FirstOrDefault()); + rt.Shadow = GetBoolean(runProperties.Elements().FirstOrDefault()); + rt.Strikethrough = GetBoolean(runProperties.Elements().FirstOrDefault()); + + var underline = runProperties.Elements().FirstOrDefault(); + if (underline != null) + if (underline.Val != null) + rt.Underline = underline.Val.Value.ToClosedXml(); + else + rt.Underline = XLFontUnderlineValues.Single; + + var verticalTextAlignment = runProperties.Elements().FirstOrDefault(); + if (verticalTextAlignment != null) + + if (verticalTextAlignment.Val != null) + rt.VerticalAlignment = verticalTextAlignment.Val.Value.ToClosedXml(); + else + rt.VerticalAlignment = XLFontVerticalTextAlignmentValues.Baseline; + } + } + } + else + { + xlCell.m_cellValue = sharedString.InnerText; + } + } else xlCell.m_cellValue = dCell.CellValue.Text; } diff --git a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs index fd99c28..5902642 100644 --- a/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs +++ b/ClosedXML/ClosedXML/ClosedXML/Excel/XLWorkbook_Save.cs @@ -690,7 +690,7 @@ Int32 stringId = 0; Dictionary newStrings = new Dictionary(); - Dictionary newRichStrings = new Dictionary(); + Dictionary newRichStrings = new Dictionary(); foreach (var w in Worksheets.Cast()) { foreach (var c in w.Internals.CellsCollection.Values) @@ -712,9 +712,9 @@ SharedStringItem sharedStringItem = new SharedStringItem(); foreach (var rt in c.RichText) { - var run = new A.Run(); + var run = new DocumentFormat.OpenXml.Spreadsheet.Run(); - var runProperties = new A.RunProperties(); + var runProperties = new DocumentFormat.OpenXml.Spreadsheet.RunProperties(); Bold bold = rt.Bold ? new Bold() : null; Italic italic = rt.Italic ? new Italic() : null; @@ -724,7 +724,7 @@ Shadow shadow = rt.Shadow ? new Shadow() : null; FontSize fontSize = new FontSize() { Val = rt.FontSize }; Color color = GetNewColor(rt.FontColor); - FontName fontName = new FontName() { Val = rt.FontName }; + RunFont fontName = new RunFont() { Val = rt.FontName }; FontFamilyNumbering fontFamilyNumbering = new FontFamilyNumbering() { Val = (Int32)rt.FontFamilyNumbering }; if (bold != null) runProperties.Append(bold); @@ -854,7 +854,7 @@ Int32 numberFormatCount = 1; var xlStyles = new HashSet(); - foreach (var worksheet in WorksheetsInternal.Cast()) + foreach (var worksheet in WorksheetsInternal) { foreach (var s in worksheet.Styles) { diff --git a/ClosedXML/ClosedXML/ClosedXML_Examples/Misc/AdjustToContents.cs b/ClosedXML/ClosedXML/ClosedXML_Examples/Misc/AdjustToContents.cs index bae56f4..b102bb0 100644 --- a/ClosedXML/ClosedXML/ClosedXML_Examples/Misc/AdjustToContents.cs +++ b/ClosedXML/ClosedXML/ClosedXML_Examples/Misc/AdjustToContents.cs @@ -97,9 +97,9 @@ c.RichText.AddText("Text to adjust - " + co).SetBold(); c.RichText.AddText(Environment.NewLine); - c.RichText.AddText("World!").SetBold().SetFontColor(XLColor.Blue).SetFontSize(10); + c.RichText.AddText("World!").SetBold().SetFontColor(XLColor.Blue).SetFontSize(25); c.RichText.AddText(Environment.NewLine); - c.RichText.AddText("Hello Cruel and unsusual world").SetBold().SetFontSize(15); + c.RichText.AddText("Hello Cruel and unsusual world").SetBold().SetFontSize(20); c.RichText.AddText(Environment.NewLine); c.RichText.AddText("Hello").SetBold(); c.Style.Alignment.SetTextRotation(co);