ASCU_ALL/PrintPDF/MigraDoc.DocumentObjectModel/DocumentObjectModel/Style.cs

453 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 MigraDoc.DocumentObjectModel.publics;
using MigraDoc.DocumentObjectModel.Visitors;
namespace MigraDoc.DocumentObjectModel
{
/// <summary>
/// Represents style templates for paragraph or character formatting.
/// </summary>
public sealed class Style : DocumentObject, IVisitable
{
/// <summary>
/// Initializes a new instance of the Style class.
/// </summary>
public Style()
{ }
/// <summary>
/// Initializes a new instance of the Style class with the specified parent.
/// </summary>
public Style(DocumentObject parent) : base(parent) { }
/// <summary>
/// Initializes a new instance of the Style class with name and base style name.
/// </summary>
public Style(string name, string baseStyleName)
: this()
{
// baseStyleName can be null or empty
if (name == null)
throw new ArgumentNullException("name");
if (name == "")
throw new ArgumentException("name");
_name.Value = name;
_baseStyle.Value = baseStyleName;
}
/// <summary>
/// Creates a deep copy of this object.
/// </summary>
public new Style Clone()
{
return (Style)DeepCopy();
}
/// <summary>
/// Implements the deep copy of the object.
/// </summary>
protected override object DeepCopy()
{
Style style = (Style)base.DeepCopy();
if (style._paragraphFormat != null)
{
style._paragraphFormat = style._paragraphFormat.Clone();
style._paragraphFormat._parent = style;
}
return style;
}
/// <summary>
/// Returns the value with the specified name and value access.
/// </summary>
public override object GetValue(string name, GV flags) //newStL
{
if (name == null)
throw new ArgumentNullException("name");
if (name == "")
throw new ArgumentException("name");
if (name.ToLower().StartsWith("font"))
return ParagraphFormat.GetValue(name);
return base.GetValue(name, flags);
}
#region Properties
/// <summary>
/// Indicates whether the style is read-only.
/// </summary>
public bool IsReadOnly { get; set; }
/// <summary>
/// Gets the font of ParagraphFormat.
/// Calling style.Font is just a shortcut to style.ParagraphFormat.Font.
/// </summary>
[DV]
public Font Font
{
get { return ParagraphFormat.Font; }
// SetParent will be called inside ParagraphFormat.
set { ParagraphFormat.Font = value; }
}
/// <summary>
/// Gets the name of the style.
/// </summary>
public string Name
{
get { return _name.Value; }
}
[DV]
public NString _name = NString.NullValue;
/// <summary>
/// Gets the ParagraphFormat. To prevent read-only styles from being modified, a copy of its ParagraphFormat
/// is returned in this case.
/// </summary>
public ParagraphFormat ParagraphFormat
{
get
{
if (_paragraphFormat == null)
_paragraphFormat = new ParagraphFormat(this);
if (IsReadOnly)
return _paragraphFormat.Clone();
return _paragraphFormat;
}
set
{
SetParent(value);
_paragraphFormat = value;
}
}
[DV]
public ParagraphFormat _paragraphFormat;
/// <summary>
/// Gets or sets the name of the base style.
/// </summary>
public string BaseStyle
{
get { return _baseStyle.Value; }
set
{
if (value == null || value == "" && _baseStyle.Value != "")
throw new ArgumentException(DomSR.EmptyBaseStyle);
// Self assignment is allowed
if (String.Compare(_baseStyle.Value, value, StringComparison.OrdinalIgnoreCase) == 0)
{
_baseStyle.Value = value; // character case may change...
return;
}
if (String.Compare(_name.Value, DefaultParagraphName, StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(_name.Value, DefaultParagraphFontName, StringComparison.OrdinalIgnoreCase) == 0)
{
string msg = String.Format("Style '{0}' has no base style and that cannot be altered.", _name);
throw new ArgumentException(msg);
}
Styles styles = (Styles)_parent;
// The base style must exists
int idxBaseStyle = styles.GetIndex(value);
if (idxBaseStyle == -1)
{
string msg = String.Format("Base style '{0}' does not exist.", value);
throw new ArgumentException(msg);
}
if (idxBaseStyle > 1)
{
// Is this style in the base style chain of the new base style
Style style = styles[idxBaseStyle] as Style;
while (style != null)
{
if (style == this)
{
string msg = String.Format("Base style '{0}' leads to a circular dependency.", value);
throw new ArgumentException(msg);
}
style = styles[style.BaseStyle];
}
}
// Now setting new base style is safe
_baseStyle.Value = value;
}
}
[DV]
public NString _baseStyle = NString.NullValue;
/// <summary>
/// Gets the StyleType of the style.
/// </summary>
public StyleType Type
{
get
{
//old
//if (IsNull("Type"))
//{
// if (String.Compare (this .baseStyle.Value, DefaultParagraphFontName, true) == 0)
// SetValue("Type", StyleType.Character);
// else
// {
// Style bsStyle = GetBaseStyle();
// if (bsStyle == null)
// throw new ArgumentException("User defined style has no valid base Style.");
//
// SetValue("Type", bsStyle.Type);
// }
//}
//return styleType;
if (_styleType.IsNull)
{
if (String.Compare(_baseStyle.Value, DefaultParagraphFontName, StringComparison.OrdinalIgnoreCase) == 0)
_styleType.Value = (int)StyleType.Character;
else
{
Style baseStyle = GetBaseStyle();
if (baseStyle == null)
throw new InvalidOperationException("User defined style has no valid base Style.");
_styleType.Value = (int)baseStyle.Type;
}
}
return (StyleType)_styleType.Value;
}
}
[DV(Type = typeof(StyleType))]
public NEnum _styleType = NEnum.NullValue(typeof(StyleType));
/// <summary>
/// Determines whether the style is the style Normal or DefaultParagraphFont.
/// </summary>
public bool IsRootStyle
{
get
{
return String.Compare(Name, DefaultParagraphFontName, StringComparison.OrdinalIgnoreCase) == 0 ||
String.Compare(Name, DefaultParagraphName, StringComparison.OrdinalIgnoreCase) == 0;
}
}
/// <summary>
/// Get the BaseStyle of the current style.
/// </summary>
public Style GetBaseStyle()
{
if (IsRootStyle)
return null;
Styles styles = Parent as Styles;
if (styles == null)
throw new InvalidOperationException("A parent object is required for this operation; access failed");
if (_baseStyle.Value == "")
throw new ArgumentException("User defined Style defined without a BaseStyle");
// TODO Remove German remarks!
//REVIEW KlPo4StLa Spezialbehandlung f<>r den DefaultParagraphFont kr<6B>ppelig(DefaultParagraphFont wird bei Zugriff <20>ber styles["name"] nicht zur<75>ckgeliefert).
if (_baseStyle.Value == DefaultParagraphFontName)
return styles[0];
return styles[_baseStyle.Value];
}
/// <summary>
/// Indicates whether the style is a predefined (build in) style.
/// </summary>
public bool BuildIn
{
get { return _buildIn.Value; }
}
[DV]
public NBool _buildIn = NBool.NullValue;
// TODO: rename to builtIn.
/// <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
// Names of the root styles. Root styles have no BaseStyle.
/// <summary>
/// Name of the default character style.
/// </summary>
public const string DefaultParagraphFontName = StyleNames.DefaultParagraphFont;
/// <summary>
/// Name of the default paragraph style.
/// </summary>
public const string DefaultParagraphName = StyleNames.Normal;
#region public
/// <summary>
/// Converts Style into DDL.
/// </summary>
public override void Serialize(Serializer serializer)
{
#if DEBUG_ // Test
if (Name == StyleNames.Heading1 || Name == StyleNames.Heading2)
Name.GetType();
#endif
// For build-in styles all properties that differ from their default values
// are serialized.
// For user-defined styles all non-null properties are serialized.
Styles buildInStyles = Styles.BuildInStyles;
Style refStyle = null;
Font refFont = null;
ParagraphFormat refFormat = null;
serializer.WriteComment(_comment.Value);
if (_buildIn.Value)
{
// BaseStyle is never null, but empty only for "Normal" and "DefaultParagraphFont"
if (BaseStyle == "")
{
// case: style is "Normal"
if (String.Compare(_name.Value, DefaultParagraphName, StringComparison.OrdinalIgnoreCase) != 0)
throw new ArgumentException("public Error: BaseStyle not set.");
refStyle = buildInStyles[buildInStyles.GetIndex(Name)];
refFormat = refStyle.ParagraphFormat;
refFont = refFormat.Font;
string name = DdlEncoder.QuoteIfNameContainsBlanks(Name);
serializer.WriteLineNoCommit(name);
}
else
{
// case: any build-in style except "Normal"
refStyle = buildInStyles[buildInStyles.GetIndex(Name)];
refFormat = refStyle.ParagraphFormat;
refFont = refFormat.Font;
if (String.Compare(BaseStyle, refStyle.BaseStyle, StringComparison.OrdinalIgnoreCase) == 0)
{
// case: build-in style with unmodified base style name
string name = DdlEncoder.QuoteIfNameContainsBlanks(Name);
serializer.WriteLineNoCommit(name);
// It's fine if we have the predefined base style, but ...
// ... the base style may have been modified or may even have a modified base style.
// Methinks it's wrong to compare with the built-in style, so let's compare with the
// real base style:
refStyle = Document.Styles[Document.Styles.GetIndex(_baseStyle.Value)];
refFormat = refStyle.ParagraphFormat;
refFont = refFormat.Font;
// Note: we must write "Underline = none" if the base style has "Underline = single" - we cannot
// detect this if we compare with the built-in style that has no underline.
// Known problem: Default values like "OutlineLevel = Level1" will now be serialized
// TODO: optimize...
}
else
{
// case: build-in style with modified base style name
string name = DdlEncoder.QuoteIfNameContainsBlanks(Name);
string baseName = DdlEncoder.QuoteIfNameContainsBlanks(BaseStyle);
serializer.WriteLine(name + " : " + baseName);
refStyle = Document.Styles[Document.Styles.GetIndex(_baseStyle.Value)];
refFormat = refStyle.ParagraphFormat;
refFont = refFormat.Font;
}
}
}
else
{
// case: user-defined style; base style always exists
string name = DdlEncoder.QuoteIfNameContainsBlanks(Name);
string baseName = DdlEncoder.QuoteIfNameContainsBlanks(BaseStyle);
serializer.WriteLine(name + " : " + baseName);
#if true
Style refStyle0 = Document.Styles[Document.Styles.GetIndex(_baseStyle.Value)];
refStyle = Document.Styles[_baseStyle.Value];
refFormat = refStyle != null ? refStyle.ParagraphFormat : null;
#else
refFormat = null;
#endif
}
serializer.BeginContent();
if (!IsNull("ParagraphFormat"))
{
if (!ParagraphFormat.IsNull("Font"))
Font.Serialize(serializer, refFormat != null ? refFormat.Font : null);
if (Type == StyleType.Paragraph)
ParagraphFormat.Serialize(serializer, "ParagraphFormat", refFormat);
}
serializer.EndContent();
}
/// <summary>
/// Sets all properties to Null that have the same value as the base style.
/// </summary>
private void Optimize()
{
// just here as a reminder to do it...
}
/// <summary>
/// Allows the visitor object to visit the document object and its child objects.
/// </summary>
void IVisitable.AcceptVisitor(DocumentObjectVisitor visitor, bool visitChildren)
{
visitor.VisitStyle(this);
}
/// <summary>
/// Returns the meta object of this instance.
/// </summary>
public override Meta Meta
{
get { return _meta ?? (_meta = new Meta(typeof(Style))); }
}
static Meta _meta;
#endregion
}
}