File: System\Windows\Documents\FixedElement.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\PresentationFramework\PresentationFramework.csproj (PresentationFramework)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
using MS.Internal.Documents;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Markup;    // for XmlLanguage
using System.Windows.Navigation;
using System.Globalization;
using System.Text;
 
//
// Description:
//      FixedElement represents a flow element/object in the Fixed Document.
//
 
namespace System.Windows.Documents
{
    /// <summary>
    /// FixedElement represents a flow element/object in the Fixed Document.
    /// Its children collection is used for DependencyProperty evaluation.
    /// No Z-order is implied!
    /// </summary>
    // suggestion: derive from TextElement to get text properties like FontSize
    // will we also need TableCell.ColumnSpan?  Would we want to make this derive from TableCell?  Probably not.
    internal sealed class FixedElement : DependencyObject
    {
        internal enum ElementType
        {
            Paragraph,
            Inline,
            Run,
            Span,
            Bold,
            Italic,
            Underline,
            Object,
            Container,
            Section,
            Figure,
            Table,
            TableRowGroup,
            TableRow,
            TableCell,
            List,
            ListItem,
            Header,
            Footer,
            Hyperlink,
            InlineUIContainer,
        }
 
        // apply to everything
        public static readonly DependencyProperty LanguageProperty =
                    FrameworkElement.LanguageProperty.AddOwner(
                                typeof(FixedElement));
 
        // only apply to ElementType.Run
        public static readonly DependencyProperty FontFamilyProperty =
                    TextElement.FontFamilyProperty.AddOwner(
                                typeof(FixedElement));
 
        public static readonly DependencyProperty FontStyleProperty =
                    TextElement.FontStyleProperty.AddOwner(
                                typeof(FixedElement));
 
        public static readonly DependencyProperty FontWeightProperty =
                    TextElement.FontWeightProperty.AddOwner(
                                typeof(FixedElement));
 
        public static readonly DependencyProperty FontStretchProperty =
                    TextElement.FontStretchProperty.AddOwner(
                                typeof(FixedElement));
 
        public static readonly DependencyProperty FontSizeProperty =
                    TextElement.FontSizeProperty.AddOwner(
                                typeof(FixedElement));
 
        public static readonly DependencyProperty ForegroundProperty =
                    TextElement.ForegroundProperty.AddOwner(
                                typeof(FixedElement));
 
        public static readonly DependencyProperty FlowDirectionProperty =
                    FrameworkElement.FlowDirectionProperty.AddOwner(
                                typeof(FixedElement));
 
 
 
        //Applies only to Table
        public static readonly DependencyProperty CellSpacingProperty =
                    Table.CellSpacingProperty.AddOwner(
                                typeof(FixedElement));
 
 
        //Applies only to TableCell
        public static readonly DependencyProperty BorderThicknessProperty =
                    Block.BorderThicknessProperty.AddOwner(typeof(FixedElement));
 
        public static readonly DependencyProperty BorderBrushProperty =
                    Block.BorderBrushProperty.AddOwner(typeof(FixedElement));
 
        public static readonly DependencyProperty ColumnSpanProperty =
                    TableCell.ColumnSpanProperty.AddOwner(typeof(FixedElement));
 
        //Applies only to Hyperlink
        public static readonly DependencyProperty NavigateUriProperty =
            Hyperlink.NavigateUriProperty.AddOwner(
                        typeof(FixedElement));
 
        //Applies only to images
        public static readonly DependencyProperty NameProperty =
            AutomationProperties.NameProperty.AddOwner(
                        typeof(FixedElement));
 
        public static readonly DependencyProperty HelpTextProperty =
            AutomationProperties.HelpTextProperty.AddOwner(
                        typeof(FixedElement));
 
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
        #region Constructors
        // Ctor always set mutable flag to false
        internal FixedElement(ElementType type, FixedTextPointer start, FixedTextPointer end, int pageIndex)
        {
            _type = type;
#if DEBUG
            if (_type == ElementType.Object) // is EmbeddedObject
            {
                Debug.Assert((object)_start == (object)_end);
            }
            _children = new List<FixedElement>();
#endif
            _start = start;
            _end = end;
            _pageIndex = pageIndex;
        }
 
        #endregion Constructors
 
 
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
 
#if DEBUG
        /// <summary>
        /// Create a string representation of this object
        /// </summary>
        /// <returns>string - A string representation of this object</returns>
        public override string ToString()
        {
            return string.Create(CultureInfo.InvariantCulture, $"{{S@{_start}---E@{_end}}} {System.Enum.GetName(_type)}");
        }
#endif
 
        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------
 
        //------------------------------------------------------
        //
        //  Public Events
        //
        //------------------------------------------------------
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        // Method to allow append of element
        // Note element order doesn't imply Z-order in this implementation!
        internal void Append(FixedElement e)
        {
#if DEBUG
            _children.Add(e);
#endif
            if (_type == ElementType.InlineUIContainer)
            {
                Debug.Assert(_object == null && e._type == ElementType.Object);
                _object = e._object; // To generate InlineUIContainer with child with object;
            }
        }
 
        internal object GetObject()
        {
            if (_type == ElementType.Hyperlink || _type == ElementType.Paragraph ||
                (_type >= ElementType.Table && _type <= ElementType.TableCell))
            {
                if (_object == null)
                {
                    _object = BuildObjectTree();
                }
                return _object;
            }
 
            if (!(_type == ElementType.Object || _type == ElementType.InlineUIContainer))
            {
                // This is currently not implemented for any other type
                return null;
            }
 
            Image im = GetImage();
            object o = im;
            if (_type == ElementType.InlineUIContainer)
            {
                InlineUIContainer c = new InlineUIContainer();
                c.Child = im;
                o = c;
            }
            return o;
        }
 
        internal object BuildObjectTree()
        {
            IAddChild root;
            switch (_type)
            {
                case ElementType.Table:
                    root = new Table();
                    break;
                case ElementType.TableRowGroup:
                    root = new TableRowGroup();
                    break;
                case ElementType.TableRow:
                    root = new TableRow();
                    break;
                case ElementType.TableCell:
                    root = new TableCell();
                    break;
                case ElementType.Paragraph:
                    root = new Paragraph();
                    break;
                case ElementType.Hyperlink:
                    Hyperlink link = new Hyperlink();
                    link.NavigateUri = GetValue(NavigateUriProperty) as Uri;
                    link.RequestNavigate += new RequestNavigateEventHandler(ClickHyperlink);
                    AutomationProperties.SetHelpText(link, (String)this.GetValue(HelpTextProperty));
                    AutomationProperties.SetName(link, (String)this.GetValue(NameProperty));
                    root = link;
                    break;
                default:
                    Debug.Assert(false);
                    root = null;
                    break;
            }
 
            ITextPointer pos = ((ITextPointer)_start).CreatePointer();
 
            while (pos.CompareTo((ITextPointer)_end) < 0)
            {
                TextPointerContext tpc = pos.GetPointerContext(LogicalDirection.Forward);
                if (tpc == TextPointerContext.Text)
                {
                    root.AddText(pos.GetTextInRun(LogicalDirection.Forward));
                }
                else if (tpc == TextPointerContext.EmbeddedElement)
                {
                    root.AddChild(pos.GetAdjacentElement(LogicalDirection.Forward));
                }
                else if (tpc == TextPointerContext.ElementStart)
                {
                    object obj = pos.GetAdjacentElement(LogicalDirection.Forward);
                    if (obj != null)
                    {
                        root.AddChild(obj);
                        pos.MoveToNextContextPosition(LogicalDirection.Forward);
                        pos.MoveToElementEdge(ElementEdge.BeforeEnd);
                    }
                }
 
                pos.MoveToNextContextPosition(LogicalDirection.Forward);
            }
            return root;
        }
 
        private Image GetImage()
        {
            Image image = null; // return value
            Uri source = _object as Uri;
            if (source != null)
            {
                image = new Image();
                image.Source = new System.Windows.Media.Imaging.BitmapImage(source);
                image.Width = image.Source.Width;
                image.Height = image.Source.Height;
 
                AutomationProperties.SetName(image, (String)this.GetValue(NameProperty));
                AutomationProperties.SetHelpText(image, (String)this.GetValue(HelpTextProperty));
            }
            return image;
        }
 
        private void ClickHyperlink(Object sender, RequestNavigateEventArgs args)
        {
            FixedDocument doc = _start.FixedTextContainer.FixedDocument;
            int pageno = doc.GetPageNumber(_start);
            FixedPage page = doc.SyncGetPage(pageno, false);
 
            //have page raise click event
            Hyperlink.RaiseNavigate(page, args.Uri, null);
        }
 
        #endregion Internal Methods
 
#if DEBUG
        internal void Dump()
        {
            DumpTree(0);
        }
 
        internal void DumpTree(int indent)
        {
            if (DocumentsTrace.FixedTextOM.Map.IsEnabled)
            {
                StringBuilder dp = new StringBuilder();
 
                dp.Append("\r\n");
                for (int kk = 0; kk < indent; kk++)
                {
                    dp.Append("    ");
                }
                dp.Append(this.ToString());
                for(int i = 0, n = _children.Count; i < n; i++)
                {
                    ((FixedElement)_children[i]).DumpTree(indent+1);
                }
 
                DocumentsTrace.FixedTextOM.Map.Trace(dp.ToString());
            }
        }
#endif
        //------------------------------------------------------
        //
        //  Internal Properties
        //
        //------------------------------------------------------
 
        #region Internal Properties
        internal bool IsTextElement
        {
            get
            {
                return ! (_type == ElementType.Object
                    || _type == ElementType.Container);
            }
        }
 
        internal Type Type
        {
            get
            {
                switch (_type)
                {
                    case ElementType.Paragraph:
                        return typeof(Paragraph);
 
                    case ElementType.Inline:
                        return typeof(Inline);
 
                    case ElementType.Run:
                        return typeof(Run);
 
                    case ElementType.Span:
                        return typeof(Span);
 
                    case ElementType.Bold:
                        return typeof(Bold);
 
                    case ElementType.Italic:
                        return typeof(Italic);
 
                    case ElementType.Underline:
                        return typeof(Underline);
 
                    case ElementType.Object:
                        return typeof(Object);
 
                    case ElementType.Table:
                        return typeof(Table);
 
                    case ElementType.TableRowGroup:
                        return typeof(TableRowGroup);
 
                    case ElementType.TableRow:
                        return typeof(TableRow);
 
                    case ElementType.TableCell:
                        return typeof(TableCell);
 
                    case ElementType.List:
                        return typeof(List);
 
                    case ElementType.ListItem:
                        return typeof(ListItem);
 
                    case ElementType.Section:
                        return typeof(Section);
 
                    case ElementType.Figure:
                        return typeof(Figure);
 
                    case ElementType.Hyperlink:
                        return typeof(Hyperlink);
 
                    case ElementType.InlineUIContainer:
                        return typeof(InlineUIContainer);
                    default:
                        return typeof(Object);
                }
            }
        }
 
        internal FixedTextPointer Start
        {
            get { return _start; }
        }
 
 
        internal FixedTextPointer End
        {
            get { return _end; }
        }
 
        internal int PageIndex
        {
            get { return _pageIndex; }
        }
 
        internal object Object
        {
            set { _object = value; }
        }
        #endregion Internal Properties
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
        #region Private Fields
#if DEBUG
        private List<FixedElement>      _children;
#endif
        private ElementType  _type;             // logical type that this element represents
        private FixedTextPointer  _start;      // start position for this element
        private FixedTextPointer  _end;        // end position for this element
        private object _object;                 // embedded object
        private int _pageIndex;
        #endregion Private Fields
    }
}