#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 { /// /// Represents style templates for paragraph or character formatting. /// public sealed class Style : DocumentObject, IVisitable { /// /// Initializes a new instance of the Style class. /// public Style() { } /// /// Initializes a new instance of the Style class with the specified parent. /// public Style(DocumentObject parent) : base(parent) { } /// /// Initializes a new instance of the Style class with name and base style name. /// 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; } /// /// Creates a deep copy of this object. /// public new Style Clone() { return (Style)DeepCopy(); } /// /// Implements the deep copy of the object. /// protected override object DeepCopy() { Style style = (Style)base.DeepCopy(); if (style._paragraphFormat != null) { style._paragraphFormat = style._paragraphFormat.Clone(); style._paragraphFormat._parent = style; } return style; } /// /// Returns the value with the specified name and value access. /// 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 /// /// Indicates whether the style is read-only. /// public bool IsReadOnly { get; set; } /// /// Gets the font of ParagraphFormat. /// Calling style.Font is just a shortcut to style.ParagraphFormat.Font. /// [DV] public Font Font { get { return ParagraphFormat.Font; } // SetParent will be called inside ParagraphFormat. set { ParagraphFormat.Font = value; } } /// /// Gets the name of the style. /// public string Name { get { return _name.Value; } } [DV] public NString _name = NString.NullValue; /// /// Gets the ParagraphFormat. To prevent read-only styles from being modified, a copy of its ParagraphFormat /// is returned in this case. /// 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; /// /// Gets or sets the name of the base style. /// 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; /// /// Gets the StyleType of the style. /// 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)); /// /// Determines whether the style is the style Normal or DefaultParagraphFont. /// public bool IsRootStyle { get { return String.Compare(Name, DefaultParagraphFontName, StringComparison.OrdinalIgnoreCase) == 0 || String.Compare(Name, DefaultParagraphName, StringComparison.OrdinalIgnoreCase) == 0; } } /// /// Get the BaseStyle of the current style. /// 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üppelig(DefaultParagraphFont wird bei Zugriff über styles["name"] nicht zurückgeliefert). if (_baseStyle.Value == DefaultParagraphFontName) return styles[0]; return styles[_baseStyle.Value]; } /// /// Indicates whether the style is a predefined (build in) style. /// public bool BuildIn { get { return _buildIn.Value; } } [DV] public NBool _buildIn = NBool.NullValue; // TODO: rename to builtIn. /// /// Gets or sets a comment associated with this object. /// 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. /// /// Name of the default character style. /// public const string DefaultParagraphFontName = StyleNames.DefaultParagraphFont; /// /// Name of the default paragraph style. /// public const string DefaultParagraphName = StyleNames.Normal; #region public /// /// Converts Style into DDL. /// 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(); } /// /// Sets all properties to Null that have the same value as the base style. /// private void Optimize() { // just here as a reminder to do it... } /// /// Allows the visitor object to visit the document object and its child objects. /// void IVisitable.AcceptVisitor(DocumentObjectVisitor visitor, bool visitChildren) { visitor.VisitStyle(this); } /// /// Returns the meta object of this instance. /// public override Meta Meta { get { return _meta ?? (_meta = new Meta(typeof(Style))); } } static Meta _meta; #endregion } }