diff options
Diffstat (limited to 'sw/source/core/view/pagepreviewlayout.cxx')
-rw-r--r-- | sw/source/core/view/pagepreviewlayout.cxx | 1465 |
1 files changed, 1465 insertions, 0 deletions
diff --git a/sw/source/core/view/pagepreviewlayout.cxx b/sw/source/core/view/pagepreviewlayout.cxx new file mode 100644 index 000000000..5fc740ebf --- /dev/null +++ b/sw/source/core/view/pagepreviewlayout.cxx @@ -0,0 +1,1465 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_wasm_strip.h> + +#include <pagepreviewlayout.hxx> +#include <prevwpage.hxx> + +#include <algorithm> +#include <osl/diagnose.h> +#include <tools/fract.hxx> +#include <vcl/settings.hxx> + +#include <rootfrm.hxx> +#include <pagefrm.hxx> +#include <viewsh.hxx> +#include <viewimp.hxx> +#include <viewopt.hxx> +#include <swregion.hxx> +#include <strings.hrc> +#include <frmtool.hxx> +#include <sfx2/zoomitem.hxx> +#include <printdata.hxx> +#include <paintfrm.hxx> + +#include <IDocumentDeviceAccess.hxx> + +// methods to initialize page preview layout + +SwPagePreviewLayout::SwPagePreviewLayout( SwViewShell& _rParentViewShell, + const SwRootFrame& _rLayoutRootFrame ) + : mrParentViewShell( _rParentViewShell ), + mrLayoutRootFrame ( _rLayoutRootFrame ) +{ + Clear_(); + + mbBookPreview = false; + mbBookPreviewModeToggled = false; + + mbPrintEmptyPages = mrParentViewShell.getIDocumentDeviceAccess().getPrintData().IsPrintEmptyPages(); +} + +void SwPagePreviewLayout::Clear_() +{ + mbLayoutInfoValid = mbLayoutSizesValid = mbPaintInfoValid = false; + + maWinSize.setWidth( 0 ); + maWinSize.setHeight( 0 ); + mnCols = mnRows = 0; + + ClearPreviewLayoutSizes(); + + mbDoesLayoutRowsFitIntoWindow = false; + mbDoesLayoutColsFitIntoWindow = false; + + mnPaintPhyStartPageNum = 0; + mnPaintStartCol = mnPaintStartRow = 0; + mbNoPageVisible = false; + maPaintStartPageOffset.setX( 0 ); + maPaintStartPageOffset.setY( 0 ); + maPaintPreviewDocOffset.setX( 0 ); + maPaintPreviewDocOffset.setY( 0 ); + maAdditionalPaintOffset.setX( 0 ); + maAdditionalPaintOffset.setY( 0 ); + maPaintedPreviewDocRect.SetLeft( 0 ); + maPaintedPreviewDocRect.SetTop( 0 ); + maPaintedPreviewDocRect.SetRight( 0 ); + maPaintedPreviewDocRect.SetBottom( 0 ); + mnSelectedPageNum = 0; + ClearPreviewPageData(); + + mbInPaint = false; + mbNewLayoutDuringPaint = false; +} + +void SwPagePreviewLayout::ClearPreviewLayoutSizes() +{ + mnPages = 0; + + maMaxPageSize.setWidth( 0 ); + maMaxPageSize.setHeight( 0 ); + maPreviewDocRect.SetLeft( 0 ); + maPreviewDocRect.SetTop( 0 ); + maPreviewDocRect.SetRight( 0 ); + maPreviewDocRect.SetBottom( 0 ); + mnColWidth = mnRowHeight = 0; + mnPreviewLayoutWidth = mnPreviewLayoutHeight = 0; +} + +void SwPagePreviewLayout::ClearPreviewPageData() +{ + maPreviewPages.clear(); +} + +/** calculate page preview layout sizes + +*/ +void SwPagePreviewLayout::CalcPreviewLayoutSizes() +{ + vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut(); + // calculate maximal page size; calculate also number of pages + + const SwPageFrame* pPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower()); + while ( pPage ) + { + if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() ) + { + pPage = static_cast<const SwPageFrame*>(pPage->GetNext()); + continue; + } + + ++mnPages; + pPage->Calc(pRenderContext); + const Size& rPageSize = pPage->getFrameArea().SSize(); + if ( rPageSize.Width() > maMaxPageSize.Width() ) + maMaxPageSize.setWidth( rPageSize.Width() ); + if ( rPageSize.Height() > maMaxPageSize.Height() ) + maMaxPageSize.setHeight( rPageSize.Height() ); + pPage = static_cast<const SwPageFrame*>(pPage->GetNext()); + } + // calculate and set column width and row height + mnColWidth = maMaxPageSize.Width() + gnXFree; + mnRowHeight = maMaxPageSize.Height() + gnYFree; + + // calculate and set preview layout width and height + mnPreviewLayoutWidth = mnCols * mnColWidth + gnXFree; + mnPreviewLayoutHeight = mnRows * mnRowHeight + gnYFree; + + // calculate document rectangle in preview layout + { + Size aDocSize; + // document width + aDocSize.setWidth( mnPreviewLayoutWidth ); + + // document height + // determine number of rows needed for <nPages> in preview layout + // use method <GetRowOfPage(..)>. + const sal_uInt16 nDocRows = GetRowOfPage( mnPages ); + aDocSize.setHeight( nDocRows * maMaxPageSize.Height() + + (nDocRows+1) * gnYFree ); + maPreviewDocRect.SetPos( Point( 0, 0 ) ); + maPreviewDocRect.SetSize( aDocSize ); + } +} + +/** init page preview layout + + initialize the page preview settings for a given layout. + + side effects: + (1) If parameter <_bCalcScale> is true, mapping mode with calculated + scaling is set at the output device and the zoom at the view options of + the given view shell is set with the calculated scaling. +*/ +void SwPagePreviewLayout::Init( const sal_uInt16 _nCols, + const sal_uInt16 _nRows, + const Size& _rPxWinSize + ) +{ + // check environment and parameters + { + bool bColsRowsValid = (_nCols != 0) && (_nRows != 0); + OSL_ENSURE( bColsRowsValid, "preview layout parameters not correct - preview layout can *not* be initialized" ); + if ( !bColsRowsValid ) + return; + + bool bPxWinSizeValid = (_rPxWinSize.Width() >= 0) && + (_rPxWinSize.Height() >= 0); + OSL_ENSURE( bPxWinSizeValid, "no window size - preview layout can *not* be initialized" ); + if ( !bPxWinSizeValid ) + return; + } + + // environment and parameters ok + + // clear existing preview settings + Clear_(); + + // set layout information columns and rows + mnCols = _nCols; + mnRows = _nRows; + + CalcPreviewLayoutSizes(); + + // validate layout information + mbLayoutInfoValid = true; + + // calculate scaling + MapMode aMapMode( MapUnit::MapTwip ); + Size aWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize, aMapMode ); + Fraction aXScale( aWinSize.Width(), mnPreviewLayoutWidth ); + Fraction aYScale( aWinSize.Height(), mnPreviewLayoutHeight ); + if( aXScale < aYScale ) + aYScale = aXScale; + { + // adjust scaling for Drawing layer. + aYScale *= Fraction( 1000, 1 ); + tools::Long nNewNuminator = aYScale.operator long(); + if( nNewNuminator < 1 ) + nNewNuminator = 1; + aYScale = Fraction( nNewNuminator, 1000 ); + // propagate scaling as zoom percentage to view options for font cache + ApplyNewZoomAtViewShell( static_cast<sal_uInt8>(nNewNuminator/10) ); + + aMapMode.SetScaleY( aYScale ); + aMapMode.SetScaleX( aYScale ); + // set created mapping mode with calculated scaling at output device. + mrParentViewShell.GetOut()->SetMapMode( aMapMode ); + // update statics for paint. + ::SwCalcPixStatics( mrParentViewShell.GetOut() ); + } + + // set window size in twips + maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize ); + // validate layout sizes + mbLayoutSizesValid = true; +} + +/** apply new zoom at given view shell */ +void SwPagePreviewLayout::ApplyNewZoomAtViewShell( sal_uInt8 _aNewZoom ) +{ + SwViewOption aNewViewOptions = *(mrParentViewShell.GetViewOptions()); + if ( aNewViewOptions.GetZoom() != _aNewZoom ) + { + aNewViewOptions.SetZoom( _aNewZoom ); + //#i19975# - consider zoom type. + aNewViewOptions.SetZoomType( SvxZoomType::PERCENT ); + mrParentViewShell.ApplyViewOptions( aNewViewOptions ); + } +} + +/** method to adjust page preview layout to document changes + +*/ +void SwPagePreviewLayout::ReInit() +{ + // check environment and parameters + { + bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid; + OSL_ENSURE( bLayoutSettingsValid, + "no valid preview layout info/sizes - no re-init of page preview layout"); + if ( !bLayoutSettingsValid ) + return; + } + + ClearPreviewLayoutSizes(); + CalcPreviewLayoutSizes(); +} + +// methods to prepare paint of page preview + +/** prepare paint of page preview + + delete parameter _onStartPageVirtNum + + @note _nProposedStartPageNum, _onStartPageNum are absolute +*/ +bool SwPagePreviewLayout::Prepare( const sal_uInt16 _nProposedStartPageNum, + const Point& rProposedStartPos, + const Size& _rPxWinSize, + sal_uInt16& _onStartPageNum, + tools::Rectangle& _orDocPreviewPaintRect, + const bool _bStartWithPageAtFirstCol + ) +{ + sal_uInt16 nProposedStartPageNum = ConvertAbsoluteToRelativePageNum( _nProposedStartPageNum ); + // check environment and parameters + { + bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid; + OSL_ENSURE( bLayoutSettingsValid, + "no valid preview layout info/sizes - no prepare of preview paint"); + if ( !bLayoutSettingsValid ) + return false; + + bool bStartPageRangeValid = nProposedStartPageNum <= mnPages; + OSL_ENSURE( bStartPageRangeValid, + "proposed start page not existing - no prepare of preview paint"); + if ( !bStartPageRangeValid ) + return false; + + bool bStartPosRangeValid = + rProposedStartPos.X() >= 0 && rProposedStartPos.Y() >= 0 && + rProposedStartPos.X() <= maPreviewDocRect.Right() && + rProposedStartPos.Y() <= maPreviewDocRect.Bottom(); + OSL_ENSURE( bStartPosRangeValid, + "proposed start position out of range - no prepare of preview paint"); + if ( !bStartPosRangeValid ) + return false; + + bool bWinSizeValid = !_rPxWinSize.IsEmpty(); + OSL_ENSURE( bWinSizeValid, "no window size - no prepare of preview paint"); + if ( !bWinSizeValid ) + return false; + + bool bStartInfoValid = _nProposedStartPageNum > 0 || + rProposedStartPos != Point(0,0); + if ( !bStartInfoValid ) + nProposedStartPageNum = 1; + } + + // environment and parameter ok + + // update window size at preview setting data + maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize ); + + mbNoPageVisible = false; + if ( nProposedStartPageNum > 0 ) + { + // determine column and row of proposed start page in virtual preview layout + const sal_uInt16 nColOfProposed = GetColOfPage( nProposedStartPageNum ); + const sal_uInt16 nRowOfProposed = GetRowOfPage( nProposedStartPageNum ); + // determine start page + if ( _bStartWithPageAtFirstCol ) + { + // leaving left-top-corner blank is + // controlled by <mbBookPreview>. + if ( mbBookPreview && + ( nProposedStartPageNum == 1 || nRowOfProposed == 1 ) + ) + mnPaintPhyStartPageNum = 1; + else + mnPaintPhyStartPageNum = nProposedStartPageNum - (nColOfProposed-1); + } + else + mnPaintPhyStartPageNum = nProposedStartPageNum; + + mnPaintPhyStartPageNum = ConvertRelativeToAbsolutePageNum( mnPaintPhyStartPageNum ); + + // set starting column + if ( _bStartWithPageAtFirstCol ) + mnPaintStartCol = 1; + else + mnPaintStartCol = nColOfProposed; + // set starting row + mnPaintStartRow = nRowOfProposed; + // page offset == (-1,-1), indicating no offset and paint of free space. + maPaintStartPageOffset.setX( -1 ); + maPaintStartPageOffset.setY( -1 ); + // virtual preview document offset. + if ( _bStartWithPageAtFirstCol ) + maPaintPreviewDocOffset.setX( 0 ); + else + maPaintPreviewDocOffset.setX( (nColOfProposed-1) * mnColWidth ); + maPaintPreviewDocOffset.setY( (nRowOfProposed-1) * mnRowHeight ); + } + else + { + // determine column and row of proposed start position. + // Note: paint starts at point (0,0) + const sal_uInt16 nColOfProposed = + o3tl::narrowing<sal_uInt16>(rProposedStartPos.X() / mnColWidth) + 1; + const sal_uInt16 nRowOfProposed = + o3tl::narrowing<sal_uInt16>(rProposedStartPos.Y() / mnRowHeight) + 1; + // determine start page == page at proposed start position + // leaving left-top-corner blank is + // controlled by <mbBookPreview>. + if ( mbBookPreview && + ( nRowOfProposed == 1 && nColOfProposed == 1 ) + ) + mnPaintPhyStartPageNum = 1; + else + { + // leaving left-top-corner blank is + // controlled by <mbBookPreview>. + mnPaintPhyStartPageNum = (nRowOfProposed-1) * mnCols + nColOfProposed; + if ( mbBookPreview ) + --mnPaintPhyStartPageNum; + if ( mnPaintPhyStartPageNum > mnPages ) + { + // no page will be visible, because shown part of document + // preview is the last row to the right of the last page + mnPaintPhyStartPageNum = mnPages; + mbNoPageVisible = true; + } + } + // set starting column and starting row + mnPaintStartCol = nColOfProposed; + mnPaintStartRow = nRowOfProposed; + // page offset + maPaintStartPageOffset.setX( + (rProposedStartPos.X() % mnColWidth) - gnXFree ); + maPaintStartPageOffset.setY( + (rProposedStartPos.Y() % mnRowHeight) - gnYFree ); + // virtual preview document offset. + maPaintPreviewDocOffset = rProposedStartPos; + } + + // determine additional paint offset, if preview layout fits into window. + CalcAdditionalPaintOffset(); + + // determine rectangle to be painted from document preview + CalcDocPreviewPaintRect(); + _orDocPreviewPaintRect = maPaintedPreviewDocRect; + + // shift visible preview document area to the left, + // if on the right is an area left blank. + if ( !mbDoesLayoutColsFitIntoWindow && + maPaintedPreviewDocRect.GetWidth() < maWinSize.Width() ) + { + maPaintedPreviewDocRect.Move( + -(maWinSize.Width() - maPaintedPreviewDocRect.GetWidth()), 0 ); + Prepare( 0, maPaintedPreviewDocRect.TopLeft(), + _rPxWinSize, _onStartPageNum, + _orDocPreviewPaintRect, _bStartWithPageAtFirstCol ); + } + + // shift visible preview document area to the top, + // if on the bottom is an area left blank. + if ( mbBookPreviewModeToggled && + maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom() && + maPaintedPreviewDocRect.GetHeight() < maWinSize.Height() ) + { + if ( mbDoesLayoutRowsFitIntoWindow ) + { + if ( maPaintedPreviewDocRect.GetHeight() < mnPreviewLayoutHeight) + { + maPaintedPreviewDocRect.Move( + 0, -(mnPreviewLayoutHeight - maPaintedPreviewDocRect.GetHeight()) ); + Prepare( 0, maPaintedPreviewDocRect.TopLeft(), + _rPxWinSize, _onStartPageNum, + _orDocPreviewPaintRect, _bStartWithPageAtFirstCol ); + } + } + else + { + maPaintedPreviewDocRect.Move( + 0, -(maWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) ); + Prepare( 0, maPaintedPreviewDocRect.TopLeft(), + _rPxWinSize, _onStartPageNum, + _orDocPreviewPaintRect, _bStartWithPageAtFirstCol ); + } + } + + // determine preview pages - visible pages with needed data for paint and + // accessible pages with needed data. + CalcPreviewPages(); + + // OD 07.11.2003 #i22014# - indicate new layout, if print preview is in paint + if ( mbInPaint ) + { + mbNewLayoutDuringPaint = true; + } + + // validate paint data + mbPaintInfoValid = true; + + // return start page + _onStartPageNum = mnPaintPhyStartPageNum; + + return true; +} + +/** calculate additional paint offset + +*/ +void SwPagePreviewLayout::CalcAdditionalPaintOffset() +{ + if ( mnPreviewLayoutWidth <= maWinSize.Width() && + maPaintStartPageOffset.X() <= 0 ) + { + mbDoesLayoutColsFitIntoWindow = true; + maAdditionalPaintOffset.setX( (maWinSize.Width() - mnPreviewLayoutWidth) / 2 ); + } + else + { + mbDoesLayoutColsFitIntoWindow = false; + maAdditionalPaintOffset.setX( 0 ); + } + + if ( mnPreviewLayoutHeight <= maWinSize.Height() && + maPaintStartPageOffset.Y() <= 0 ) + { + mbDoesLayoutRowsFitIntoWindow = true; + maAdditionalPaintOffset.setY( (maWinSize.Height() - mnPreviewLayoutHeight) / 2 ); + } + else + { + mbDoesLayoutRowsFitIntoWindow = false; + maAdditionalPaintOffset.setY( 0 ); + } +} + +/** calculate painted preview document rectangle + +*/ +void SwPagePreviewLayout::CalcDocPreviewPaintRect() +{ + Point aTopLeftPos = maPaintPreviewDocOffset; + maPaintedPreviewDocRect.SetPos( aTopLeftPos ); + + Size aSize; + if ( mbDoesLayoutColsFitIntoWindow ) + aSize.setWidth( std::min( tools::Long(mnPreviewLayoutWidth), + maPreviewDocRect.GetWidth() - aTopLeftPos.X() ) ); + else + aSize.setWidth( std::min( maPreviewDocRect.GetWidth() - aTopLeftPos.X(), + maWinSize.Width() - maAdditionalPaintOffset.X() ) ); + if ( mbDoesLayoutRowsFitIntoWindow ) + aSize.setHeight( std::min( tools::Long(mnPreviewLayoutHeight), + maPreviewDocRect.GetHeight() - aTopLeftPos.Y() ) ); + else + aSize.setHeight( std::min( maPreviewDocRect.GetHeight() - aTopLeftPos.Y(), + maWinSize.Height() - maAdditionalPaintOffset.Y() ) ); + maPaintedPreviewDocRect.SetSize( aSize ); +} + +/** calculate preview pages + +*/ +void SwPagePreviewLayout::CalcPreviewPages() +{ + vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut(); + ClearPreviewPageData(); + + if ( mbNoPageVisible ) + return; + + // determine start page frame + const SwPageFrame* pStartPage = mrLayoutRootFrame.GetPageByPageNum( mnPaintPhyStartPageNum ); + + // calculate initial paint offset + Point aInitialPaintOffset; + /// check whether RTL interface or not + if(!AllSettings::GetLayoutRTL()){ + if ( maPaintStartPageOffset != Point( -1, -1 ) ) + aInitialPaintOffset = Point(0,0) - maPaintStartPageOffset; + else + aInitialPaintOffset = Point( gnXFree, gnYFree ); + } + else { + if ( maPaintStartPageOffset != Point( -1, -1 ) ) + aInitialPaintOffset = Point(0 + ((SwPagePreviewLayout::mnCols-1)*mnColWidth),0) - maPaintStartPageOffset; + else + aInitialPaintOffset = Point( gnXFree + ((SwPagePreviewLayout::mnCols-1)*mnColWidth), gnYFree ); + } + aInitialPaintOffset += maAdditionalPaintOffset; + + // prepare loop data + const SwPageFrame* pPage = pStartPage; + sal_uInt16 nCurrCol = mnPaintStartCol; + sal_uInt16 nConsideredRows = 0; + Point aCurrPaintOffset = aInitialPaintOffset; + // loop on pages to determine preview background rectangles + while ( pPage && + (!mbDoesLayoutRowsFitIntoWindow || nConsideredRows < mnRows) && + aCurrPaintOffset.Y() < maWinSize.Height() + ) + { + if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() ) + { + pPage = static_cast<const SwPageFrame*>(pPage->GetNext()); + continue; + } + + pPage->Calc(pRenderContext); + + // consider only pages, which have to be painted. + if ( nCurrCol < mnPaintStartCol ) + { + // calculate data of unvisible page needed for accessibility + std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage); + Point aCurrAccOffset = aCurrPaintOffset - + Point( (mnPaintStartCol-nCurrCol) * mnColWidth, 0 ); + CalcPreviewDataForPage( *pPage, aCurrAccOffset, pPreviewPage.get() ); + pPreviewPage->bVisible = false; + maPreviewPages.push_back( std::move(pPreviewPage) ); + // continue with next page and next column + pPage = static_cast<const SwPageFrame*>(pPage->GetNext()); + ++nCurrCol; + continue; + } + if ( aCurrPaintOffset.X() < maWinSize.Width() ) + { + // leaving left-top-corner blank is + // controlled by <mbBookPreview>. + if ( mbBookPreview && pPage->GetPhyPageNum() == 1 && mnCols != 1 && nCurrCol == 1 + ) + { + // first page in 2nd column + // --> continue with increased paint offset and next column + /// check whether RTL interface or not + if(!AllSettings::GetLayoutRTL()) + aCurrPaintOffset.AdjustX(mnColWidth ); + else aCurrPaintOffset.AdjustX( -mnColWidth ); + ++nCurrCol; + continue; + } + + // calculate data of visible page + std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage); + CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() ); + pPreviewPage->bVisible = true; + maPreviewPages.push_back( std::move(pPreviewPage) ); + } + else + { + // calculate data of unvisible page needed for accessibility + std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage); + CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() ); + pPreviewPage->bVisible = false; + maPreviewPages.push_back( std::move(pPreviewPage) ); + } + + // prepare data for next loop + pPage = static_cast<const SwPageFrame*>(pPage->GetNext()); + + /// check whether RTL interface or not + if(!AllSettings::GetLayoutRTL()) + aCurrPaintOffset.AdjustX(mnColWidth ); + else aCurrPaintOffset.AdjustX( -mnColWidth ); + ++nCurrCol; + if ( nCurrCol > mnCols ) + { + ++nConsideredRows; + aCurrPaintOffset.setX( aInitialPaintOffset.X() ); + nCurrCol = 1; + aCurrPaintOffset.AdjustY(mnRowHeight ); + } + } +} + +/** determines preview data for a given page and a given preview offset + + OD 13.12.2002 #103492# +*/ +void SwPagePreviewLayout::CalcPreviewDataForPage( const SwPageFrame& _rPage, + const Point& _rPreviewOffset, + PreviewPage* _opPreviewPage ) +{ + // page frame + _opPreviewPage->pPage = &_rPage; + // size of page frame + if ( _rPage.IsEmptyPage() ) + { + if ( _rPage.GetPhyPageNum() % 2 == 0 ) + _opPreviewPage->aPageSize = _rPage.GetPrev()->getFrameArea().SSize(); + else + _opPreviewPage->aPageSize = _rPage.GetNext()->getFrameArea().SSize(); + } + else + _opPreviewPage->aPageSize = _rPage.getFrameArea().SSize(); + // position of page in preview window + Point aPreviewWinOffset( _rPreviewOffset ); + if ( _opPreviewPage->aPageSize.Width() < maMaxPageSize.Width() ) + aPreviewWinOffset.AdjustX(( maMaxPageSize.Width() - _opPreviewPage->aPageSize.Width() ) / 2 ); + if ( _opPreviewPage->aPageSize.Height() < maMaxPageSize.Height() ) + aPreviewWinOffset.AdjustY(( maMaxPageSize.Height() - _opPreviewPage->aPageSize.Height() ) / 2 ); + _opPreviewPage->aPreviewWinPos = aPreviewWinOffset; + // logic position of page and mapping offset for paint + if ( _rPage.IsEmptyPage() ) + { + _opPreviewPage->aLogicPos = _opPreviewPage->aPreviewWinPos; + _opPreviewPage->aMapOffset = Point( 0, 0 ); + } + else + { + _opPreviewPage->aLogicPos = _rPage.getFrameArea().Pos(); + _opPreviewPage->aMapOffset = _opPreviewPage->aPreviewWinPos - _opPreviewPage->aLogicPos; + } +} + +/** enable/disable book preview + + OD 2004-03-04 #i18143# +*/ +bool SwPagePreviewLayout::SetBookPreviewMode( const bool _bEnableBookPreview, + sal_uInt16& _onStartPageNum, + tools::Rectangle& _orDocPreviewPaintRect ) +{ + if ( mbBookPreview != _bEnableBookPreview) + { + mbBookPreview = _bEnableBookPreview; + // re-initialize page preview layout + ReInit(); + // re-prepare page preview layout + { + mbBookPreviewModeToggled = true; + Point aProposedStartPos( maPaintPreviewDocOffset ); + // if proposed start position is below virtual preview document + // bottom, adjust it to the virtual preview document bottom + if ( aProposedStartPos.Y() > maPreviewDocRect.Bottom() ) + { + aProposedStartPos.setY( maPreviewDocRect.Bottom() ); + } + Prepare( 0, aProposedStartPos, + mrParentViewShell.GetOut()->LogicToPixel( maWinSize ), + _onStartPageNum, _orDocPreviewPaintRect ); + mbBookPreviewModeToggled = false; + } + + return true; + } + + return false; +} + +// methods to determine new data for changing the current shown part of the +// document preview. + +/** calculate start position for new scale + +*/ +Point SwPagePreviewLayout::GetPreviewStartPosForNewScale( + const Fraction& _aNewScale, + const Fraction& _aOldScale, + const Size& _aNewWinSize ) const +{ + Point aNewPaintStartPos = maPaintedPreviewDocRect.TopLeft(); + if ( _aNewScale < _aOldScale ) + { + // increase paint width by moving start point to left. + if ( mnPreviewLayoutWidth < _aNewWinSize.Width() ) + aNewPaintStartPos.setX( 0 ); + else if ( maPaintedPreviewDocRect.GetWidth() < _aNewWinSize.Width() ) + { + aNewPaintStartPos.AdjustX( -( + (_aNewWinSize.Width() - maPaintedPreviewDocRect.GetWidth()) / 2) ); + if ( aNewPaintStartPos.X() < 0) + aNewPaintStartPos.setX( 0 ); + } + + if ( !mbDoesLayoutRowsFitIntoWindow ) + { + // increase paint height by moving start point to top. + if ( mnPreviewLayoutHeight < _aNewWinSize.Height() ) + { + aNewPaintStartPos.setY( + (mnPaintStartRow - 1) * mnRowHeight ); + } + else if ( maPaintedPreviewDocRect.GetHeight() < _aNewWinSize.Height() ) + { + aNewPaintStartPos.AdjustY( -( + (_aNewWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) / 2) ); + if ( aNewPaintStartPos.Y() < 0) + aNewPaintStartPos.setY( 0 ); + } + } + } + else + { + // decrease paint width by moving start point to right + if ( maPaintedPreviewDocRect.GetWidth() > _aNewWinSize.Width() ) + aNewPaintStartPos.AdjustX( + (maPaintedPreviewDocRect.GetWidth() - _aNewWinSize.Width()) / 2 ); + // decrease paint height by moving start point to bottom + if ( maPaintedPreviewDocRect.GetHeight() > _aNewWinSize.Height() ) + { + aNewPaintStartPos.AdjustY( + (maPaintedPreviewDocRect.GetHeight() - _aNewWinSize.Height()) / 2 ); + // check, if new y-position is outside document preview + if ( aNewPaintStartPos.Y() > maPreviewDocRect.Bottom() ) + aNewPaintStartPos.setY( + std::max( tools::Long(0), maPreviewDocRect.Bottom() - mnPreviewLayoutHeight ) ); + } + } + + return aNewPaintStartPos; +} + +/** determines, if page with given page number is visible in preview + + @note _nPageNum is absolute +*/ +bool SwPagePreviewLayout::IsPageVisible( const sal_uInt16 _nPageNum ) const +{ + const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum ); + return pPreviewPage && pPreviewPage->bVisible; +} + +/** calculate data to bring new selected page into view. + + @note IN/OUT parameters are absolute page numbers!!! +*/ +void SwPagePreviewLayout::CalcStartValuesForSelectedPageMove( + const sal_Int16 _nHoriMove, + const sal_Int16 _nVertMove, + sal_uInt16& _orNewSelectedPage, + sal_uInt16& _orNewStartPage, + Point& _orNewStartPos ) const +{ + // determine position of current selected page + sal_uInt16 nTmpRelSelPageNum = ConvertAbsoluteToRelativePageNum( mnSelectedPageNum ); + sal_uInt16 nNewRelSelectedPageNum = nTmpRelSelPageNum; + + const sal_uInt16 nCurrRow = GetRowOfPage(nTmpRelSelPageNum); + + // determine new selected page number + { + if ( _nHoriMove != 0 ) + { + if ( (nNewRelSelectedPageNum + _nHoriMove) < 1 ) + nNewRelSelectedPageNum = 1; + else if ( (nNewRelSelectedPageNum + _nHoriMove) > mnPages ) + nNewRelSelectedPageNum = mnPages; + else + nNewRelSelectedPageNum = nNewRelSelectedPageNum + _nHoriMove; + } + if ( _nVertMove != 0 ) + { + if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) < 1 ) + nNewRelSelectedPageNum = 1; + else if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) > mnPages ) + nNewRelSelectedPageNum = mnPages; + else + nNewRelSelectedPageNum += ( _nVertMove * mnCols ); + } + } + + sal_uInt16 nNewStartPage = mnPaintPhyStartPageNum; + Point aNewStartPos(0,0); + + const sal_uInt16 nNewAbsSelectedPageNum = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum ); + if ( !IsPageVisible( nNewAbsSelectedPageNum ) ) + { + if ( _nHoriMove != 0 && _nVertMove != 0 ) + { + OSL_FAIL( "missing implementation for moving preview selected page horizontal AND vertical"); + return; + } + + // new selected page has to be brought into view considering current + // visible preview. + const sal_uInt16 nTotalRows = GetRowOfPage( mnPages ); + if ( (_nHoriMove > 0 || _nVertMove > 0) && + mbDoesLayoutRowsFitIntoWindow && + mbDoesLayoutColsFitIntoWindow && + nCurrRow > nTotalRows - mnRows ) + { + // new proposed start page = left-top-corner of last possible + // preview page. + nNewStartPage = (nTotalRows - mnRows) * mnCols + 1; + // leaving left-top-corner blank is controlled + // by <mbBookPreview>. + if ( mbBookPreview ) + { + // Note: decrease new proposed start page number by one, + // because of blank left-top-corner + --nNewStartPage; + } + nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewStartPage ); + } + else + { + // new proposed start page = new selected page. + nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum ); + } + } + + _orNewSelectedPage = nNewAbsSelectedPageNum; + _orNewStartPage = nNewStartPage; + _orNewStartPos = aNewStartPos; +} + +namespace { + +/** checks, if given position is inside a shown document page */ +struct PreviewPosInsidePagePred +{ + const Point mnPreviewPos; + explicit PreviewPosInsidePagePred(const Point& rPreviewPos) + : mnPreviewPos( rPreviewPos ) + {} + bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage ) + { + if ( _pPreviewPage->bVisible ) + { + tools::Rectangle aPreviewPageRect( _pPreviewPage->aPreviewWinPos, _pPreviewPage->aPageSize ); + return aPreviewPageRect.Contains( mnPreviewPos ); + } + return false; + } +}; + +} + +bool SwPagePreviewLayout::IsPreviewPosInDocPreviewPage( const Point& rPreviewPos, + Point& _orDocPos, + bool& _obPosInEmptyPage, + sal_uInt16& _onPageNum ) const +{ + // initialize variable parameter values. + _orDocPos.setX( 0 ); + _orDocPos.setY( 0 ); + _obPosInEmptyPage = false; + _onPageNum = 0; + + auto aFoundPreviewPageIter = + std::find_if( maPreviewPages.begin(), maPreviewPages.end(), + PreviewPosInsidePagePred( rPreviewPos ) ); + + if ( aFoundPreviewPageIter != maPreviewPages.end() ) + { + // given preview position is inside a document page. + _onPageNum = (*aFoundPreviewPageIter)->pPage->GetPhyPageNum(); + _obPosInEmptyPage = (*aFoundPreviewPageIter)->pPage->IsEmptyPage(); + if ( !_obPosInEmptyPage ) + { + // given preview position inside a normal page + _orDocPos = rPreviewPos - + (*aFoundPreviewPageIter)->aPreviewWinPos + + (*aFoundPreviewPageIter)->aLogicPos; + return true; + } + } + + return false; +} + +/** determine window page scroll amount */ +SwTwips SwPagePreviewLayout::GetWinPagesScrollAmount( + const sal_Int16 _nWinPagesToScroll ) const +{ + SwTwips nScrollAmount; + if ( mbDoesLayoutRowsFitIntoWindow ) + { + nScrollAmount = (mnPreviewLayoutHeight - gnYFree) * _nWinPagesToScroll; + } + else + nScrollAmount = _nWinPagesToScroll * maPaintedPreviewDocRect.GetHeight(); + + // check, if preview layout size values are valid. + // If not, the checks for an adjustment of the scroll amount aren't useful. + if ( mbLayoutSizesValid ) + { + if ( (maPaintedPreviewDocRect.Top() + nScrollAmount) <= 0 ) + nScrollAmount = -maPaintedPreviewDocRect.Top(); + + // correct scroll amount + if ( nScrollAmount > 0 && + maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom() + ) + { + nScrollAmount = 0; + } + else + { + while ( (maPaintedPreviewDocRect.Top() + nScrollAmount + gnYFree) >= maPreviewDocRect.GetHeight() ) + { + nScrollAmount -= mnRowHeight; + } + } + } + + return nScrollAmount; +} + +// methods to paint page preview layout + +namespace +{ +/// Similar to RenderContextGuard, but does not touch the draw view. +class PreviewRenderContextGuard +{ + VclPtr<vcl::RenderContext> m_pOriginalValue; + SwViewShell& m_rShell; + +public: + PreviewRenderContextGuard(SwViewShell& rShell, vcl::RenderContext* pValue) + : m_pOriginalValue(rShell.GetOut()), + m_rShell(rShell) + { + m_rShell.SetOut(pValue); + } + + ~PreviewRenderContextGuard() + { + m_rShell.SetOut(m_pOriginalValue); + } +}; +} + +/** paint prepared preview + +*/ +bool SwPagePreviewLayout::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rOutRect) const +{ + PreviewRenderContextGuard aGuard(mrParentViewShell, &rRenderContext); + // check environment and parameters + { + if (!mrParentViewShell.GetWin() && !mrParentViewShell.GetOut()->GetConnectMetaFile()) + { + return false; + } + + OSL_ENSURE(mbPaintInfoValid, "invalid preview settings - no paint of preview"); + if (!mbPaintInfoValid) + return false; + } + + // OD 17.11.2003 #i22014# - no paint, if <superfluous> flag is set at layout + if (mrLayoutRootFrame.IsSuperfluous()) + { + return true; + } + + // environment and parameter ok + + if (mbInPaint) + { + return false; + } + mbInPaint = true; + + OutputDevice* pOutputDev = &rRenderContext; + + // prepare paint + if ( !maPreviewPages.empty() ) + { + mrParentViewShell.Imp()->m_bFirstPageInvalid = false; + mrParentViewShell.Imp()->m_pFirstVisiblePage = + const_cast<SwPageFrame*>(maPreviewPages[0]->pPage); + } + + // paint preview background + { + SwRegionRects aPreviewBackgrdRegion((SwRect(rOutRect))); + // calculate preview background rectangles + for ( auto & rpPreviewPage : maPreviewPages ) + { + if ( rpPreviewPage->bVisible ) + { + aPreviewBackgrdRegion -= + SwRect( rpPreviewPage->aPreviewWinPos, rpPreviewPage->aPageSize ); + } + } + // paint preview background rectangles + mrParentViewShell.PaintDesktop_(aPreviewBackgrdRegion); + } + + // prepare data for paint of pages + const tools::Rectangle aPxOutRect( pOutputDev->LogicToPixel(rOutRect) ); + + MapMode aMapMode( pOutputDev->GetMapMode() ); + MapMode aSavedMapMode = aMapMode; + + const vcl::Font& rEmptyPgFont = SwPageFrame::GetEmptyPageFont(); + + for ( auto & rpPreviewPage : maPreviewPages ) + { + if ( !rpPreviewPage->bVisible ) + continue; + + tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize ); + aMapMode.SetOrigin( rpPreviewPage->aMapOffset ); + pOutputDev->SetMapMode( aMapMode ); + tools::Rectangle aPxPaintRect = pOutputDev->LogicToPixel( aPageRect ); + if ( aPxOutRect.Overlaps( aPxPaintRect) ) + { + const SwPageFrame* pPage = rpPreviewPage->pPage; + + if (pPage->IsEmptyPage()) + { + const Color aRetouche( mrParentViewShell.Imp()->GetRetoucheColor() ); + if( pOutputDev->GetFillColor() != aRetouche ) + pOutputDev->SetFillColor( aRetouche ); + pOutputDev->SetLineColor(); // no line color + // use aligned page rectangle + { + SwRect aTmpPageRect( aPageRect ); + ::SwAlignRect( aTmpPageRect, &mrParentViewShell, &rRenderContext ); + aPageRect = aTmpPageRect.SVRect(); + } + pOutputDev->DrawRect( aPageRect ); + + // paint empty page text + vcl::Font aOldFont( pOutputDev->GetFont() ); + pOutputDev->SetFont( rEmptyPgFont ); + pOutputDev->DrawText( aPageRect, SwResId( STR_EMPTYPAGE ), + DrawTextFlags::VCenter | + DrawTextFlags::Center | + DrawTextFlags::Clip ); + pOutputDev->SetFont( aOldFont ); + // paint shadow and border for empty page + // use new method to paint page border and shadow + SwPageFrame::PaintBorderAndShadow( SwRect(aPageRect), &mrParentViewShell, true, false, true ); + } + else + { + const bool bIsLeftShadowed = pPage->IsLeftShadowNeeded(); + const bool bIsRightShadowed = pPage->IsRightShadowNeeded(); + + mrParentViewShell.maVisArea = SwRect(aPageRect); + aPxPaintRect.Intersection( aPxOutRect ); + tools::Rectangle aPaintRect = pOutputDev->PixelToLogic( aPxPaintRect ); + mrParentViewShell.Paint(rRenderContext, aPaintRect); + + // --> OD 2007-08-15 #i80691# + // paint page border and shadow + { + SwRect aPageBorderRect; + SwPageFrame::GetBorderAndShadowBoundRect( SwRect( aPageRect ), &mrParentViewShell, &rRenderContext, aPageBorderRect, + bIsLeftShadowed, bIsRightShadowed, true ); + const vcl::Region aDLRegion(aPageBorderRect.SVRect()); + mrParentViewShell.DLPrePaint2(aDLRegion); + SwPageFrame::PaintBorderAndShadow( SwRect(aPageRect), &mrParentViewShell, true, false, true ); + mrParentViewShell.DLPostPaint2(true); + } + // <-- + } + // OD 07.11.2003 #i22014# - stop painting, because new print + // preview layout is created during paint. + if ( mbNewLayoutDuringPaint ) + { + break; + } + + if (pPage->GetPhyPageNum() == mnSelectedPageNum) + { + PaintSelectMarkAtPage(rRenderContext, rpPreviewPage.get()); + } + } + } + + // OD 17.11.2003 #i22014# - no update of accessible preview, if a new + // print preview layout is created during paint. +#if !ENABLE_WASM_STRIP_ACCESSIBILITY + if ( !mbNewLayoutDuringPaint ) + { + // update at accessibility interface + mrParentViewShell.Imp()->UpdateAccessiblePreview( + maPreviewPages, + aMapMode.GetScaleX(), + mrLayoutRootFrame.GetPageByPageNum( mnSelectedPageNum ), + maWinSize ); + } +#endif + + pOutputDev->SetMapMode( aSavedMapMode ); + mrParentViewShell.maVisArea.Clear(); + + // OD 07.11.2003 #i22014# + mbInPaint = false; + mbNewLayoutDuringPaint = false; + + return true; +} + +/** repaint pages on page preview + + OD 18.12.2002 #103492# +*/ +void SwPagePreviewLayout::Repaint( const tools::Rectangle& rInvalidCoreRect ) const +{ + // check environment and parameters + { + if ( !mrParentViewShell.GetWin() && + !mrParentViewShell.GetOut()->GetConnectMetaFile() ) + return; + + OSL_ENSURE( mbPaintInfoValid, + "invalid preview settings - no paint of preview" ); + if ( !mbPaintInfoValid ) + return; + } + + // environment and parameter ok + + // prepare paint + if ( !maPreviewPages.empty() ) + { + mrParentViewShell.Imp()->m_bFirstPageInvalid = false; + mrParentViewShell.Imp()->m_pFirstVisiblePage = + const_cast<SwPageFrame*>(maPreviewPages[0]->pPage); + } + + // invalidate visible pages, which overlap the invalid core rectangle + for ( auto & rpPreviewPage : maPreviewPages ) + { + if ( !rpPreviewPage->bVisible ) + continue; + + tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize ); + if ( rInvalidCoreRect.Overlaps( aPageRect ) ) + { + aPageRect.Intersection(rInvalidCoreRect); + tools::Rectangle aInvalidPreviewRect = aPageRect; + aInvalidPreviewRect.SetPos( aInvalidPreviewRect.TopLeft() - + rpPreviewPage->aLogicPos + + rpPreviewPage->aPreviewWinPos ); + mrParentViewShell.GetWin()->Invalidate( aInvalidPreviewRect ); + } + } +} + +/** paint selection mark at page + + OD 17.12.2002 #103492# +*/ +void SwPagePreviewLayout::PaintSelectMarkAtPage(vcl::RenderContext& rRenderContext, + const PreviewPage* _aSelectedPreviewPage ) const +{ + OutputDevice* pOutputDev = &rRenderContext; + MapMode aMapMode( pOutputDev->GetMapMode() ); + // save mapping mode of output device + MapMode aSavedMapMode = aMapMode; + // save fill and line color of output device + Color aFill( pOutputDev->GetFillColor() ); + Color aLine( pOutputDev->GetLineColor() ); + + // determine selection mark color + Color aSelPgLineColor(117, 114, 106); + const StyleSettings& rSettings = + mrParentViewShell.GetWin()->GetSettings().GetStyleSettings(); + if ( rSettings.GetHighContrastMode() ) + aSelPgLineColor = rSettings.GetHighlightTextColor(); + + // set needed mapping mode at output device + aMapMode.SetOrigin( _aSelectedPreviewPage->aMapOffset ); + pOutputDev->SetMapMode( aMapMode ); + + // calculate page rectangle in pixel coordinates + SwRect aPageRect( _aSelectedPreviewPage->aLogicPos, + _aSelectedPreviewPage->aPageSize ); + // OD 19.02.2003 #107369# - use aligned page rectangle, as it is used for + // page border and shadow paint - see <SwPageFrame::PaintBorderAndShadow(..)> + ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev ); + tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() ); + + // draw two rectangle + // OD 19.02.2003 #107369# - adjust position of select mark rectangle + tools::Rectangle aRect( aPxPageRect.Left(), aPxPageRect.Top(), + aPxPageRect.Right(), aPxPageRect.Bottom() ); + aRect = pOutputDev->PixelToLogic( aRect ); + pOutputDev->SetFillColor(); // OD 20.02.2003 #107369# - no fill color + pOutputDev->SetLineColor( aSelPgLineColor ); + pOutputDev->DrawRect( aRect ); + // OD 19.02.2003 #107369# - adjust position of select mark rectangle + aRect = tools::Rectangle( aPxPageRect.Left()+1, aPxPageRect.Top()+1, + aPxPageRect.Right()-1, aPxPageRect.Bottom()-1 ); + aRect = pOutputDev->PixelToLogic( aRect ); + pOutputDev->DrawRect( aRect ); + + // reset fill and line color of output device + pOutputDev->SetFillColor( aFill ); + pOutputDev->SetLineColor( aLine ); + + // reset mapping mode of output device + pOutputDev->SetMapMode( aSavedMapMode ); +} + +/** paint to mark new selected page + + OD 17.12.2002 #103492# + Perform paint for current selected page in order to unmark it. + Set new selected page and perform paint to mark this page. + + @note _nSelectedPage, mnSelectedPage are absolute +*/ +void SwPagePreviewLayout::MarkNewSelectedPage( const sal_uInt16 _nSelectedPage ) +{ + const sal_uInt16 nOldSelectedPageNum = mnSelectedPageNum; + mnSelectedPageNum = _nSelectedPage; + + // re-paint for current selected page in order to unmark it. + const PreviewPage* pOldSelectedPreviewPage = GetPreviewPageByPageNum( nOldSelectedPageNum ); + OutputDevice* pOutputDev = mrParentViewShell.GetOut(); + if ( pOldSelectedPreviewPage && pOldSelectedPreviewPage->bVisible ) + { + // OD 20.02.2003 #107369# - invalidate only areas of selection mark. + SwRect aPageRect( pOldSelectedPreviewPage->aPreviewWinPos, + pOldSelectedPreviewPage->aPageSize ); + ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev ); + tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() ); + // invalidate top mark line + tools::Rectangle aInvalPxRect( aPxPageRect.Left(), aPxPageRect.Top(), + aPxPageRect.Right(), aPxPageRect.Top()+1 ); + mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) ); + // invalidate right mark line + aInvalPxRect = tools::Rectangle( aPxPageRect.Right()-1, aPxPageRect.Top(), + aPxPageRect.Right(), aPxPageRect.Bottom() ); + mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) ); + // invalidate bottom mark line + aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Bottom()-1, + aPxPageRect.Right(), aPxPageRect.Bottom() ); + mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) ); + // invalidate left mark line + aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Top(), + aPxPageRect.Left()+1, aPxPageRect.Bottom() ); + mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) ); + } + + // re-paint for new selected page in order to mark it. + const PreviewPage* pNewSelectedPreviewPage = GetPreviewPageByPageNum( _nSelectedPage ); + if ( pNewSelectedPreviewPage && pNewSelectedPreviewPage->bVisible ) + { + const PreviewPage* pSelectedPreviewPage = GetPreviewPageByPageNum(mnSelectedPageNum); + SwRect aPageRect(pSelectedPreviewPage->aPreviewWinPos, pSelectedPreviewPage->aPageSize); + ::SwAlignRect(aPageRect, &mrParentViewShell, pOutputDev); + mrParentViewShell.GetWin()->Invalidate(aPageRect.SVRect()); + } +} + +// helper methods + +namespace { + +/** get preview page by physical page number + + OD 17.12.2002 #103492# +*/ +struct EqualsPageNumPred +{ + const sal_uInt16 mnPageNum; + explicit EqualsPageNumPred(const sal_uInt16 _nPageNum) + : mnPageNum( _nPageNum ) + {} + bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage ) + { + return _pPreviewPage->pPage->GetPhyPageNum() == mnPageNum; + } +}; + +} + +const PreviewPage* SwPagePreviewLayout::GetPreviewPageByPageNum( const sal_uInt16 _nPageNum ) const +{ + auto aFoundPreviewPageIter = + std::find_if( maPreviewPages.begin(), maPreviewPages.end(), + EqualsPageNumPred( _nPageNum ) ); + + if ( aFoundPreviewPageIter == maPreviewPages.end() ) + return nullptr; + + return aFoundPreviewPageIter->get(); +} + +/** determine row the page with the given number is in + + OD 17.01.2003 #103492# + + @note _nPageNum is relative +*/ +sal_uInt16 SwPagePreviewLayout::GetRowOfPage( sal_uInt16 _nPageNum ) const +{ + // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled + // by <mbBookPreview>. + if ( mbBookPreview ) + { + // Note: increase given physical page number by one, because left-top-corner + // in the preview layout is left blank. + ++_nPageNum; + } + + return _nPageNum / mnCols + ((_nPageNum % mnCols)>0 ? 1 : 0); +} + +/** determine column the page with the given number is in + + OD 17.01.2003 #103492# + + @note _nPageNum is relative +*/ +sal_uInt16 SwPagePreviewLayout::GetColOfPage( sal_uInt16 _nPageNum ) const +{ + // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled + // by <mbBookPreview>. + if ( mbBookPreview ) + { + // Note: increase given physical page number by one, because left-top-corner + // in the preview layout is left blank. + ++_nPageNum; + } + + const sal_uInt16 nCol = _nPageNum % mnCols; + return nCol ? nCol : mnCols; +} + +Size SwPagePreviewLayout::GetPreviewDocSize() const +{ + OSL_ENSURE( PreviewLayoutValid(), "PagePreviewLayout not valid" ); + return maPreviewDocRect.GetSize(); +} + +/** get size of a preview page by its physical page number + + OD 15.01.2003 #103492# +*/ +Size SwPagePreviewLayout::GetPreviewPageSizeByPageNum( sal_uInt16 _nPageNum ) const +{ + const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum ); + if ( pPreviewPage ) + { + return pPreviewPage->aPageSize; + } + return Size( 0, 0 ); +} + +/** get virtual page number by its physical page number + + OD 21.03.2003 #108282# +*/ +sal_uInt16 SwPagePreviewLayout::GetVirtPageNumByPageNum( sal_uInt16 _nPageNum ) const +{ + const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum ); + if ( pPreviewPage ) + { + return pPreviewPage->pPage->GetVirtPageNum(); + } + return 0; +} + +/** Convert absolute to relative page numbers (see PrintEmptyPages) */ +sal_uInt16 SwPagePreviewLayout::ConvertAbsoluteToRelativePageNum( sal_uInt16 _nAbsPageNum ) const +{ + if ( mbBookPreview || mbPrintEmptyPages || !_nAbsPageNum ) + { + return _nAbsPageNum; + } + + const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower()); + + sal_uInt16 nRet = 1; + + while ( pTmpPage && pTmpPage->GetPhyPageNum() != _nAbsPageNum ) + { + if ( !pTmpPage->IsEmptyPage() ) + ++nRet; + + pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() ); + } + + return nRet; +} + +/** Convert relative to absolute page numbers (see PrintEmptyPages) */ +sal_uInt16 SwPagePreviewLayout::ConvertRelativeToAbsolutePageNum( sal_uInt16 _nRelPageNum ) const +{ + if ( mbBookPreview || mbPrintEmptyPages || !_nRelPageNum ) + { + return _nRelPageNum; + } + + const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower()); + const SwPageFrame* pRet = nullptr; + + sal_uInt16 i = 0; + while( pTmpPage && i != _nRelPageNum ) + { + if ( !pTmpPage->IsEmptyPage() ) + ++i; + + pRet = pTmpPage; + pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() ); + } + + return pRet->GetPhyPageNum(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |