ASCU_ALL/MigraDoc.DocumentObjectModel/DocumentObjectModel/Styles.cs

448 lines
17 KiB
C#
Raw Normal View History

2020-09-04 12:49:15 +05:00
#region MigraDoc - Creating Documents on the Fly
//
// Authors:
// Stefan Lange
// Klaus Potzesny
// David Stephensen
//
// Copyright (c) 2001-2017 empira Software GmbH, Cologne Area (Germany)
//
// http://www.pdfsharp.com
// http://www.migradoc.com
// http://sourceforge.net/projects/pdfsharp
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using MigraDoc.DocumentObjectModel.publics;
using MigraDoc.DocumentObjectModel.Visitors;
namespace MigraDoc.DocumentObjectModel
{
/// <summary>
/// Represents the collection of all styles.
/// </summary>
public class Styles : DocumentObjectCollection, IVisitable
{
/// <summary>
/// Initializes a new instance of the Styles class.
/// </summary>
public Styles()
{
SetupStyles();
}
/// <summary>
/// Initializes a new instance of the Styles class with the specified parent.
/// </summary>
public Styles(DocumentObject parent)
: base(parent)
{
SetupStyles();
}
#region Methods
/// <summary>
/// Creates a deep copy of this object.
/// </summary>
public new Styles Clone()
{
return (Styles)base.DeepCopy();
}
/// <summary>
/// Gets a style by its name.
/// </summary>
public Style this[string styleName]
{
get
{
int count = Count;
// index starts from 1; DefaultParagraphFont cannot be modified.
for (int index = 1; index < count; ++index)
{
Style style = this[index];
if (String.Compare(style.Name, styleName, StringComparison.OrdinalIgnoreCase) == 0)
return style;
}
return null;
}
}
/// <summary>
/// Gets a style by index.
/// </summary>
public new Style this[int index]
{
get { return (Style)base[index]; }
}
/// <summary>
/// Gets the index of a style by name.
/// </summary>
/// <param name="styleName">Name of the style looking for.</param>
/// <returns>Index or -1 if it does not exist.</returns>
public int GetIndex(string styleName)
{
if (styleName == null)
throw new ArgumentNullException("styleName");
int count = Count;
for (int index = 0; index < count; ++index)
{
Style style = this[index];
if (String.Compare(style.Name, styleName, StringComparison.OrdinalIgnoreCase) == 0)
return index;
}
return -1;
}
/// <summary>
/// Adds a new style to the styles collection.
/// </summary>
/// <param name="name">Name of the style.</param>
/// <param name="baseStyleName">Name of the base style.</param>
public Style AddStyle(string name, string baseStyleName)
{
if (name == null || baseStyleName == null)
throw new ArgumentNullException(name == null ? "name" : "baseStyleName");
if (name == "" || baseStyleName == "")
throw new ArgumentException(name == "" ? "name" : "baseStyleName");
Style style = new Style();
style._name.Value = name;
style._baseStyle.Value = baseStyleName;
Add(style);
// Add(style) may add a clone of style, therefore we return the style by name.
return this[name];
}
/// <summary>
/// Adds a DocumentObject to the styles collection. Will sometimes add a clone of the DocumentObject, not the object passed as parameter.
/// </summary>
public override void Add(DocumentObject value)
{
if (value == null)
throw new ArgumentNullException("value");
Style style = value as Style;
if (style == null)
throw new InvalidOperationException(DomSR.StyleExpected);
bool isRootStyle = style.IsRootStyle;
if (style.BaseStyle == "" && !isRootStyle)
throw new ArgumentException(DomSR.UndefinedBaseStyle(style.BaseStyle));
Style baseStyle = null;
int styleIndex = GetIndex(style.BaseStyle);
if (styleIndex != -1)
baseStyle = this[styleIndex] as Style;
else if (!isRootStyle)
throw new ArgumentException(DomSR.UndefinedBaseStyle(style.BaseStyle));
if (baseStyle != null)
style._styleType.Value = (int)baseStyle.Type;
int index = GetIndex(style.Name);
if (index >= 0)
{
// Here a clone of the object will be added to the list, not the original object.
style = style.Clone();
style._parent = this;
((IList)this)[index] = style;
}
else
base.Add(value);
}
#endregion
#region Properties
/// <summary>
/// Gets the default paragraph style.
/// </summary>
public Style Normal
{
get { return this[Style.DefaultParagraphName]; }
}
/// <summary>
/// Gets or sets a comment associated with this object.
/// </summary>
public string Comment
{
get { return _comment.Value; }
set { _comment.Value = value; }
}
[DV]
public NString _comment = NString.NullValue;
#endregion
/// <summary>
/// Initialize the built-in styles.
/// </summary>
public void SetupStyles()
{
Style style;
// First standard style.
style = new Style(Style.DefaultParagraphFontName, null);
style.IsReadOnly = true;
style._styleType.Value = (int)StyleType.Character;
style._buildIn.Value = true;
Add(style);
// Normal 'Standard' (Paragraph Style).
style = new Style(Style.DefaultParagraphName, null);
style._styleType.Value = (int)StyleType.Paragraph;
style._buildIn.Value = true;
style.Font.Name = "Arial"; // Not "Verdana" anymore.
style.Font.Size = 10;
style.Font.Bold = false;
style.Font.Italic = false;
style.Font.Underline = Underline.None;
style.Font.Color = Colors.Black;
style.Font.Subscript = false;
style.Font.Superscript = false;
style.ParagraphFormat.Alignment = ParagraphAlignment.Left;
style.ParagraphFormat.FirstLineIndent = 0;
style.ParagraphFormat.LeftIndent = 0;
style.ParagraphFormat.RightIndent = 0;
style.ParagraphFormat.KeepTogether = false;
style.ParagraphFormat.KeepWithNext = false;
style.ParagraphFormat.SpaceBefore = 0;
style.ParagraphFormat.SpaceAfter = 0;
style.ParagraphFormat.LineSpacing = 10;
style.ParagraphFormat.LineSpacingRule = LineSpacingRule.Single;
style.ParagraphFormat.OutlineLevel = OutlineLevel.BodyText;
style.ParagraphFormat.PageBreakBefore = false;
style.ParagraphFormat.WidowControl = true;
Add(style);
// Heading1 '<27>berschrift 1' (Paragraph Style).
style = new Style(StyleNames.Heading1, StyleNames.Normal);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level1;
Add(style);
// Heading2 '<27>berschrift 2' (Paragraph Style).
style = new Style(StyleNames.Heading2, StyleNames.Heading1);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level2;
Add(style);
// Heading3 '<27>berschrift 3' (Paragraph Style).
style = new Style(StyleNames.Heading3, StyleNames.Heading2);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level3;
Add(style);
// Heading4 '<27>berschrift 4' (Paragraph Style).
style = new Style(StyleNames.Heading4, StyleNames.Heading3);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level4;
Add(style);
// Heading5 '<27>berschrift 5' (Paragraph Style).
style = new Style(StyleNames.Heading5, StyleNames.Heading4);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level5;
Add(style);
// Heading6 '<27>berschrift 6' (Paragraph Style).
style = new Style(StyleNames.Heading6, StyleNames.Heading5);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level6;
Add(style);
// Heading7 '<27>berschrift 7' (Paragraph Style).
style = new Style(StyleNames.Heading7, StyleNames.Heading6);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level7;
Add(style);
// Heading8 '<27>berschrift 8' (Paragraph Style).
style = new Style(StyleNames.Heading8, StyleNames.Heading7);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level8;
Add(style);
// Heading9 '<27>berschrift 9' (Paragraph Style).
style = new Style(StyleNames.Heading9, StyleNames.Heading8);
style._buildIn.Value = true;
style.ParagraphFormat.OutlineLevel = OutlineLevel.Level9;
Add(style);
// List 'Liste' (Paragraph Style).
style = new Style(StyleNames.List, StyleNames.Normal);
style._buildIn.Value = true;
Add(style);
// Footnote 'Fu<46>note' (Paragraph Style).
style = new Style(StyleNames.Footnote, StyleNames.Normal);
style._buildIn.Value = true;
Add(style);
// Header 'Kopfzeile' (Paragraph Style).
style = new Style(StyleNames.Header, StyleNames.Normal);
style._buildIn.Value = true;
Add(style);
// -33: Footer 'Fu<46>zeile' (Paragraph Style).
style = new Style(StyleNames.Footer, StyleNames.Normal);
style._buildIn.Value = true;
Add(style);
// Hyperlink 'Hyperlink' (Character Style).
style = new Style(StyleNames.Hyperlink, StyleNames.DefaultParagraphFont);
style._buildIn.Value = true;
Add(style);
// InvalidStyleName 'Ung<6E>ltiger Formatvorlagenname' (Paragraph Style).
style = new Style(StyleNames.InvalidStyleName, StyleNames.Normal);
style._buildIn.Value = true;
style.Font.Bold = true;
style.Font.Underline = Underline.Dash;
style.Font.Color = new Color(0xFF00FF00);
Add(style);
}
#region public
/// <summary>
/// Converts Styles into DDL.
/// </summary>
public override void Serialize(Serializer serializer)
{
serializer.WriteComment(_comment.Value);
int pos = serializer.BeginContent("\\styles");
// A style can only be added to Styles if its base style exists. Therefore the
// styles collection is consistent at any one time by definition. But because it
// is possible to change the base style of a style, the sequence of the styles
// in the styles collection can be in an order that a style comes before its base
// style. The styles in an DDL file must be ordered such that each style appears
// after its base style. We cannot simply reorder the styles collection, because
// the predefined styles are expected at a fixed position.
// The solution is to reorder the styles during serialization.
int count = Count;
bool[] fSerialized = new bool[count]; // already serialized
fSerialized[0] = true; // consider DefaultParagraphFont as serialized
bool[] fSerializePending = new bool[count]; // currently serializing
bool newLine = false; // gets true if at least one style was written
//Start from 1 and do not serialize DefaultParagraphFont
for (int index = 1; index < count; index++)
{
if (!fSerialized[index])
{
Style style = this[index];
SerializeStyle(serializer, index, ref fSerialized, ref fSerializePending, ref newLine);
}
}
serializer.EndContent(pos);
}
/// <summary>
/// Serialize a style, but serialize its base style first (if that was not yet done).
/// </summary>
void SerializeStyle(Serializer serializer, int index, ref bool[] fSerialized, ref bool[] fSerializePending,
ref bool newLine)
{
Style style = this[index];
// It is not possible to modify the default paragraph font
if (style.Name == Style.DefaultParagraphFontName)
return;
// Circular dependencies cannot occur if changing the base style is implemented
// correctly. But before we proof that, we check it here.
if (fSerializePending[index])
{
string message = String.Format("Circular dependency detected according to style '{0}'.", style.Name);
throw new InvalidOperationException(message);
}
// Only style 'Normal' has no base style
if (style.BaseStyle != "")
{
int idxBaseStyle = GetIndex(style.BaseStyle);
if (idxBaseStyle != -1)
{
if (!fSerialized[idxBaseStyle])
{
fSerializePending[index] = true;
SerializeStyle(serializer, idxBaseStyle, ref fSerialized, ref fSerializePending, ref newLine);
fSerializePending[index] = false;
}
}
}
int pos2 = serializer.BeginBlock();
if (newLine)
serializer.WriteLineNoCommit();
style.Serialize(serializer);
if (serializer.EndBlock(pos2))
newLine = true;
fSerialized[index] = true;
}
/// <summary>
/// Allows the visitor object to visit the document object and its child objects.
/// </summary>
void IVisitable.AcceptVisitor(DocumentObjectVisitor visitor, bool visitChildren)
{
visitor.VisitStyles(this);
Dictionary<Style, object> visitedStyles = new Dictionary<Style, object>();
foreach (Style style in this)
VisitStyle(visitedStyles, style, visitor, visitChildren);
}
/// <summary>
/// Ensures that base styles are visited first.
/// </summary>
void VisitStyle(Dictionary<Style, object> visitedStyles, Style style, DocumentObjectVisitor visitor, bool visitChildren)
{
if (!visitedStyles.ContainsKey(style))
{
Style baseStyle = style.GetBaseStyle();
if (baseStyle != null && !visitedStyles.ContainsKey(baseStyle)) //baseStyle != ""
VisitStyle(visitedStyles, baseStyle, visitor, visitChildren);
((IVisitable)style).AcceptVisitor(visitor, visitChildren);
visitedStyles.Add(style, null);
}
}
public static readonly Styles BuildInStyles = new Styles();
/// <summary>
/// Returns the meta object of this instance.
/// </summary>
public override Meta Meta
{
get { return _meta ?? (_meta = new Meta(typeof(Styles))); }
}
static Meta _meta;
#endregion
}
}