public void GetLastElement_OneElement() { IVwLayoutStream stream = VwLayoutStreamClass.Create(); using (DummyDivisionMgr division = new DummyDivisionMgr(stream, false)) { using (DummyPublication dummyPub = new DummyPublication(null, division, DateTime.Now)) { using (DummyPage page = new DummyPage(dummyPub)) { PageElement element = new PageElement(division, stream, false, new Rectangle(720, 1440, (int)(6.5 * 720), (int)(9 * 1440)), 0, true, 1, 1, 0, 9 * 1440, 0, false); page.PageElements.Add(element); int xd; PageElement lastElement = page.CallGetLastElement(division, out xd); Assert.AreEqual(element.LocationOnPage.Right, xd); Debug.WriteLine("GetLastElement_OneElement xd: " + xd); Assert.AreEqual(element, lastElement); } } } }
public void GetLastElement_TwoElementsRtoLStandard() { IVwLayoutStream stream = VwLayoutStreamClass.Create(); using (DummyDivisionMgr division = new DummyDivisionMgr(stream, true)) using (DummyPublication dummyPub = new DummyPublication(null, division, DateTime.Now)) using (DummyPage page = new DummyPage(dummyPub)) { PageElement leftColumnElement = new PageElement(division, stream, false, new Rectangle(0, 1440, (int)(3 * 720), (int)(5 * 1440)), 0, true, 1, 2, 0, 5 * 1440, 0, true); PageElement rightColumnElement = new PageElement(division, stream, false, new Rectangle(3 * 720 + 360, 1440, (int)(3 * 720), (int)(9 * 1440)), 0, true, 2, 2, 0, 9 * 1440, 0, true); page.PageElements.Add(leftColumnElement); page.PageElements.Add(rightColumnElement); int xd; PageElement lastElement = page.CallGetLastElement(division, out xd); Debug.WriteLine("GetLastElement_TwoElementsRtoLStandard xd: " + xd); Assert.AreEqual(leftColumnElement, lastElement, "The left-most column should be the last element in a right-to-left writing system"); Assert.AreEqual(0, xd); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Exposes the PageFromPrinterY method /// </summary> /// <param name="y">The y.</param> /// <param name="fUp">If the point is right at a page boundary, return the first /// page if this is true, the second if it is false.</param> /// <param name="strm">The STRM.</param> /// <param name="dyPageScreen">The dy page screen.</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public Page CallPageFromPrinterY(int y, bool fUp, IVwLayoutStream strm, out int dyPageScreen) { int iDiv; // not used in the tests return(PageFromPrinterY(0, y, fUp, strm, out dyPageScreen, out iDiv)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Configure a PublicationControl /// </summary> /// ------------------------------------------------------------------------------------ public void ConfigurePublication() { Dictionary <string, string> cacheOptions = new Dictionary <string, string>(); cacheOptions.Add("db", "TestLangProj"); m_fdoCache = FdoCache.Create(cacheOptions); // Make sure we don't call InstallLanguage during tests. m_fdoCache.LanguageWritingSystemFactoryAccessor.BypassInstall = true; if (m_pub != null) { m_pub.Dispose(); } m_division = new DummyDivision(new DummyHFPrintConfigurer(m_fdoCache), 1); Publication pub = new Publication(m_fdoCache, m_fdoCache.LangProject.TranslatedScriptureOA.PublicationsOC.HvoArray[0]); m_pub = new DummyPublication(pub, m_division, DateTime.Now); m_pub.Configure(); // Check initial state Assert.AreEqual(m_division, m_pub.Divisions[0]); IVwLayoutStream layoutStream = m_division.MainLayoutStream; Assert.IsNotNull(layoutStream); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Configure a PublicationControl /// </summary> /// <param name="fAddSubStream">if set to <c>true</c> add subordinate stream.</param> /// ------------------------------------------------------------------------------------ private void ConfigurePublication(bool fAddSubStream) { // When called for test setup, they will be null. // When called from within as test if (m_pub != null) { m_pub.Dispose(); } if (m_division != null) { m_division.Dispose(); } m_division = new DummyDivision(new DummyLazyPrintConfigurer(Cache, fAddSubStream), 1); Publication pub = new Publication(Cache, Cache.LangProject.TranslatedScriptureOA.PublicationsOC.HvoArray[0]); m_pub = new DummyPublication(pub, m_division, DateTime.Now); m_pub.Configure(); // Check initial state Assert.AreEqual(m_division, m_pub.Divisions[0]); Assert.IsNotNull(m_division.MainVc as DummyMainLazyViewVc); IVwLayoutStream layoutStream = m_division.MainLayoutStream; Assert.IsNotNull(layoutStream); m_pub.IsLeftBound = true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Configure a PublicationControl /// </summary> /// <param name="fAddSubStream">if set to <c>true</c> add subordinate stream.</param> /// <param name="fAddContent">if set to <c>true</c> add real content, otherwise add /// rectangle for paragraph.</param> /// ------------------------------------------------------------------------------------ private void ConfigurePublication(bool fAddSubStream, bool fAddContent) { // When called for test setup, they will be null. // When called from within as test if (m_pub != null) m_pub.Dispose(); if (m_division != null) m_division.Dispose(); m_division = new DummyDivision(new DummyLazyPrintConfigurer(Cache, fAddSubStream, fAddContent), 2); IPublication pub = Cache.LangProject.TranslatedScriptureOA.PublicationsOC.ToArray()[0]; m_pub = new DummyPublication(pub, m_division, DateTime.Now); m_pub.Configure(); // Check initial state Assert.AreEqual(m_division, m_pub.Divisions[0]); Assert.IsNotNull(m_division.MainVc as DummyMainLazyViewVc); IVwLayoutStream layoutStream = m_division.MainLayoutStream; Assert.IsNotNull(layoutStream); m_pub.IsLeftBound = true; // Set up the publication m_pub.PageHeight = 72000 * 11; // 11 inches m_pub.PageWidth = (int)(72000 * 8.5); // 8.5 inches m_division.TopMargin = 36000; // Half inch m_division.BottomMargin = 18000; // Quarter inch m_division.InsideMargin = 9000; // 1/8 inch m_division.OutsideMargin = 4500; // 1/16 inch DummyMainLazyViewVc vc = m_division.MainVc as DummyMainLazyViewVc; vc.m_estBookHeight = 2000; vc.m_estSectionHeight = 2000; m_pub.Width = 3 * 96; // represents a window that is 3" wide at 96 DPI }
public void DeleteFootnoteSelection() { m_ScrPubCtrl.PageHeight = 432000; // 6 inches m_ScrPubCtrl.PageWidth = 288000; // 4 inches m_division.TopMargin = 18000; // Half inch m_division.BottomMargin = 18000; m_division.InsideMargin = 18000; m_division.OutsideMargin = 18000; m_ScrPubCtrl.Width = 4 * 96; // represents a window that is 4" wide at 96 DPI m_ScrPubCtrl.CreatePages(); List <Page> pagesToBeDrawn = m_ScrPubCtrl.PrepareToDrawPages(0, 2000); IVwLayoutStream layoutStream = m_division.MainLayoutStream; IVwRootBox rootbox = layoutStream as IVwRootBox; // Get number of footnotes in book. IScripture scr = m_fdoCache.LangProject.TranslatedScriptureOA; Assert.AreEqual(3, scr.ScriptureBooksOS.Count); ScrBook james = (ScrBook)m_fdoCache.LangProject.TranslatedScriptureOA.ScriptureBooksOS[1]; int numFootnotes = james.FootnotesOS.Count; // Select the first footnote in James. SelectionHelper selHelper = SelectRangeOfChars(rootbox, 2, 2, 3); // Delete the footnote marker selection. //m_footnoteView.OnKeyDown(new KeyEventArgs(Keys.Delete)); m_ScrPubCtrl.PressKey(new KeyEventArgs(Keys.Delete)); // Confirm that there is one less footnote in the book. Assert.AreEqual(numFootnotes - 1, james.FootnotesOS.Count); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Constructs a TePrintLayoutConfig to configure the main print layout /// </summary> /// <param name="cache">The cache.</param> /// <param name="styleSheet">The style sheet.</param> /// <param name="publication">The publication.</param> /// <param name="viewType">Type of the view.</param> /// <param name="filterInstance">the book filter instance in effect</param> /// <param name="printDateTime">printing date and time</param> /// <param name="fIntroDivision">set to <c>true</c> for a division that displays book /// title and introduction material, <c>false</c> for a division that displays main /// scripture text.</param> /// <param name="hvoBook">The hvo of the book.</param> /// <param name="sharedStream">A layout stream used for footnotes which is shared across /// multiple divisions</param> /// <param name="ws">The writing system to use for the back translation</param> /// ------------------------------------------------------------------------------------ public TeBtPrintLayoutConfig(FdoCache cache, IVwStylesheet styleSheet, IPublication publication, TeViewType viewType, int filterInstance, DateTime printDateTime, bool fIntroDivision, int hvoBook, IVwLayoutStream sharedStream, int ws) : base(cache, styleSheet, publication, viewType, filterInstance, printDateTime, fIntroDivision, hvoBook, sharedStream, ws) { }
/// ------------------------------------------------------------------------------------ /// <summary> /// Constructs a TePrintLayoutConfig to configure the main print layout /// </summary> /// <param name="cache">The cache.</param> /// <param name="styleSheet">The style sheet.</param> /// <param name="publication">The publication.</param> /// <param name="viewType">Type of the view.</param> /// <param name="filterInstance">the book filter instance in effect</param> /// <param name="printDateTime">printing date and time</param> /// <param name="hvoBook">The hvo of the book.</param> /// <param name="sharedStream">A layout stream used for footnotes which is shared across /// multiple divisions</param> /// <param name="ws">The writing system to use for the back translation</param> /// ------------------------------------------------------------------------------------ public TeBtPrintLayoutConfig(FdoCache cache, IVwStylesheet styleSheet, IPublication publication, TeViewType viewType, int filterInstance, DateTime printDateTime, int hvoBook, IVwLayoutStream sharedStream, int ws) : base(cache, styleSheet, publication, viewType, filterInstance, printDateTime, PrintLayoutPortion.AllContent, hvoBook, sharedStream, ws) { }
///// <summary>type of width for this page element across the page</summary> //internal readonly PageElementWidthType m_widthType; #endregion #region Constructor /// ------------------------------------------------------------------------------------ /// <summary> /// Constructor /// </summary> /// <param name="division">The division.</param> /// <param name="stream">The stream.</param> /// <param name="fPageElementOwnsStream">if set to <c>true</c> the page element owns /// the stream.</param> /// <param name="locationOnPage">The location on page.</param> /// <param name="dypOffsetToTopOfDataOnPage">The dyp offset to top of data on page.</param> /// <param name="fMainStream">set to <c>true</c> if <paramref name="stream"/> is the /// main stream of <paramref name="division"/>, otherwise <c>false</c>.</param> /// <param name="columnNumber">The column number of the page element (1-based)</param> /// <param name="totalColumns">The total number of columns on the page for this stream.</param> /// <param name="columnGap">The gap between the columns, which is used if there are two /// or more columns.</param> /// <param name="columnHeight">The height of the current column.</param> /// <param name="dypOverlapWithPreviousElement"></param> /// <param name="fInRightToLeftStream">if set to <c>true</c> the page element is in a /// right-to-left stream.</param> /// ------------------------------------------------------------------------------------ public PageElement(DivisionLayoutMgr division, IVwLayoutStream stream, bool fPageElementOwnsStream, Rectangle locationOnPage, int dypOffsetToTopOfDataOnPage, bool fMainStream, int columnNumber, int totalColumns, int columnGap, int columnHeight, int dypOverlapWithPreviousElement, bool fInRightToLeftStream) { m_division = division; m_stream = stream; m_fPageElementOwnsStream = fPageElementOwnsStream; m_locationOnPage = locationOnPage; m_dypOffsetToTopOfDataOnPage = dypOffsetToTopOfDataOnPage; m_fMainStream = fMainStream; m_column = columnNumber; m_totalColumns = totalColumns; m_fInRightToLeftStream = fInRightToLeftStream; m_columnGap = columnGap; m_columnHeight = columnHeight; m_dypOverlapWithPreviousElement = dypOverlapWithPreviousElement; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Constructs a TePrintLayoutConfig to configure the main print layout /// </summary> /// <param name="cache">The cache.</param> /// <param name="styleSheet">The style sheet.</param> /// <param name="publication">The publication.</param> /// <param name="viewType">Type of the view.</param> /// <param name="filterInstance">the book filter instance in effect</param> /// <param name="printDateTime">printing date and time</param> /// <param name="divisionPortion">portion of the book to be layed out in this division</param> /// <param name="hvoBook">The hvo of the book we're displaying.</param> /// <param name="sharedStream">A layout stream used for footnotes which is shared across /// multiple divisions</param> /// <param name="ws">The writing system to use for the view.</param> /// ------------------------------------------------------------------------------------ public TePrintLayoutConfig(FdoCache cache, IVwStylesheet styleSheet, IPublication publication, TeViewType viewType, int filterInstance, DateTime printDateTime, PrintLayoutPortion divisionPortion, int hvoBook, IVwLayoutStream sharedStream, int ws) { m_fdoCache = cache; m_scr = m_fdoCache.LangProject.TranslatedScriptureOA; m_styleSheet = styleSheet; m_pub = publication; m_viewType = viewType; m_bookFilterInstance = filterInstance; m_printDateTime = printDateTime; m_divisionPortion = divisionPortion; m_hvoBook = hvoBook; m_sharedStream = sharedStream; m_ws = ws; m_paraCounter = cache.ServiceLocator.GetInstance <IParagraphCounterRepository>().GetParaCounter((int)TeViewGroup.Scripture); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Configure a PublicationControl /// </summary> /// ------------------------------------------------------------------------------------ public void ConfigurePublication() { if (m_pub != null) { m_pub.Dispose(); } m_division = new DummyDivision(new DummyHFPrintConfigurer(Cache), 1); IPublication pub = Cache.LangProject.TranslatedScriptureOA.PublicationsOC.ToArray()[0]; m_pub = new DummyPublication(pub, m_division, DateTime.Now); m_pub.Configure(); // Check initial state Assert.AreEqual(m_division, m_pub.Divisions[0]); IVwLayoutStream layoutStream = m_division.MainLayoutStream; Assert.IsNotNull(layoutStream); }
public void OneColumnOneBook() { foreach (PubDivision div in m_dbPub.DivisionsOS) { div.NumColumns = 1; } m_BookFilter.UpdateFilter( Cache.LangProject.TranslatedScriptureOA.ScriptureBooksOS.HvoArray[1]); Assert.AreEqual(1, m_BookFilter.BookCount); m_ScrPubCtrl.Configure(); m_ScrPubCtrl.CreatePages(); // Verify that both divisions are one-column Assert.AreEqual(2, m_ScrPubCtrl.Divisions.Count); DivisionLayoutMgr divTitleIntro = m_ScrPubCtrl.Divisions[0]; DivisionLayoutMgr divScripture = m_ScrPubCtrl.Divisions[1]; Assert.AreEqual(divTitleIntro.AvailableMainStreamColumWidthInPrinterPixels, divScripture.AvailableMainStreamColumWidthInPrinterPixels); Assert.AreEqual(divTitleIntro.AvailableMainStreamColumWidthInPrinterPixels, divTitleIntro.AvailablePageWidthInPrinterPixels); Assert.AreNotEqual(DivisionStartOption.Continuous, divTitleIntro.StartAt); Assert.AreEqual(DivisionStartOption.Continuous, divScripture.StartAt); Assert.Greater(divTitleIntro.MainRootBox.Height, 0); Assert.Greater(divScripture.MainRootBox.Height, 0); Assert.Greater(divScripture.MainRootBox.Height, divTitleIntro.MainRootBox.Height); Assert.Greater(m_ScrPubCtrl.PageCount, 2); Assert.IsNotNull(divTitleIntro.MainVc as ScriptureBookIntroVc); Assert.IsNotNull(divScripture.MainVc as ScriptureBodyVc); foreach (DivisionLayoutMgr div in m_ScrPubCtrl.Divisions) { IVwLayoutStream layoutStream = div.MainLayoutStream; Assert.IsNotNull(layoutStream); Assert.IsNotNull(layoutStream as IVwRootBox); } }
public void TwoColumnOneBook() { foreach (IPubDivision div in m_dbPub.DivisionsOS) { div.NumColumns = 2; } m_BookFilter.FilteredBooks = new [] { Cache.LangProject.TranslatedScriptureOA.ScriptureBooksOS[1] }; Assert.AreEqual(1, m_BookFilter.BookCount); m_ScrPubCtrl.CallRefreshDisplay(); m_ScrPubCtrl.Configure(); m_ScrPubCtrl.CreatePages(); Assert.AreEqual(2, m_ScrPubCtrl.Divisions.Count); DivisionLayoutMgr divTitleIntro = m_ScrPubCtrl.Divisions[0]; DivisionLayoutMgr divScripture = m_ScrPubCtrl.Divisions[1]; Assert.AreNotEqual(divTitleIntro.AvailableMainStreamColumWidthInPrinterPixels, divScripture.AvailableMainStreamColumWidthInPrinterPixels); Assert.AreEqual(divTitleIntro.AvailableMainStreamColumWidthInPrinterPixels, divTitleIntro.AvailablePageWidthInPrinterPixels); Assert.AreNotEqual(DivisionStartOption.Continuous, divTitleIntro.StartAt); Assert.AreEqual(DivisionStartOption.Continuous, divScripture.StartAt); Assert.Greater(divTitleIntro.MainRootBox.Height, 0); Assert.Greater(divScripture.MainRootBox.Height, 0); Assert.Greater(divScripture.MainRootBox.Height, divTitleIntro.MainRootBox.Height); Assert.Greater(m_ScrPubCtrl.PageCount, 1); Assert.IsNotNull(divTitleIntro.MainVc as ScriptureBookIntroVc); Assert.IsNotNull(divScripture.MainVc as ScriptureBodyVc); foreach (DivisionLayoutMgr div in m_ScrPubCtrl.Divisions) { IVwLayoutStream layoutStream = div.MainLayoutStream; Assert.IsNotNull(layoutStream); Assert.IsNotNull(layoutStream as IVwRootBox); } }
public void DeleteFootnoteSelection() { // Add a footnote to the last section in the book of Genesis. (The last section is // what is contained in our rootbox). Assert.AreEqual(3, m_book.SectionsOS.Count); IScrTxtPara para = (IScrTxtPara)m_book.SectionsOS[1].ContentOA.ParagraphsOS[0]; AddFootnote(m_book, para, para.Contents.Length, "Footnote to delete"); // Get number of footnotes in book. IScripture scr = Cache.LangProject.TranslatedScriptureOA; Assert.AreEqual(1, scr.ScriptureBooksOS.Count); int numFootnotes = m_book.FootnotesOS.Count; m_ScrPubCtrl.PageHeight = 432000; // 6 inches m_ScrPubCtrl.PageWidth = 288000; // 4 inches m_division.TopMargin = 18000; // Half inch m_division.BottomMargin = 18000; m_division.InsideMargin = 18000; m_division.OutsideMargin = 18000; m_ScrPubCtrl.Width = 4 * 96; // represents a window that is 4" wide at 96 DPI m_ScrPubCtrl.CreatePages(); m_ScrPubCtrl.PrepareToDrawPages(0, 2000); IVwLayoutStream layoutStream = m_division.MainLayoutStream; IVwRootBox rootbox = layoutStream as IVwRootBox; // Select the first footnote in the last section of the book. SelectRangeOfChars(rootbox, 0, para.Contents.Length - 2, para.Contents.Length - 1); // Delete the footnote marker selection. //m_footnoteView.OnKeyDown(new KeyEventArgs(Keys.Delete)); m_lp.Cache.ActionHandlerAccessor.EndUndoTask(); // Delete key generates own UOW m_ScrPubCtrl.PressKey(new KeyEventArgs(Keys.Delete)); m_lp.Cache.ActionHandlerAccessor.BeginUndoTask("nonsence", "redo nonsence"); // Confirm that there is one less footnote in the book. Assert.AreEqual(numFootnotes - 1, m_book.FootnotesOS.Count); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Configure a PublicationControl /// </summary> /// ------------------------------------------------------------------------------------ public void ConfigurePublication() { if (m_division != null) { m_division.Dispose(); } if (m_ScrPubCtrl != null) { m_ScrPubCtrl.Dispose(); } m_division = new DummyDivision(new DummyPrintConfigurer(m_fdoCache, null), 1); Publication pub = new Publication(m_fdoCache, m_fdoCache.LangProject.TranslatedScriptureOA.PublicationsOC.HvoArray[0]); m_ScrPubCtrl = new TeDummyPublication(pub, m_division, DateTime.Now); m_ScrPubCtrl.Configure(); // Check initial state Assert.AreEqual(m_division, m_ScrPubCtrl.Divisions[0]); Assert.IsNotNull(m_division.MainVc as StVc); IVwLayoutStream layoutStream = m_division.MainLayoutStream; Assert.IsNotNull(layoutStream); Assert.AreEqual(layoutStream, m_division.MainLayoutStream, "MainLayoutStream should not contruct a new stream each time"); IVwRootBox rootbox = layoutStream as IVwRootBox; Assert.IsNotNull(rootbox); IVwSelection sel = rootbox.Selection; Assert.IsNotNull(sel); int ich, hvo, tag, ws; // dummies bool fAssocPrev; ITsString tss; sel.TextSelInfo(false, out tss, out ich, out fAssocPrev, out hvo, out tag, out ws); Assert.AreEqual("14", tss.Text.Substring(0, 2)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Constructs a TePrintLayoutConfig to configure the main print layout /// </summary> /// <param name="cache">The cache.</param> /// <param name="styleSheet">The style sheet.</param> /// <param name="publication">The publication.</param> /// <param name="viewType">Type of the view.</param> /// <param name="filterInstance">the book filter instance in effect</param> /// <param name="printDateTime">printing date and time</param> /// <param name="fIntroDivision">set to <c>true</c> for a division that displays book /// title and introduction material, <c>false</c> for a division that displays main /// scripture text.</param> /// <param name="hvoBook">The hvo of the book we're displaying.</param> /// <param name="sharedStream">A layout stream used for footnotes which is shared across /// multiple divisions</param> /// <param name="ws">The writing system to use for the view.</param> /// ------------------------------------------------------------------------------------ public TePrintLayoutConfig(FdoCache cache, IVwStylesheet styleSheet, IPublication publication, TeViewType viewType, int filterInstance, DateTime printDateTime, bool fIntroDivision, int hvoBook, IVwLayoutStream sharedStream, int ws) { m_fdoCache = cache; m_scr = m_fdoCache.LangProject.TranslatedScriptureOA; m_styleSheet = styleSheet; m_pub = publication; m_viewType = viewType; m_bookFilterInstance = filterInstance; m_printDateTime = printDateTime; m_fIntroDivision = fIntroDivision; m_hvoBook = hvoBook; m_sharedStream = sharedStream; m_ws = ws; m_sectionFilterInstance = g_nextSectionFilterInstance++; m_sectionFilter = new FilteredSequenceHandler(cache, ScrBook.kClassId, m_sectionFilterInstance, this, this, new SimpleFlidProvider((int)ScrBook.ScrBookTags.kflidSections)); m_paraCounter = ParagraphCounterManager.GetParaCounter(cache, (int)TeViewGroup.Scripture); }
/// <summary> /// Attempt to find the page for a location quickly, if it is the /// main stream for some division and the location is within one of the /// elements for that division. /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="fUp"></param> /// <param name="strm"></param> /// <param name="iDiv"></param> /// <returns></returns> private Page PossiblePageFromPrinter(int x, int y, bool fUp, IVwLayoutStream strm, out int iDiv) { iDiv = DivisionIndexForMainStream(strm); if (iDiv < 0 || Pages == null || Pages.Count == 0) return null; // can't find it this way unless it's a main stream and we have pages. DivisionLayoutMgr divMgr = Divisions[iDiv]; int divOffset; for (int i = 0; i < Pages.Count; i++) { Page page = Pages[i]; if (page.FirstDivOnPage > iDiv) { // No more pages of the required division. // If there is a previous page, it might be on there, otherwise we won't find it. if (i > 0) return Pages[i - 1]; else return null; } PageElement firstPe; divOffset = page.OffsetFromTopOfDiv(strm, divMgr, out firstPe); if (y <= divOffset) { // We've found the first page of this division which starts at or beyond y. // Typically we want the previous page, since this one starts after y. // If there is no previous page return this one. if (i == 0) return page; // If we're exactly on the boundary and preferring down, we want this one; if (y == divOffset && !fUp) return page; // If we're in the overlap region we need to investigate. If it's actually on // this page we want this one. if (firstPe != null && y > divOffset - firstPe.OverlapWithPreviousElement) { Point locOnPage; if (page.GetPositionOnPage(strm, new Point(x, y), out locOnPage)) return page; } return Pages[i - 1]; } } // If we didn't find a page, see if the position is on the last page return Pages[Pages.Count - 1]; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Sets the accessible name of the stream. /// </summary> /// <param name="stream">The stream.</param> /// <param name="name">The name.</param> /// ------------------------------------------------------------------------------------ public static void SetAccessibleStreamName(IVwLayoutStream stream, string name) { IAccessible acc = AccessibleRootObject(stream) as IAccessible; if (acc != null) acc.set_accName(null, name); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Get the accessible object from the root box (implements IAccessible) /// </summary> /// ------------------------------------------------------------------------------------ private static object AccessibleRootObject(IVwLayoutStream stream) { if (stream == null) { return null; } object obj = null; #if !__MonoCS__ if (stream is IOleServiceProvider) { IOleServiceProvider sp = (IOleServiceProvider)stream; Debug.Assert(sp != null); Guid guidAcc = Marshal.GenerateGuidForType(typeof(IAccessible)); // 1st guid currently ignored. sp.QueryService(ref guidAcc, ref guidAcc, out obj); } #else // TODO-Linux: for a VwLayoutStream, stream is IOleServiceProvider is returning true while QueryInterface (cast) throws exceptions a VwLayoutStream // QueryInterface doesn't report that its a VwLayoutStream. #endif return obj; }
/// -------------------------------------------------------------------------------- /// <summary> /// Calls Page.AddPageElement(). /// </summary> /// <param name="division">The division</param> /// <param name="stream">The stream (rootbox) which supplies data for this element</param> /// <param name="fPageElementOwnsStream"><c>true</c> if this element is responsible for /// closing its stream when it is destoyed</param> /// <param name="locationOnPage">Location where this stream is laid out, in printer /// pixels, relative to the top left of the physical page</param> /// <param name="dypOffsetToTopPageBoundaryOnPage">Offset in stream to top of data being shown /// on this page, in printer pixels</param> /// <param name="fMainStream"><c>true</c> if this element is for a "main" stream; /// <c>false</c> if it's for a subordinate stream or a Header/Footer stream</param> /// <param name="currentColumn">The current column (1-based).</param> /// <param name="totalColumns">The total columns in the specified stream.</param> /// <param name="columnGap">The gap between the columns.</param> /// <param name="columnHeight">The height of the current column.</param> /// <param name="isRightToLeft">if set to <c>true</c> the stream is right-to-left. /// Otherwise, it is left-to-right.</param> /// <param name="fReducesFreeSpaceFromTop">Flag indicating whether additoin of this /// element reduces the free space from top or bottom.</param> /// -------------------------------------------------------------------------------- public void CallAddPageElement(DivisionLayoutMgr division, IVwLayoutStream stream, bool fPageElementOwnsStream, Rectangle locationOnPage, int dypOffsetToTopPageBoundaryOnPage, bool fMainStream, int currentColumn, int totalColumns, int columnGap, int columnHeight, bool isRightToLeft, bool fReducesFreeSpaceFromTop) { base.AddPageElement(division, stream, fPageElementOwnsStream, locationOnPage, dypOffsetToTopPageBoundaryOnPage, fMainStream, currentColumn, totalColumns, columnGap, columnHeight, 0, isRightToLeft, fReducesFreeSpaceFromTop); }
/// ------------------------------------------------------------------------------------- /// <summary> /// Inserts additonal pages if needed at dydPosition to approximately match the new /// estimated height when a lazy box has been expanded. /// </summary> /// <param name="changedSizePage">The last page whose top doesn't move (i.e., the one the /// lazy box is actually on). We may need to insert pages just after this.</param> /// <param name="strm">The IVwLayoutStream interface of the rootbox that is the main /// stream on at least some of the pages of this publication (i.e., this publication /// should be the IVwRootsite of the given rootbox).</param> /// <param name="dydSize">The amount the rootbox grew, in printer pixels. This is /// guaranteed to be positive.</param> /// <param name="dydPosition">The top of the lazy box which was (partially) expanded, /// split, etc (in printer pixels). Or the position of the top of the real box that got /// relazified. /// </param> /// <returns>true if there are not enough pages for the AutoScrollPosition to increase as /// much as required.</returns> /// ------------------------------------------------------------------------------------- private bool InsertAdditionalPages(Page changedSizePage, IVwLayoutStream strm, int dydSize, int dydPosition) { Debug.Assert(changedSizePage != null); Debug.Assert(dydSize > 0); Page nextPage = PageAfter(changedSizePage); int heightOfChangedPage; // Current height, to next page or estimated end of doc. int iDiv = DivisionIndexForMainStream(strm); DivisionLayoutMgr divMgr = Divisions[iDiv]; if (nextPage == null) { heightOfChangedPage = dydSize; // An empty page may have nothing from the main stream - can happen when project is // empty or filter excludes all content PageElement pe = changedSizePage.GetFirstElementForStream(strm); if (pe != null) heightOfChangedPage -= pe.OffsetToTopPageBoundary; } else { heightOfChangedPage = nextPage.OffsetFromTopOfDiv(divMgr) - changedSizePage.OffsetFromTopOfDiv(divMgr); } int desiredPageHeight = divMgr.AvailablePageHeightInPrinterPixels; // This computes the number of pages to add, if any, so that // if the tops of the pages are more than a page and a half apart we // insert enough pages so no page is more than an ideal page and a half long. // Subtracting half the desired page height accounts both for rounding and // the fact that one page (rather than zero) is the desired page height. int numberOfPagesToAdd = (heightOfChangedPage - desiredPageHeight / 2) / desiredPageHeight; // Pathologically, it might be possible for that calculation to produce // a negative number, if this page has shrunk to less than a half page from // previous lazy box expansions. if (numberOfPagesToAdd < 0) numberOfPagesToAdd = 0; Page pageToInsertAfter = changedSizePage; for (int i = 0; i < numberOfPagesToAdd; i++) { // Insert a new page. pageToInsertAfter = InsertPage(iDiv, pageToInsertAfter.OffsetFromTopOfDiv(divMgr) + desiredPageHeight, pageToInsertAfter); } // If we're increasing the autoscroll position, do it AFTER we possibly adjust // the autoscroll range, otherwise, the increased value might be greater than // the old range and get truncated. // Remember: Microsoft's idea of how to set AutoScrollPosition is brain-dead. We read // it as negative and have to set it as positive. int dydPosScreen = (int)(dydPosition * DpiYScreen / DpiYPrinter); if (-AutoScrollPosition.Y > dydPosScreen) { int dydDesiredAutoScrollY = (int)(AutoScrollPosition.Y - (dydSize * DpiYScreen / DpiYPrinter)); // larger negative AutoScrollPosition = new Point( -AutoScrollPosition.X, -dydDesiredAutoScrollY); // Something messy happened if we can't achieve that position (presumably // it is out of range, we didn't add enough pages). return (AutoScrollPosition.Y != dydDesiredAutoScrollY); } return false; // We get here only if we didn't have to adjust scroll position at all. }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the print layout configurer. /// </summary> /// <param name="fIntroDivision">set to <c>true</c> for a division that displays book /// title and introduction material, <c>false</c> for a division that displays main /// scripture text.</param> /// <param name="hvoBook">The hvo of the book.</param> /// <param name="sharedStream">A layout stream used for footnotes which is shared across /// multiple divisions</param> /// <param name="ws">The writing system</param> /// <returns>A print layout configurer</returns> /// ------------------------------------------------------------------------------------ protected override TePrintLayoutConfig GetPrintLayoutConfigurer(bool fIntroDivision, int hvoBook, IVwLayoutStream sharedStream, int ws) { return new TeBtPrintLayoutConfig(m_cache, m_stylesheet, m_publication, m_viewType, m_filterInstance, m_printDateTime, fIntroDivision, hvoBook, sharedStream, ws); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Expose the PublicationControl.AddsSharedSubstream. /// </summary> /// <param name="subStream">The substream.</param> /// ------------------------------------------------------------------------------------ internal new void AddSharedSubstream(IVwLayoutStream subStream) { base.AddSharedSubstream(subStream); }
/// -------------------------------------------------------------------------------- /// <summary> /// Initializes a new instance of the <see cref="DummyDivisionMgr"/> class. /// </summary> /// <param name="stream">The stream.</param> /// <param name="fMainStreamRightToLeft">if set to <c>true</c> if the main stream in /// the test is right-to-left; otherwise <c>false</c>.</param> /// -------------------------------------------------------------------------------- public DummyDivisionMgr(IVwLayoutStream stream, bool fMainStreamRightToLeft) : base(null, null, 0) { m_mainLayoutStream = stream; m_fMainStreamRightToLeft = fMainStreamRightToLeft; }
/// <summary> /// Executes in two distinct scenarios. /// /// 1. If disposing is true, the method has been called directly /// or indirectly by a user's code via the Dispose method. /// Both managed and unmanaged resources can be disposed. /// /// 2. If disposing is false, the method has been called by the /// runtime from inside the finalizer and you should not reference (access) /// other managed objects, as they already have been garbage collected. /// Only unmanaged resources can be disposed. /// </summary> /// <param name="disposing"></param> /// <remarks> /// If any exceptions are thrown, that is fine. /// If the method is being done in a finalizer, it will be ignored. /// If it is thrown by client code calling Dispose, /// it needs to be handled by fixing the bug. /// /// If subclasses override this method, they should call the base implementation. /// </remarks> protected virtual void Dispose(bool disposing) { System.Diagnostics.Debug.WriteLineIf(!disposing, "****** Missing Dispose() call for " + GetType().Name + ". ****** "); // Must not be run more than once. if (m_isDisposed) return; IVwRootBox rootb; if (disposing) { // Dispose managed resources here. if (m_subStreams != null) { foreach (SubordinateStream stream in m_subStreams) { if (!stream.m_fShared) { rootb = stream.m_stream as IVwRootBox; if (rootb != null) rootb.Close(); var disposableStreamVc = stream.m_vc as IDisposable; if (disposableStreamVc != null) disposableStreamVc.Dispose(); } } m_subStreams.Clear(); } var disposable = m_mainVc as IDisposable; if (disposable != null) disposable.Dispose(); foreach (var hfVc in m_CreatedHfVcs) { disposable = hfVc as IDisposable; if (disposable != null) disposable.Dispose(); } m_CreatedHfVcs.Clear(); } // Dispose unmanaged resources here, whether disposing is true or false. rootb = m_mainLayoutStream as IVwRootBox; if (rootb != null) rootb.Close(); m_mainLayoutStream = null; m_subStreams = null; m_mainVc = null; m_CreatedHfVcs = null; m_isDisposed = true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Indicates whether this division displays the given stream. /// </summary> /// <param name="stream">The stream to check</param> /// <returns><c>true</c> if this DivisionLayoutMgr displays this stream</returns> /// ------------------------------------------------------------------------------------ internal bool IsManagerForStream(IVwLayoutStream stream) { CheckDisposed(); return (MainLayoutStream == stream); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Shuts down the FDO cache /// </summary> /// ------------------------------------------------------------------------------------ public override void TestTearDown() { if (m_firstDivision != null) { m_firstDivision.m_hPagesBroken.Clear(); m_firstDivision.Dispose(); m_firstDivision = null; } // Make sure we close all the rootboxes if (m_pub != null) { m_pub.Dispose(); m_pub = null; } m_subViewVc = null; m_subStream = null; base.TestTearDown(); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Given a point in printer(layout) pixels relative to the top left of the stream, /// determine which page it occurs on, and return that page, along with the /// distance from the top of the page to the point. If the page does not currently /// contain valid elements, this may be somewhat approximate. /// </summary> /// <param name="x">X coord, important where pages overlap</param> /// <param name="y">Y coordinate (in printer pixels), from the top of the stream.</param> /// <param name="fUp">If the point is right at a page boundary, return the first /// page if this is true, the second if it is false.</param> /// <param name="strm">The stream that contains the y position.</param> /// <param name="dyPageScreen">Distance in screen coords from top of page to /// the specified location.</param> /// <param name="iDiv">Index of the division at the specified location.</param> /// <param name="layedOutPage">Flag returned as <c>true</c> if a page was layed out during /// this call</param> /// <returns>The page that contains the y-position, or <c>null</c>.</returns> /// ------------------------------------------------------------------------------------ protected internal Page PageFromPrinterY(int x, int y, bool fUp, IVwLayoutStream strm, out int dyPageScreen, out int iDiv, out bool layedOutPage) { layedOutPage = false; Page possiblePage = PossiblePageFromPrinter(x, y, fUp, strm, out iDiv); if (possiblePage != null) { Point locOnPage; if (possiblePage.GetPositionOnPage(strm, new Point(x, y), out locOnPage)) { dyPageScreen = ConvertPrintEltOffsetToPixelsY(locOnPage.Y, DpiYScreen); return possiblePage; } } // footnotes aren't in page element stream, no use looking for it if (strm == null) { dyPageScreen = 0; // satisfy compiler return null; } // If it's not the main stream or we didn't find it the quick way, all we can // do is look for a hopeful element. Since the thing might well be on even a // broken page, for this we consider even broken pages...to make things more // accurate we fix any broken page. if (Pages != null && Pages.Count > 0) { bool layedOutSomething; bool foundPageOnStream = false; do { layedOutSomething = false; foreach (Page page in Pages) { if (page.LayOutIfNeeded()) { layedOutSomething = true; layedOutPage = true; break; } bool foundElemOnStream = false; foreach (PageElement pe in page.PageElements) { if (pe.m_stream != strm) continue; foundPageOnStream = true; foundElemOnStream = true; // If y is in the range for this page element, we probably stop here... if (y >= pe.OffsetToTopPageBoundary - pe.OverlapWithPreviousElement && y <= pe.OffsetToTopPageBoundary + pe.LocationOnPage.Height) { if (y < pe.OffsetToTopPageBoundary && !pe.IsInOurPartOfOverlap(new Point(x, y))) continue; // Except, if we're exactly at the bottom and want to be at the top, // keep trying. (Enhance JohnT: not sure we can depend on fUp any more, // now we have overlap...) if ((!fUp) && y == pe.OffsetToTopPageBoundary + pe.LocationOnPage.Height) continue; // Also, in case the element might be out of order, if we we're // exactly at the top and want to be at the bottom, keep trying if (fUp && y <= pe.OffsetToTopPageBoundary - pe.OverlapWithPreviousElement) continue; int yOnPage = y - pe.OffsetToTopPageBoundary - pe.OverlapWithPreviousElement + pe.LocationOnPage.Top; dyPageScreen = ConvertPrintEltOffsetToPixelsY(yOnPage, DpiYScreen); return page; } else if (y < pe.OffsetToTopPageBoundary) { // have gone too far, can end the search. Y must be on // a page that hasn't been layed out. dyPageScreen = 0; // satisfy compiler return null; } } // another check to see that we've gone too far if (foundPageOnStream && !foundElemOnStream) { dyPageScreen = 0; // satisfy compiler return null; } } } while (layedOutSomething); } dyPageScreen = 0; // satisfy compiler return null; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the index of the division for the given stream /// </summary> /// <returns>The index of the division for the given stream if it is the main stream /// for any division in this publication; Otherwise -1.</returns> /// ------------------------------------------------------------------------------------ public int DivisionIndexForMainStream(IVwLayoutStream stream) { CheckDisposed(); if (stream == null) return -1; for (int i = 0; i < m_divisions.Count; i++) { if (m_divisions[i].IsManagerForStream(stream)) return i; } return -1; }
public void TwoColumnTwoBooks() { foreach (PubDivision div in m_dbPub.DivisionsOS) { div.NumColumns = 2; } m_BookFilter.UpdateFilter( Cache.LangProject.TranslatedScriptureOA.ScriptureBooksOS.HvoArray[0], Cache.LangProject.TranslatedScriptureOA.ScriptureBooksOS.HvoArray[1]); Assert.AreEqual(2, m_BookFilter.BookCount); m_ScrPubCtrl.Configure(); m_ScrPubCtrl.CreatePages(); Assert.AreEqual(4, m_ScrPubCtrl.Divisions.Count); DivisionLayoutMgr divTitleIntroFirstBook = m_ScrPubCtrl.Divisions[0]; DivisionLayoutMgr divScriptureFirstBook = m_ScrPubCtrl.Divisions[1]; DivisionLayoutMgr divTitleIntroSecondBook = m_ScrPubCtrl.Divisions[2]; DivisionLayoutMgr divScriptureSecondBook = m_ScrPubCtrl.Divisions[3]; Assert.Greater(divTitleIntroFirstBook.AvailableMainStreamColumWidthInPrinterPixels, divScriptureFirstBook.AvailableMainStreamColumWidthInPrinterPixels); Assert.AreEqual(divTitleIntroFirstBook.AvailableMainStreamColumWidthInPrinterPixels, divTitleIntroFirstBook.AvailablePageWidthInPrinterPixels); Assert.AreEqual(divTitleIntroFirstBook.AvailableMainStreamColumWidthInPrinterPixels, divTitleIntroSecondBook.AvailableMainStreamColumWidthInPrinterPixels); Assert.AreEqual(divScriptureFirstBook.AvailableMainStreamColumWidthInPrinterPixels, divScriptureSecondBook.AvailableMainStreamColumWidthInPrinterPixels); Assert.AreNotEqual(DivisionStartOption.Continuous, divTitleIntroFirstBook.StartAt); Assert.AreEqual(DivisionStartOption.Continuous, divScriptureFirstBook.StartAt); Assert.AreNotEqual(DivisionStartOption.Continuous, divTitleIntroSecondBook.StartAt); Assert.AreEqual(DivisionStartOption.Continuous, divScriptureSecondBook.StartAt); Assert.Greater(divTitleIntroFirstBook.MainRootBox.Height, 0); Assert.Greater(divScriptureFirstBook.MainRootBox.Height, 0); // Intro of Philemon is quite long, so we just test that the heights of the two division are not equal Assert.AreNotEqual(divScriptureFirstBook.MainRootBox.Height, divTitleIntroFirstBook.MainRootBox.Height); Assert.Greater(divTitleIntroSecondBook.MainRootBox.Height, 0); Assert.Greater(divScriptureSecondBook.MainRootBox.Height, 0); Assert.Greater(divScriptureSecondBook.MainRootBox.Height, divTitleIntroSecondBook.MainRootBox.Height); Assert.AreEqual(2, m_ScrPubCtrl.Pages[1].FirstDivOnPage, "Page 2 should start with second book (third division)"); Assert.AreEqual(0, m_ScrPubCtrl.Pages[1].OffsetFromTopOfDiv( m_ScrPubCtrl.Divisions[m_ScrPubCtrl.Pages[2].FirstDivOnPage]), "Third division should start on top of page 2"); Assert.Greater(m_ScrPubCtrl.PageCount, 2); Assert.IsNotNull(divTitleIntroFirstBook.MainVc as ScriptureBookIntroVc); Assert.IsNotNull(divScriptureFirstBook.MainVc as ScriptureBodyVc); Assert.IsNotNull(divTitleIntroSecondBook.MainVc as ScriptureBookIntroVc); Assert.IsNotNull(divScriptureSecondBook.MainVc as ScriptureBodyVc); foreach (DivisionLayoutMgr div in m_ScrPubCtrl.Divisions) { IVwLayoutStream layoutStream = div.MainLayoutStream; Assert.IsNotNull(layoutStream); Assert.IsNotNull(layoutStream as IVwRootBox); } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Exposes the PageFromPrinterY method /// </summary> /// <param name="y">The y.</param> /// <param name="fUp">If the point is right at a page boundary, return the first /// page if this is true, the second if it is false.</param> /// <param name="strm">The STRM.</param> /// <param name="dyPageScreen">The dy page screen.</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ public Page CallPageFromPrinterY(int y, bool fUp, IVwLayoutStream strm, out int dyPageScreen) { int iDiv; // not used in the tests return PageFromPrinterY(0, y, fUp, strm, out dyPageScreen, out iDiv); }
/// <summary> /// Record which page(s) were broken. /// </summary> /// <param name="lay"></param> /// <param name="hPage"></param> public override void PageBroken(IVwLayoutStream lay, int hPage) { CheckDisposed(); m_hPagesBroken.Add(hPage); base.PageBroken(lay, hPage); }
//private Form m_form; /// ------------------------------------------------------------------------------------ /// <summary> /// Creates the division and publication. /// </summary> /// <param name="columns">The number of columns.</param> /// <param name="fSharedSubStreams">if set to <c>true</c> configure the print layout /// view using shared sub streams; otherwise, each division will create an owned /// substream.</param> /// ------------------------------------------------------------------------------------ private void CreateDivisionAndPublication(int columns, bool fSharedSubStreams) { if (m_firstDivision != null) m_firstDivision.Dispose(); if (m_pub != null) m_pub.Dispose(); m_subStream = null; if (fSharedSubStreams) m_subStream = VwLayoutStreamClass.Create(); m_firstDivision = new DummyDivision(new DummyPrintConfigurer(Cache, m_subStream), columns); IPublication pub = Cache.LangProject.TranslatedScriptureOA.PublicationsOC.ToArray()[0]; m_pub = new DummyPublication(pub, m_firstDivision, DateTime.Now); if (fSharedSubStreams) { m_subViewVc = new DummyFirstSubViewVc(); int hvoScr = Cache.LangProject.TranslatedScriptureOA.Hvo; IVwRootBox rootbox = (IVwRootBox)m_subStream; rootbox.DataAccess = Cache.MainCacheAccessor; rootbox.SetRootObject(hvoScr, m_subViewVc, DummyFirstSubViewVc.kfragScrFootnotes, null); m_pub.AddSharedSubstream(m_subStream); } }
/// ------------------------------------------------------------------------------------- /// <summary> /// The layout manager is informed by this method that the (primary) layout stream 'lay' /// has determined that references to the objects objectGuids occur on the page. The input /// value of dysAvailHeight indicates how much of the height allocated to 'lay' for this /// page will remain available if the text containing these references is added to the /// page (assuming that adding them does not reduce the space available for 'lay'). /// This is an alternative implementation of AddDependentObjects for the case where /// RootOnEachPage is true. /// </summary> /// <param name="lay">The primary layout stream filling the page</param> /// <param name="vg">The graphics object being used to layout the page</param> /// <param name="hPage">The handle to the page being laid out</param> /// <param name="cguid">Number of elements in objectGuids array</param> /// <param name="objectGuids">Array of GUIDS representing objects to be laid out in a /// separate layout stream</param> /// <param name="fAllowFail">Indicates whether this method can fail (return /// <c>fFailed == true</c>). If this is false, this method should force the requested /// objects to be laid out within the available space, even if it requires omitting or /// truncating some or all of them</param> /// <param name="fFailed">If the available height would become negative (typically /// because the objects must share space with 'lay' and they don't fit in the available /// height), this will be set to true (unless fAllowFail is false).</param> /// <param name="dysAvailHeight">Input value indicates how much of the height allocated /// to 'lay' for this page will remain available if the text containing these references /// is added to the page, assuming that adding them does not reduce the space available /// for 'lay'. The output value indicates how much is left after laying out these /// dependent objects.</param> /// ------------------------------------------------------------------------------------- public virtual void AddDependentObjectsToPageRoot(IVwLayoutStream lay, IVwGraphics vg, int hPage, int cguid, Guid[] objectGuids, bool fAllowFail, out bool fFailed, ref int dysAvailHeight) { int dysAvailableHeight = dysAvailHeight; fFailed = false; int[] rgHvo = new int[cguid]; int i = 0; foreach (Guid guid in objectGuids) { int hvo = m_configurer.GetIdFromGuid(guid); if (hvo != 0) rgHvo[i++] = hvo; // only add the ones we can match. else cguid--; // found unmatched guid } Page page = Publication.FindPage(hPage); if (page.DoingTrialLayout) { page.NoteDependentRoots(rgHvo); // note that we do not need to adjust dysAvailHeight, because in trial mode the // INITIAL height is set to the space available minus the old dependent root // objects view's height. return; } // Collect some information we need IVwLayoutStream dependentStream = page.DependentObjectsRootStream; IVwRootBox dependentRootbox = (IVwRootBox)dependentStream; int hvoRoot = m_configurer.DependentRootHvo; int dependentObjTag = m_configurer.DependentRootTag; int dependentObjFrag = m_configurer.DependentRootFrag; IDependentObjectsVc depObjVc; ISilDataAccess sda = m_configurer.DataAccess; int oldHeight = 0; int startIndex = -1; int endIndex = -1; int prevStartIndex; int prevEndIndex; if (dependentRootbox == null) { // no pre-existing rootbox for this page so create a new one depObjVc = m_configurer.DependentRootVc; dependentStream = VwLayoutStreamClass.Create(); dependentStream.SetManager(this); page.DependentObjectsRootStream = dependentStream; dependentRootbox = (IVwRootBox)dependentStream; dependentRootbox.SetSite(Publication); dependentRootbox.DataAccess = sda; dependentRootbox.SetRootObject(hvoRoot, depObjVc, dependentObjFrag, m_configurer.StyleSheet); // Set up the view constructor to show the correct objects if (cguid > 0) { startIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[0]); endIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[cguid - 1]); Debug.Assert(startIndex >= 0 && endIndex >= 0); } depObjVc.StartingObjIndex = startIndex; depObjVc.EndingObjIndex = endIndex; prevStartIndex = prevEndIndex = -1; } else { // A rootbox was already created for this page, just update what is shown oldHeight = dependentRootbox.Height; IVwViewConstructor vc; IVwStylesheet ss; dependentRootbox.GetRootObject(out hvoRoot, out vc, out dependentObjFrag, out ss); depObjVc = (IDependentObjectsVc)vc; prevStartIndex = depObjVc.StartingObjIndex; prevEndIndex = depObjVc.EndingObjIndex; // Update the view constructor with the new objects if (cguid > 0) { startIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[0]); endIndex = sda.GetObjIndex(hvoRoot, dependentObjTag, rgHvo[cguid - 1]); Debug.Assert(startIndex >= 0 && endIndex >= 0); Debug.Assert(startIndex > depObjVc.EndingObjIndex && endIndex > depObjVc.EndingObjIndex); if (depObjVc.StartingObjIndex == -1) { // Most likely all the shown objects were removed from the view constructor. // We need to make sure we have a valid starting index. depObjVc.StartingObjIndex = startIndex; } depObjVc.EndingObjIndex = endIndex; } } if (startIndex < 0 || endIndex < 0) { fFailed = fAllowFail; return; } // update the rootbox with the new items. try { // propChanged generates a PageBroken notification we need to ignore. m_hPageBeingBuilt = hPage; int count = endIndex - startIndex + 1; dependentRootbox.PropChanged(hvoRoot, dependentObjTag, startIndex, count, count); } finally { m_hPageBeingBuilt = 0; } PublicationControl.SetAccessibleStreamName(dependentStream, "Dependent stream for page " + page.PageNumber); // The actual laying out is probably redundant, but this lets the dependent stream // know what page it's on, which is useful for notifications. With an interface // change we could do this more efficiently, I think. for (int ihvo = startIndex; ihvo <= endIndex; ihvo++) { SelLevInfo[] rgSelLevInfo = new SelLevInfo[1]; rgSelLevInfo[0].tag = dependentObjTag; rgSelLevInfo[0].ihvo = ihvo - depObjVc.StartingObjIndex; dependentStream.LayoutObj(vg, AvailablePageWidthInPrinterPixels, 0, rgSelLevInfo.Length, rgSelLevInfo, hPage); } int newHeight = dependentRootbox.Height; int dysHeightUsed = newHeight - oldHeight; // If this stream is just now being added to the page, need to allow for gap between elements. if (oldHeight == 0) dysHeightUsed += VerticalGapBetweenElements * vg.YUnitsPerInch / MiscUtils.kdzmpInch; if ((dysHeightUsed * m_numberMainStreamColumns) > dysAvailHeight) { // We can't add everything needed for the current chunk (in the main stream), // so we need to fail (if that's permitted), and roll everything back if (fAllowFail) { fFailed = true; // roll back: remove the extra objects. try { int newStartObjIndex = depObjVc.StartingObjIndex; int newEndObjIndex = depObjVc.EndingObjIndex; depObjVc.StartingObjIndex = prevStartIndex; depObjVc.EndingObjIndex = prevEndIndex; int count = endIndex - newStartObjIndex + 1; dependentRootbox.PropChanged(hvoRoot, dependentObjTag, newStartObjIndex, count, count); } finally { m_hPageBeingBuilt = 0; } return; } else dysAvailableHeight = 0; } else { // When we layout with multiple columns, we pretend to have one large // page. But the substreams are still only one column which means // they affect all columns, so we have to multiply the height used // with the number of columns. dysAvailableHeight -= (dysHeightUsed * m_numberMainStreamColumns); } // Now we know all the objects fit (or else we weren't allowed to fail), so // adjust the rectangle occupied by the element. // First time thru, the previous "element" is the bottom page margin. // So far we only have one, but the code here shows vestiges of the loop in the // main AddDependentObjects. int ysTopOfPrevElement = Publication.PageHeightInPrinterPixels - BottomMarginInPrinterPixels; if (newHeight > 0) AddOrAdjustPageElement(page, ysTopOfPrevElement, newHeight, dependentStream, 0); dysAvailHeight = dysAvailableHeight; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the print layout configurer. /// </summary> /// <param name="fIntroDivision">set to <c>true</c> for a division that displays book /// title and introduction material, <c>false</c> for a division that displays main /// scripture text.</param> /// <param name="hvoBook">The hvo of the book.</param> /// <param name="sharedStream">A layout stream used for footnotes which is shared across /// multiple divisions</param> /// <param name="ws">The writing system</param> /// <returns>A print layout configurer</returns> /// ------------------------------------------------------------------------------------ protected override TePrintLayoutConfig GetPrintLayoutConfigurer(bool fIntroDivision, int hvoBook, IVwLayoutStream sharedStream, int ws) { return(new TeBtPrintLayoutConfig(m_cache, m_stylesheet, m_publication, m_viewType, m_filterInstance, m_printDateTime, fIntroDivision, hvoBook, sharedStream, ws)); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the number of printer pixels (source/layout units) from the top of the given /// division's main layout stream to the top of the data represented by the first page /// element on this page for that stream. This may only be an estimate, particularly if: /// <list type="normal"> /// <item>this page has no elements (at least for the given division)</item> /// <item>this page is broken</item> /// <item>there are previous pages that are not fully laid out (or broken)</item> /// </list> /// </summary> /// <param name="stream">The stream whose offset we want (may or may not be the main /// layout stream for the given division, but must not be null).</param> /// <param name="div">The division layout manager (can be null if the stream is not /// a main layout stream).</param> /// <param name="pe">The first page element on this page for the given stream.</param> /// <returns>The offset</returns> /// ------------------------------------------------------------------------------------ internal int OffsetFromTopOfDiv(IVwLayoutStream stream, DivisionLayoutMgr div, out PageElement pe) { CheckDisposed(); pe = GetFirstElementForStream(stream); if (pe != null) return pe.OffsetToTopPageBoundary; return (div == PubControl.Divisions[FirstDivOnPage]) ? m_ypOffsetFromTopOfDiv : 0; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adds a shared substream. /// </summary> /// <param name="subStream">The substream.</param> /// ------------------------------------------------------------------------------------ protected void AddSharedSubstream(IVwLayoutStream subStream) { (subStream as IVwRootBox).SetSite(this); m_sharedStreams.Add(subStream); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Gets the position of the point pt on the page. /// </summary> /// <param name="stream">The stream.</param> /// <param name="pt">The point in the stream.</param> /// <param name="result">the converted result</param> /// <returns>true if <paramref name="pt"/> is on this page.</returns> /// ------------------------------------------------------------------------------------ public bool GetPositionOnPage(IVwLayoutStream stream, Point pt, out Point result) { // find page element that contains pt foreach (PageElement pe in PageElements) { if (pt.Y <= pe.OffsetToTopPageBoundary + pe.ColumnHeight && pe.m_stream == stream) { if (pe.OffsetToTopPageBoundary <= pt.Y || pe.IsInOurPartOfOverlap(pt)) { int x = pe.LocationOnPage.Left + pt.X; int y = pe.LocationOnPage.Top + (pt.Y - pe.OffsetToTopPageBoundary); result = new Point(x, y); return true; } } } result = new Point(-1, -1); return false; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Adds a page element, representing a layout stream in a particular location on the /// page. /// </summary> /// <param name="division">The division</param> /// <param name="stream">The stream (rootbox) which supplies data for this element</param> /// <param name="fPageElementOwnsStream"><c>true</c> if this element is responsible for /// closing its stream when it is destoyed</param> /// <param name="locationOnPage">Location where this stream is laid out, in printer /// pixels, relative to the top left of the physical page</param> /// <param name="dypOffsetToTopOfDataOnPage">Offset in stream to top of data being shown /// on this page, in printer pixels</param> /// <param name="fMainStream"><c>true</c> if this element is for a "main" stream; /// <c>false</c> if it's for a subordinate stream or a Header/Footer stream</param> /// <param name="currentColumn">The current column (1-based).</param> /// <param name="totalColumns">The total columns in the specified stream.</param> /// <param name="columnGap">The gap between the columns.</param> /// <param name="columnHeight">The height of the current column.</param> /// <param name="dypOverlapWithPreviousElement"></param> /// <param name="isRightToLeft">if set to <c>true</c> the stream is right-to-left. /// Otherwise, it is left-to-right.</param> /// <param name="fReducesFreeSpaceFromTop">Flag indicating whether additoin of this /// element reduces the free space from top or bottom.</param> /// ------------------------------------------------------------------------------------ internal protected void AddPageElement(DivisionLayoutMgr division, IVwLayoutStream stream, bool fPageElementOwnsStream, Rectangle locationOnPage, int dypOffsetToTopOfDataOnPage, bool fMainStream, int currentColumn, int totalColumns, int columnGap, int columnHeight, int dypOverlapWithPreviousElement, bool isRightToLeft, bool fReducesFreeSpaceFromTop) { CheckDisposed(); PageElement newElement = new PageElement(division, stream, fPageElementOwnsStream, locationOnPage, dypOffsetToTopOfDataOnPage, fMainStream, currentColumn, totalColumns, columnGap, columnHeight, dypOverlapWithPreviousElement, isRightToLeft); InsertPageElement(newElement); AdjustFreeSpace(locationOnPage, fReducesFreeSpaceFromTop, newElement); }
///// ------------------------------------------------------------------------------------ ///// <summary> ///// True if the page is ready for drawing. When this is true, the page had better not ///// get broken; otherwise, bad stuff will happen. ///// For tests, we don't actually want to set this because we don't really draw the ///// pages, so this flag never gets cleared. It's purpose in the production code is just ///// to catch problems. ///// </summary> ///// ------------------------------------------------------------------------------------ //internal virtual bool ReadyForDrawing //{ // set // { // CheckDisposed(); // Debug.Assert(!m_fBroken); // m_fReadyForDrawing = value; // } //} private void DisposeDependentObjectStream() { if (m_dependentObjectRootStream != null) { // we'll need a new root box when next laid out // Enhance JohnT: could we save time and effort by retaining it to reuse // if the page is reused? //PageElement element = GetFirstElementForStream(m_dependentObjectRootStream); //if (element != null) // m_pageElements.Remove(element); // Review JohnT: anything else to do?? (m_dependentObjectRootStream as IVwRootBox).Close(); m_dependentObjectRootStream = null; } }
/// ------------------------------------------------------------------------------------ /// <summary> /// Retrieves the page element that corresponds to the given stream. If multiple /// elements correspond to this stream, it gets the one with the smallest offset in the /// division (i.e., the one which corresponds to the highest place in the /// total document). /// </summary> /// <param name="stream">The stream</param> /// <returns>The page element that corresponds to the given stream, or null if none /// found.</returns> /// ------------------------------------------------------------------------------------ public PageElement GetFirstElementForStream(IVwLayoutStream stream) { CheckDisposed(); foreach (PageElement pe in m_pageElements) { if (pe.m_stream == stream) return pe; } return null; }
/// ------------------------------------------------------------------------------------- /// <summary> /// Configurer should call this method for each shared subordinate stream (such as /// foootnotes) after creating the main stream. /// </summary> /// <param name="stream">The shared subordinate stream.</param> /// <param name="vc">The view constructor to be used for laying out this stream</param> /// <param name="subStreamDelegate">Implements view-specific callback methods</param> /// ------------------------------------------------------------------------------------- public void AddSharedSubordinateStream(IVwLayoutStream stream, IVwViewConstructor vc, ISubordinateStreamDelegate subStreamDelegate) { CheckDisposed(); SubordinateStream subStream; subStream.m_fShared = true; subStream.m_vc = vc; subStream.m_delegate = subStreamDelegate; subStream.m_stream = stream; // We're not always the manager for the shared stream, but sometimes, and it is // better to have a valid object as manager then to get a crash :-) subStream.m_stream.SetManager(this); m_subStreams.Add(subStream); }
/// ------------------------------------------------------------------------------------ /// <summary> /// Executes in two distinct scenarios. /// 1. If disposing is true, the method has been called directly /// or indirectly by a user's code via the Dispose method. /// Both managed and unmanaged resources can be disposed. /// 2. If disposing is false, the method has been called by the /// runtime from inside the finalizer and you should not reference (access) /// other managed objects, as they already have been garbage collected. /// Only unmanaged resources can be disposed. /// </summary> /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; /// <c>false</c> to release only unmanaged resources.</param> /// <remarks> /// If any exceptions are thrown, that is fine. /// If the method is being done in a finalizer, it will be ignored. /// If it is thrown by client code calling Dispose, /// it needs to be handled by fixing the bug. /// If subclasses override this method, they should call the base implementation. /// </remarks> /// ------------------------------------------------------------------------------------ protected virtual void Dispose(bool disposing) { // Must not be run more than once. if (m_isDisposed) return; if (disposing) { // Dispose managed resources here. foreach (PageElement pe in m_pageElements) pe.Dispose(); if (m_pageElements != null) m_pageElements.Clear(); if (m_dependentObjectRootStream != null) { (m_dependentObjectRootStream as IVwRootBox).Close(); m_dependentObjectRootStream = null; } } // Dispose unmanaged resources here, whether disposing is true or false. m_pageElements = null; m_pub = null; m_isDisposed = true; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Configure the main view and stuff. /// </summary> /// <remarks>This should only get called once during the lifetime of this object /// </remarks> /// ------------------------------------------------------------------------------------ protected internal void Configure() { if (m_configurer == null || m_configurer.DataAccess == null || m_mainLayoutStream != null) return; int hvoMainObj = m_configurer.MainObjectId; if (hvoMainObj == 0) return; m_mainVc = m_configurer.MakeMainVc(this); m_mainLayoutStream = VwLayoutStreamClass.Create(); m_mainLayoutStream.SetManager(this); PublicationControl.SetAccessibleStreamName(m_mainLayoutStream, m_Name); IVwRootBox rootbox = MainRootBox; rootbox.SetSite(Publication); m_configurer.ConfigureSubordinateViews(this); rootbox.DataAccess = m_configurer.DataAccess; rootbox.SetRootObject(hvoMainObj, m_mainVc, m_configurer.MainFragment, m_configurer.StyleSheet); // This was taken out as it was causing lazy boxes to be expanded that hadn't been // layed out yet. We still get an initial selection (set in PublicationControl.OnPaint) // so it seems to be fine. // try // { // rootbox.MakeSimpleSel(true, true, false, true); // } // catch // { // } }
/// ------------------------------------------------------------------------------------- /// <summary> /// Informs PrintLayout that the page boundary at the end of the specified page moved, /// without changing the size of the paragraph. This call is made when editing occurs in /// the first part of a paragraph that is split across two pages, and material is moved /// from one page to the other as a result, but the material moved does not include any /// object references. (If it does include object refs, PageBroken is called instead.) /// </summary> /// <param name="lay">The primary layout stream filling the page</param> /// <param name="hPage">The handle to the page being laid out</param> /// <param name="ichOld">the old character position within the affected paragraph</param> /// ------------------------------------------------------------------------------------- public void PageBoundaryMoved(IVwLayoutStream lay, int hPage, int ichOld) { CheckDisposed(); // TODO: Add PrintLayout.PageBoundaryMoved implementation }
/// ------------------------------------------------------------------------------------- /// <summary> /// The layout manager is informed by this method that the (primary) layout stream 'lay' /// has determined that references to the objects objectGuids occur on the page. The input /// value of dysAvailHeight indicates how much of the height allocated to 'lay' for this /// page will remain available if the text containing these references is added to the /// page (assuming that adding them does not reduce the space available for 'lay'). /// </summary> /// <param name="lay">The primary layout stream filling the page</param> /// <param name="vg">The graphics object being used to layout the page</param> /// <param name="hPage">The handle to the page being laid out</param> /// <param name="cguid">Number of elements in objectGuids array</param> /// <param name="objectGuids">Array of GUIDS representing objects to be laid out in a /// separate layout stream</param> /// <param name="fAllowFail">Indicates whether this method can fail (return /// <c>fFailed == true</c>). If this is false, this method should force the requested /// objects to be laid out within the available space, even if it requires omitting or /// truncating some or all of them</param> /// <param name="fFailed">If the available height would become negative (typically /// because the objects must share space with 'lay' and they don't fit in the available /// height), this will be set to true (unless fAllowFail is false).</param> /// <param name="dysAvailHeight">Input value indicates how much of the height allocated /// to 'lay' for this page will remain available if the text containing these references /// is added to the page, assuming that adding them does not reduce the space available /// for 'lay'. The output value indicates how much is left after laying out these /// dependent objects.</param> /// ------------------------------------------------------------------------------------- public virtual void AddDependentObjects(IVwLayoutStream lay, IVwGraphics vg, int hPage, int cguid, Guid[] objectGuids, bool fAllowFail, out bool fFailed, ref int dysAvailHeight) { CheckDisposed(); if (m_configurer.RootOnEachPage) { AddDependentObjectsToPageRoot(lay, vg, hPage, cguid, objectGuids, fAllowFail, out fFailed, ref dysAvailHeight); return; } int dysAvailableHeight = dysAvailHeight; fFailed = false; int[] rgHvo = new int[cguid]; int i = 0; foreach (Guid guid in objectGuids) { rgHvo[i++] = m_configurer.GetIdFromGuid(guid); } // Attempt to add all objects to any stream(s) that care about them. Don't // commit changes to any streams until we see if everything will fit. int[] rgdysNewStreamHeight = new int[m_subStreams.Count]; int iSubStream = -1; foreach (SubordinateStream subStream in m_subStreams) { subStream.m_stream.SetManager(this); // Set this every time for the sake of shared streams iSubStream++; int dysInitialPageHeight = subStream.m_stream.PageHeight(hPage); foreach (int hvo in rgHvo) { if (hvo == 0) continue; // Unable to find object in database. (TE-5007) SelLevInfo[] rgSelLevInfo = subStream.m_delegate.GetPathToObject(hvo); if (rgSelLevInfo == null) continue; // This stream doesn't display this object. subStream.m_stream.LayoutObj(vg, AvailablePageWidthInPrinterPixels, 0, rgSelLevInfo.Length, rgSelLevInfo, hPage); } int dysHeightWithAddedObjects = subStream.m_stream.PageHeight(hPage); rgdysNewStreamHeight[iSubStream] = dysHeightWithAddedObjects; int dysHeightUsed = dysHeightWithAddedObjects - dysInitialPageHeight; // If this stream is just now being added to the page, need to allow for gap between elements. if (dysInitialPageHeight == 0) dysHeightUsed += VerticalGapBetweenElements * vg.YUnitsPerInch / MiscUtils.kdzmpInch; if ((dysHeightUsed * m_numberMainStreamColumns) > dysAvailHeight) { // We can't add everything needed for the current chunk (in the main stream), // so we need to fail (if that's permitted), and roll everything back if (fAllowFail) fFailed = true; else dysAvailableHeight = 0; break; } else { // When we layout with multiple columns, we pretend to have one large // page. But the substreams are still only one column which means // they affect all columns, so we have to multiply the height used // with the number of columns. dysAvailableHeight -= (dysHeightUsed * m_numberMainStreamColumns); } } // Now we know all the objects fit (or else we weren't allowed to fail), so // remove or commit the objects we just added to any streams AND adjust // the rectangle occupied by each element so they "stack" properly. Page page = Publication.FindPage(hPage); // First time thru, the previous "element" is the bottom page margin. int ysTopOfPrevElement = Publication.PageHeightInPrinterPixels - BottomMarginInPrinterPixels; for (; iSubStream >= 0; iSubStream--) { SubordinateStream subStream = m_subStreams[iSubStream]; if (fFailed) { subStream.m_stream.RollbackLayoutObjects(hPage); } else { subStream.m_stream.CommitLayoutObjects(hPage); ysTopOfPrevElement = AddOrAdjustPageElement(page, ysTopOfPrevElement, rgdysNewStreamHeight[iSubStream], subStream.m_stream, subStream.m_stream.PagePostion(hPage)); } } if (!fFailed) dysAvailHeight = dysAvailableHeight; }
/// ------------------------------------------------------------------------------------ /// <summary> /// Informs PrintLayout that the specified page is broken. This is the most drastic of /// several notifications, sent when the View code cannot determine a more specific way /// to describe what has happened. For example, it may be that there has been a change /// drastic enough to completely replace the paragraph at one of the page boundaries. /// Or, material containing object references may have been inserted or deleted. /// </summary> /// <param name="lay">The primary layout stream filling the page</param> /// <param name="hPage">The handle to the page being laid out</param> /// ------------------------------------------------------------------------------------ public virtual void PageBroken(IVwLayoutStream lay, int hPage) { CheckDisposed(); if (hPage == m_hPageBeingBuilt) return; Page page = Publication.FindPage(hPage); if (page == null || page.IsDisposed) { // Already disposed of for some other reason? return; } // Todo: Some invalidating of the element may be needed. // Forget all the page elements on the broken page...the next PrepareToDraw will // create new, correct ones. (The element sending the message has already // discarded its record of the page, but other elements should do so as well.) foreach (PageElement pe in page.PageElements) if (pe.m_stream != lay) pe.m_stream.DiscardPage(hPage); page.Broken = true; }
// /// ------------------------------------------------------------------------------------ // /// <summary> // /// Determine the gap between the columns. // /// </summary> // /// <param name="numberColumns">The total number of columns.</param> // /// <returns> // /// If the element spans the whole width of the page, the column gap is 0. // /// Otherwise, it is ColumnGapWidthInPrinterPixels; // /// </returns> // /// ------------------------------------------------------------------------------------ // private int ColumnGap(int numberColumns) // { // return (numberColumns > 1) ? ColumnGapWidthInPrinterPixels : 0; // } /// ------------------------------------------------------------------------------------ /// <summary> /// Adds or adjusts the page element. Note that this is used ONLY for dependent objects, /// it arranges them from the bottom up. These elements don't overlap, so no overlap is /// passed. /// </summary> /// <param name="page">The page.</param> /// <param name="ysTopOfPrevElement">The top of the previous element.</param> /// <param name="ysStreamHeight">Height of the stream.</param> /// <param name="stream">The stream.</param> /// <param name="pagePosition">The page position.</param> /// <returns></returns> /// ------------------------------------------------------------------------------------ private int AddOrAdjustPageElement(Page page, int ysTopOfPrevElement, int ysStreamHeight, IVwLayoutStream stream, int pagePosition) { Debug.Assert(!page.IsDisposed); if (ysStreamHeight <= 0) return ysTopOfPrevElement; int ysTopOfThisElement = ysTopOfPrevElement - ysStreamHeight; Rectangle rectLocationOnPage = new Rectangle(LeftMarginInPrinterPixels(page), ysTopOfThisElement, AvailablePageWidthInPrinterPixels, ysStreamHeight); PageElement element = page.GetFirstElementForStream(stream); if (element == null) { // Create page element page.AddPageElement(this, stream, false, rectLocationOnPage, pagePosition, false, 1, 1, 0, ysStreamHeight, 0, MainStreamIsRightToLeft, false); } else { // Increase size of page element if (element.LocationOnPage.Height != ysStreamHeight) { // Increase size of/move location page.AdjustPageElement(element, rectLocationOnPage, false); } } return ysTopOfThisElement; }