Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Documents / DocumentSequence.cs / 1 / DocumentSequence.cs
//----------------------------------------------------------------------------
//
// Copyright (C) 2004 by Microsoft Corporation. All rights reserved.
//
//
// Description:
// Implements the FixedDocumentSequence element
//
// History:
// 05/05/2004 - Zhenbin Xu (ZhenbinX) - Created.
//
//
//---------------------------------------------------------------------------
using MS.Internal.Documents;
using MS.Utility; // ExceptionStringTable
using System.Collections;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Windows.Automation.Peers; // AutomationPeer
using System.Windows.Threading; // Dispatcher
using System.Windows; // DependencyID etc.
using System.Windows.Media; // Visual
using System.Windows.Markup; // IAddChild, ContentProperty
using System.Windows.Navigation;
#pragma warning disable 1634, 1691 // suppressing PreSharp warnings
namespace System.Windows.Documents
{
///
/// FixedDocumentSequence is a IDocumentPaginatorSource that composites other IDocumentPaginatorSource
/// via DocumentReference
///
[ContentProperty("References")]
public class FixedDocumentSequence : FrameworkContentElement, IDocumentPaginatorSource, IAddChildInternal, IServiceProvider, IFixedNavigate, IUriContext
{
//-------------------------------------------------------------------
//
// Connstructors
//
//---------------------------------------------------------------------
#region Constructors
static FixedDocumentSequence()
{
FocusableProperty.OverrideMetadata(typeof(FixedDocumentSequence), new FrameworkPropertyMetadata(true));
}
///
/// Default FixedDocumentSequence constructor
///
public FixedDocumentSequence() : base()
{
_Init();
}
#endregion Constructors
//--------------------------------------------------------------------
//
// Public Methods
//
//---------------------------------------------------------------------
#region IServiceProvider Members
///
///
///
object IServiceProvider.GetService(Type serviceType)
{
if (serviceType == null)
{
throw new ArgumentNullException("serviceType");
}
if (serviceType == typeof(ITextContainer))
{
return this.TextContainer;
}
if (serviceType == typeof(RubberbandSelector))
{
// create this on demand, but not through the property, only through the
// service, so it is only created when it's actually used
if (_rubberbandSelector == null)
{
_rubberbandSelector = new RubberbandSelector();
}
return _rubberbandSelector;
}
return null;
}
#endregion IServiceProvider Members
#region IAddChild
///
/// Called to Add the object as a Child.
///
///
/// Object to add as a child
///
void IAddChild.AddChild(Object value)
{
if (value == null)
{
throw new ArgumentNullException("value");
}
// Dispatcher.VerifyAccess();
DocumentReference docRef = value as DocumentReference;
if (docRef == null)
{
throw new ArgumentException(SR.Get(SRID.UnexpectedParameterType, value.GetType(), typeof(DocumentReference)), "value");
}
if (docRef.IsInitialized)
{
_references.Add(docRef);
}
else
{
DocumentsTrace.FixedDocumentSequence.Content.Trace(string.Format("Doc {0} Deferred", _references.Count));
if (_partialRef == null)
{
_partialRef = docRef;
_partialRef.Initialized += new EventHandler(_OnDocumentReferenceInitialized);
}
else
{
throw new InvalidOperationException(SR.Get(SRID.PrevoiusUninitializedDocumentReferenceOutstanding));
}
}
}
///
/// Called when text appears under the tag in markup
///
///
/// Text to Add to the Object
///
void IAddChild.AddText(string text)
{
XamlSerializerUtil.ThrowIfNonWhiteSpaceInAddText(text, this);
}
#endregion
#region IFixedNavigate
void IFixedNavigate.NavigateAsync(string elementID)
{
if (IsPageCountValid == true)
{
FixedHyperLink.NavigateToElement(this, elementID);
}
else
{
_navigateAfterPagination = true;
_navigateFragment = elementID;
}
}
UIElement IFixedNavigate.FindElementByID(string elementID, out FixedPage rootFixedPage)
{
UIElement uiElementRet = null;
rootFixedPage = null;
DynamicDocumentPaginator childPaginator;
FixedDocument childFixedDoc;
if (Char.IsDigit(elementID[0]))
{
//We convert to a page number here.
int pageNumber = Convert.ToInt32(elementID, CultureInfo.InvariantCulture) - 1;
int childPageNumber;
if (TranslatePageNumber(pageNumber, out childPaginator, out childPageNumber))
{
childFixedDoc = childPaginator.Source as FixedDocument;
if (childFixedDoc != null)
{
uiElementRet = childFixedDoc.GetFixedPage(childPageNumber);
}
}
}
else
{
foreach (DocumentReference docRef in References)
{
childPaginator = GetPaginator(docRef);
childFixedDoc = childPaginator.Source as FixedDocument;
if (childFixedDoc != null)
{
uiElementRet = ((IFixedNavigate)childFixedDoc).FindElementByID(elementID, out rootFixedPage);
if (uiElementRet != null)
{
break;
}
}
}
}
return uiElementRet;
}
#endregion
#region LogicalTree
///
/// Returns enumerator to logical children
///
protected internal override IEnumerator LogicalChildren
{
get
{
// Dispatcher.VerifyAccess();
DocumentReference[] docArray = new DocumentReference[_references.Count];
this._references.CopyTo(docArray, 0);
return docArray.GetEnumerator();
}
}
#endregion LogicalTree
#region IDocumentPaginatorSource Members
///
/// An object which paginates content.
///
public DocumentPaginator DocumentPaginator
{
get { return _paginator; }
}
#endregion IDocumentPaginatorSource Members
#region DocumentPaginator
///
///
///
internal DocumentPage GetPage(int pageNumber)
{
DocumentsTrace.FixedFormat.IDF.Trace(string.Format("IDP.GetPage({0})", pageNumber));
// Make sure that the call is in the right context.
// Dispatcher.VerifyAccess();
// Page number cannot be negative.
if (pageNumber < 0)
{
throw new ArgumentOutOfRangeException("pageNumber", SR.Get(SRID.IDPNegativePageNumber));
}
DocumentPage innerDP = null;
DynamicDocumentPaginator innerPaginator;
int innerPageNumber;
// Find the appropriate inner IDF and BR
if (TranslatePageNumber(pageNumber, out innerPaginator, out innerPageNumber))
{
innerDP = innerPaginator.GetPage(innerPageNumber);
Debug.Assert(innerDP != null);
// Now warp inner DP and return it
return new FixedDocumentSequenceDocumentPage(this, innerPaginator, innerDP);
}
return DocumentPage.Missing;
}
///
/// Returns a FixedDocumentSequenceDocumentPage for the specified document and page number.
///
internal DocumentPage GetPage(FixedDocument document, int fixedDocPageNumber)
{
if (fixedDocPageNumber < 0)
{
throw new ArgumentOutOfRangeException("fixedDocPageNumber", SR.Get(SRID.IDPNegativePageNumber));
}
if (document == null)
{
throw new ArgumentNullException("document");
}
DocumentPage innerDP = document.GetPage(fixedDocPageNumber);
Debug.Assert(innerDP != null);
// Now wrap inner DP and return it
return new FixedDocumentSequenceDocumentPage(this, document.DocumentPaginator as DynamicDocumentPaginator, innerDP);
}
///
///
///
internal void GetPageAsync(int pageNumber, object userState)
{
DocumentsTrace.FixedFormat.IDF.Trace(string.Format("IDP.GetPageAsync({0}, {1})", pageNumber, userState));
// Make sure that the call is in the right context.
// Dispatcher.VerifyAccess();
// Page number cannot be negative.
if (pageNumber < 0)
{
throw new ArgumentOutOfRangeException("pageNumber", SR.Get(SRID.IDPNegativePageNumber));
}
if (userState == null)
{
throw new ArgumentNullException("userState");
}
// Add to outstanding AsyncOp list
GetPageAsyncRequest asyncRequest = new GetPageAsyncRequest(new RequestedPage(pageNumber/*childPaginator, childPageNumber*/), userState);
_asyncOps[userState] = asyncRequest;
DispatcherOperationCallback queueTask = new DispatcherOperationCallback(_GetPageAsyncDelegate);
Dispatcher.BeginInvoke(DispatcherPriority.Background, queueTask, asyncRequest);
}
///
///
///
internal int GetPageNumber(ContentPosition contentPosition)
{
if (contentPosition == null)
{
throw new ArgumentNullException("contentPosition");
}
// ContentPosition may be only created by DynamicDocumentPaginator.GetObjectPosition or
// DynamicDocumentPaginator.GetPagePosition.
// Because of that we are expecting one of 2 types here.
DynamicDocumentPaginator childPaginator = null;
ContentPosition childContentPosition = null;
if (contentPosition is DocumentSequenceTextPointer)
{
DocumentSequenceTextPointer dsTextPointer = (DocumentSequenceTextPointer)contentPosition;
#pragma warning suppress 6506 // dsTextPointer is obviously not null
childPaginator = GetPaginator(dsTextPointer.ChildBlock.DocRef);
childContentPosition = dsTextPointer.ChildPointer as ContentPosition;
}
if (childContentPosition == null)
{
throw new ArgumentException(SR.Get(SRID.IDPInvalidContentPosition));
}
int childPageNumber = childPaginator.GetPageNumber(childContentPosition);
int pageNumber;
_SynthesizeGlobalPageNumber(childPaginator, childPageNumber, out pageNumber);
return pageNumber;
}
///
///
///
internal void CancelAsync(object userState)
{
DocumentsTrace.FixedFormat.IDF.Trace(string.Format("IDP.GetPageAsyncCancel([{0}])", userState));
if (userState == null)
{
throw new ArgumentNullException("userState");
}
if (_asyncOps.ContainsKey(userState))
{
GetPageAsyncRequest asyncRequest = _asyncOps[userState];
if (asyncRequest != null)
{
asyncRequest.Cancelled = true;
if (asyncRequest.Page.ChildPaginator != null)
{
asyncRequest.Page.ChildPaginator.CancelAsync(asyncRequest);
}
}
}
}
///
///
///
internal ContentPosition GetObjectPosition(Object o)
{
if (o == null)
{
throw new ArgumentNullException("o");
}
foreach (DocumentReference docRef in References)
{
DynamicDocumentPaginator childPaginator = GetPaginator(docRef);
if (childPaginator != null)
{
ContentPosition cp = childPaginator.GetObjectPosition(o);
if (cp != ContentPosition.Missing && (cp is ITextPointer))
{
ChildDocumentBlock childBlock = new ChildDocumentBlock(this.TextContainer, docRef);
return new DocumentSequenceTextPointer(childBlock, (ITextPointer)cp);
}
}
}
return ContentPosition.Missing;
}
///
///
///
internal ContentPosition GetPagePosition(DocumentPage page)
{
FixedDocumentSequenceDocumentPage docPage = page as FixedDocumentSequenceDocumentPage;
if (docPage == null)
{
return ContentPosition.Missing;
}
return docPage.ContentPosition;
}
///
///
///
internal bool IsPageCountValid
{
get
{
bool documentSequencePageCountFinal = true;
if (IsInitialized)
{
foreach (DocumentReference docRef in References)
{
DynamicDocumentPaginator paginator = GetPaginator(docRef);
if (paginator == null || !paginator.IsPageCountValid)
{
documentSequencePageCountFinal = false;
break;
}
}
}
else
{
documentSequencePageCountFinal = false;
}
return documentSequencePageCountFinal;
}
}
///
///
///
internal int PageCount
{
get
{
//
// This can be optimized if the page count for each IDP won't change
// && the list of IDP won't change. When each doc.IsPageCountValid is
// true, then page count won't change.
//
int count = 0;
foreach (DocumentReference docRef in References)
{
DynamicDocumentPaginator paginator = GetPaginator(docRef);
if (paginator != null)
{
count += paginator.PageCount;
if (!paginator.IsPageCountValid)
{
break;
}
}
}
return count;
}
}
///
///
///
internal Size PageSize
{
get { return _pageSize; }
set { _pageSize = value; }
}
#endregion DocumentPaginator
#region IUriContext
///
///
///
Uri IUriContext.BaseUri
{
get { return (Uri) GetValue(BaseUriHelper.BaseUriProperty); }
set { SetValue(BaseUriHelper.BaseUriProperty, value); }
}
#endregion
//-------------------------------------------------------------- ------
//
// Public Properties
//
//----------------------------------------------------------------------
#region Public Properties
///
/// Get a collection of DocumentReference that this FixedDocumentSequence contains.
///
[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content)]
[CLSCompliant(false)]
public DocumentReferenceCollection References
{
get
{
// Dispatcher.VerifyAccess();
return _references;
}
}
///
///
///
public static readonly DependencyProperty PrintTicketProperty
= DependencyProperty.RegisterAttached("PrintTicket", typeof(object), typeof(FixedDocumentSequence),
new FrameworkPropertyMetadata((object)null));
///
/// Get/Set PrintTicket Property
///
public object PrintTicket
{
get
{
object printTicket = GetValue(PrintTicketProperty);
return printTicket;
}
set
{
SetValue(PrintTicketProperty,value);
}
}
#endregion Public Properties
//-------------------------------------------------------------------
//
// Public Events
//
//----------------------------------------------------------------------
//-------------------------------------------------------------------
//
// Protected Methods
//
//---------------------------------------------------------------------
#region Protected Methods
///
/// Creates AutomationPeer ()
///
protected override AutomationPeer OnCreateAutomationPeer()
{
return new DocumentAutomationPeer(this);
}
#endregion Protected Methods
//-------------------------------------------------------------------
//
// Internal Methods
//
//----------------------------------------------------------------------
#region Internal Method
internal DynamicDocumentPaginator GetPaginator(DocumentReference docRef)
{
// #966803: Source change won't be a support scenario.
Debug.Assert(docRef != null);
DynamicDocumentPaginator paginator = null;
IDocumentPaginatorSource document = docRef.CurrentlyLoadedDoc;
if (document != null)
{
paginator = document.DocumentPaginator as DynamicDocumentPaginator;
Debug.Assert(paginator != null);
}
else
{
document = docRef.GetDocument(false /*forceReload*/);
if (document != null)
{
paginator = document.DocumentPaginator as DynamicDocumentPaginator;
Debug.Assert(paginator != null);
// hook up event handlers
paginator.PaginationCompleted += new EventHandler(_OnChildPaginationCompleted);
paginator.PaginationProgress += new PaginationProgressEventHandler(_OnChildPaginationProgress);
paginator.PagesChanged += new PagesChangedEventHandler(_OnChildPagesChanged);
}
}
return paginator;
}
//---------------------------------------------------------------------
// IDP Helper
//----------------------------------------------------------------------
// Take a global page number and translate it into a child paginator with a child page number.
// A document will be look at if the previous document has finished pagination.
internal bool TranslatePageNumber(int pageNumber, out DynamicDocumentPaginator childPaginator, out int childPageNumber)
{
childPaginator = null;
childPageNumber = 0;
foreach (DocumentReference docRef in References)
{
childPaginator = GetPaginator(docRef);
if (childPaginator != null)
{
childPageNumber = pageNumber;
if (childPaginator.PageCount > childPageNumber)
{
// The page falls inside this paginator.
return true;
}
else
{
if (!childPaginator.IsPageCountValid)
{
// Don't bother look further if this doc has not finished
// pagination
break;
}
pageNumber -= childPaginator.PageCount;
}
}
}
return false;
}
#endregion Internal Method
//--------------------------------------------------------------------
//
// Internal Properties
//
//---------------------------------------------------------------------
#region Internal Properties
internal DocumentSequenceTextContainer TextContainer
{
get
{
if (_textContainer == null)
{
_textContainer = new DocumentSequenceTextContainer(this);
}
return _textContainer;
}
}
#endregion Internal Properties
//--------------------------------------------------------------------
//
// Private Methods
//
//---------------------------------------------------------------------
#region Private Methods
private void _Init()
{
_paginator = new FixedDocumentSequencePaginator(this);
_references = new DocumentReferenceCollection();
_references.CollectionChanged += new NotifyCollectionChangedEventHandler(_OnCollectionChanged);
_asyncOps = new Dictionary