1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <vcl/svapp.hxx>
21 
22 #include <pagepreviewlayout.hxx>
23 #include <prevwpage.hxx>
24 
25 #include <algorithm>
26 #include <tools/fract.hxx>
27 #include <vcl/window.hxx>
28 #include <vcl/settings.hxx>
29 
30 #include <rootfrm.hxx>
31 #include <pagefrm.hxx>
32 #include <viewsh.hxx>
33 #include <viewimp.hxx>
34 #include <viewopt.hxx>
35 #include <swregion.hxx>
36 #include <strings.hrc>
37 #include <frmtool.hxx>
38 #include <sfx2/zoomitem.hxx>
39 #include <printdata.hxx>
40 #include <paintfrm.hxx>
41 
42 #include <IDocumentDeviceAccess.hxx>
43 
44 // methods to initialize page preview layout
45 
SwPagePreviewLayout(SwViewShell & _rParentViewShell,const SwRootFrame & _rLayoutRootFrame)46 SwPagePreviewLayout::SwPagePreviewLayout( SwViewShell& _rParentViewShell,
47                                           const SwRootFrame& _rLayoutRootFrame )
48     : mrParentViewShell( _rParentViewShell ),
49       mrLayoutRootFrame ( _rLayoutRootFrame )
50 {
51     Clear_();
52 
53     mbBookPreview = false;
54     mbBookPreviewModeToggled = false;
55 
56     mbPrintEmptyPages = mrParentViewShell.getIDocumentDeviceAccess().getPrintData().IsPrintEmptyPages();
57 }
58 
Clear_()59 void SwPagePreviewLayout::Clear_()
60 {
61     mbLayoutInfoValid = mbLayoutSizesValid = mbPaintInfoValid = false;
62 
63     maWinSize.setWidth( 0 );
64     maWinSize.setHeight( 0 );
65     mnCols = mnRows = 0;
66 
67     ClearPreviewLayoutSizes();
68 
69     mbDoesLayoutRowsFitIntoWindow = false;
70     mbDoesLayoutColsFitIntoWindow = false;
71 
72     mnPaintPhyStartPageNum = 0;
73     mnPaintStartCol = mnPaintStartRow = 0;
74     mbNoPageVisible = false;
75     maPaintStartPageOffset.setX( 0 );
76     maPaintStartPageOffset.setY( 0 );
77     maPaintPreviewDocOffset.setX( 0 );
78     maPaintPreviewDocOffset.setY( 0 );
79     maAdditionalPaintOffset.setX( 0 );
80     maAdditionalPaintOffset.setY( 0 );
81     maPaintedPreviewDocRect.SetLeft( 0 );
82     maPaintedPreviewDocRect.SetTop( 0 );
83     maPaintedPreviewDocRect.SetRight( 0 );
84     maPaintedPreviewDocRect.SetBottom( 0 );
85     mnSelectedPageNum = 0;
86     ClearPreviewPageData();
87 
88     mbInPaint = false;
89     mbNewLayoutDuringPaint = false;
90 }
91 
ClearPreviewLayoutSizes()92 void SwPagePreviewLayout::ClearPreviewLayoutSizes()
93 {
94     mnPages = 0;
95 
96     maMaxPageSize.setWidth( 0 );
97     maMaxPageSize.setHeight( 0 );
98     maPreviewDocRect.SetLeft( 0 );
99     maPreviewDocRect.SetTop( 0 );
100     maPreviewDocRect.SetRight( 0 );
101     maPreviewDocRect.SetBottom( 0 );
102     mnColWidth = mnRowHeight = 0;
103     mnPreviewLayoutWidth = mnPreviewLayoutHeight = 0;
104 }
105 
ClearPreviewPageData()106 void SwPagePreviewLayout::ClearPreviewPageData()
107 {
108     maPreviewPages.clear();
109 }
110 
111 /** calculate page preview layout sizes
112 
113 */
CalcPreviewLayoutSizes()114 void SwPagePreviewLayout::CalcPreviewLayoutSizes()
115 {
116     vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut();
117     // calculate maximal page size; calculate also number of pages
118 
119     const SwPageFrame* pPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
120     while ( pPage )
121     {
122         if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() )
123         {
124             pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
125             continue;
126         }
127 
128         ++mnPages;
129         pPage->Calc(pRenderContext);
130         const Size& rPageSize = pPage->getFrameArea().SSize();
131         if ( rPageSize.Width() > maMaxPageSize.Width() )
132             maMaxPageSize.setWidth( rPageSize.Width() );
133         if ( rPageSize.Height() > maMaxPageSize.Height() )
134             maMaxPageSize.setHeight( rPageSize.Height() );
135         pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
136     }
137     // calculate and set column width and row height
138     mnColWidth = maMaxPageSize.Width() + gnXFree;
139     mnRowHeight = maMaxPageSize.Height() + gnYFree;
140 
141     // calculate and set preview layout width and height
142     mnPreviewLayoutWidth = mnCols * mnColWidth + gnXFree;
143     mnPreviewLayoutHeight = mnRows * mnRowHeight + gnYFree;
144 
145     // calculate document rectangle in preview layout
146     {
147         Size aDocSize;
148         // document width
149         aDocSize.setWidth( mnPreviewLayoutWidth );
150 
151         // document height
152         // determine number of rows needed for <nPages> in preview layout
153         // use method <GetRowOfPage(..)>.
154         const sal_uInt16 nDocRows = GetRowOfPage( mnPages );
155         aDocSize.setHeight( nDocRows * maMaxPageSize.Height() +
156                             (nDocRows+1) * gnYFree );
157         maPreviewDocRect.SetPos( Point( 0, 0 ) );
158         maPreviewDocRect.SetSize( aDocSize );
159     }
160 }
161 
162 /** init page preview layout
163 
164     initialize the page preview settings for a given layout.
165 
166     side effects:
167     (1) If parameter <_bCalcScale> is true, mapping mode with calculated
168     scaling is set at the output device and the zoom at the view options of
169     the given view shell is set with the calculated scaling.
170 */
Init(const sal_uInt16 _nCols,const sal_uInt16 _nRows,const Size & _rPxWinSize)171 void SwPagePreviewLayout::Init( const sal_uInt16 _nCols,
172                                 const sal_uInt16 _nRows,
173                                 const Size&      _rPxWinSize
174                               )
175 {
176     // check environment and parameters
177     {
178         bool bColsRowsValid = (_nCols != 0) && (_nRows != 0);
179         OSL_ENSURE( bColsRowsValid, "preview layout parameters not correct - preview layout can *not* be initialized" );
180         if ( !bColsRowsValid )
181             return;
182 
183         bool bPxWinSizeValid = (_rPxWinSize.Width() >= 0) &&
184                                (_rPxWinSize.Height() >= 0);
185         OSL_ENSURE( bPxWinSizeValid, "no window size - preview layout can *not* be initialized" );
186         if ( !bPxWinSizeValid )
187             return;
188     }
189 
190     // environment and parameters ok
191 
192     // clear existing preview settings
193     Clear_();
194 
195     // set layout information columns and rows
196     mnCols = _nCols;
197     mnRows = _nRows;
198 
199     CalcPreviewLayoutSizes();
200 
201     // validate layout information
202     mbLayoutInfoValid = true;
203 
204     // calculate scaling
205     MapMode aMapMode( MapUnit::MapTwip );
206     Size aWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize, aMapMode );
207     Fraction aXScale( aWinSize.Width(), mnPreviewLayoutWidth );
208     Fraction aYScale( aWinSize.Height(), mnPreviewLayoutHeight );
209     if( aXScale < aYScale )
210         aYScale = aXScale;
211     {
212         // adjust scaling for Drawing layer.
213         aYScale *= Fraction( 1000, 1 );
214         long nNewNuminator = aYScale.operator long();
215         if( nNewNuminator < 1 )
216             nNewNuminator = 1;
217         aYScale = Fraction( nNewNuminator, 1000 );
218         // propagate scaling as zoom percentage to view options for font cache
219         ApplyNewZoomAtViewShell( static_cast<sal_uInt8>(nNewNuminator/10) );
220 
221         aMapMode.SetScaleY( aYScale );
222         aMapMode.SetScaleX( aYScale );
223         // set created mapping mode with calculated scaling at output device.
224         mrParentViewShell.GetOut()->SetMapMode( aMapMode );
225         // update statics for paint.
226         ::SwCalcPixStatics( mrParentViewShell.GetOut() );
227     }
228 
229     // set window size in twips
230     maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize );
231     // validate layout sizes
232     mbLayoutSizesValid = true;
233 }
234 
235 /** apply new zoom at given view shell */
ApplyNewZoomAtViewShell(sal_uInt8 _aNewZoom)236 void SwPagePreviewLayout::ApplyNewZoomAtViewShell( sal_uInt8 _aNewZoom )
237 {
238     SwViewOption aNewViewOptions = *(mrParentViewShell.GetViewOptions());
239     if ( aNewViewOptions.GetZoom() != _aNewZoom )
240     {
241         aNewViewOptions.SetZoom( _aNewZoom );
242         //#i19975# - consider zoom type.
243         aNewViewOptions.SetZoomType( SvxZoomType::PERCENT );
244         mrParentViewShell.ApplyViewOptions( aNewViewOptions );
245     }
246 }
247 
248 /** method to adjust page preview layout to document changes
249 
250 */
ReInit()251 void SwPagePreviewLayout::ReInit()
252 {
253     // check environment and parameters
254     {
255         bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid;
256         OSL_ENSURE( bLayoutSettingsValid,
257                 "no valid preview layout info/sizes - no re-init of page preview layout");
258         if ( !bLayoutSettingsValid )
259             return;
260     }
261 
262     ClearPreviewLayoutSizes();
263     CalcPreviewLayoutSizes();
264 }
265 
266 // methods to prepare paint of page preview
267 
268 /** prepare paint of page preview
269 
270     delete parameter _onStartPageVirtNum
271 
272     @note _nProposedStartPageNum, _onStartPageNum are absolute
273 */
Prepare(const sal_uInt16 _nProposedStartPageNum,const Point & rProposedStartPos,const Size & _rPxWinSize,sal_uInt16 & _onStartPageNum,tools::Rectangle & _orDocPreviewPaintRect,const bool _bStartWithPageAtFirstCol)274 bool SwPagePreviewLayout::Prepare( const sal_uInt16 _nProposedStartPageNum,
275                                    const Point&      rProposedStartPos,
276                                    const Size&      _rPxWinSize,
277                                    sal_uInt16&      _onStartPageNum,
278                                    tools::Rectangle&       _orDocPreviewPaintRect,
279                                    const bool       _bStartWithPageAtFirstCol
280                                  )
281 {
282     sal_uInt16 nProposedStartPageNum = ConvertAbsoluteToRelativePageNum( _nProposedStartPageNum );
283     // check environment and parameters
284     {
285         bool bLayoutSettingsValid = mbLayoutInfoValid && mbLayoutSizesValid;
286         OSL_ENSURE( bLayoutSettingsValid,
287                 "no valid preview layout info/sizes - no prepare of preview paint");
288         if ( !bLayoutSettingsValid )
289             return false;
290 
291         bool bStartPageRangeValid = nProposedStartPageNum <= mnPages;
292         OSL_ENSURE( bStartPageRangeValid,
293                 "proposed start page not existing - no prepare of preview paint");
294         if ( !bStartPageRangeValid )
295             return false;
296 
297         bool bStartPosRangeValid =
298                 rProposedStartPos.X() >= 0 && rProposedStartPos.Y() >= 0 &&
299                 rProposedStartPos.X() <= maPreviewDocRect.Right() &&
300                 rProposedStartPos.Y() <= maPreviewDocRect.Bottom();
301         OSL_ENSURE( bStartPosRangeValid,
302                 "proposed start position out of range - no prepare of preview paint");
303         if ( !bStartPosRangeValid )
304             return false;
305 
306         bool bWinSizeValid = _rPxWinSize.Width() != 0 && _rPxWinSize.Height() != 0;
307         OSL_ENSURE( bWinSizeValid, "no window size - no prepare of preview paint");
308         if ( !bWinSizeValid )
309             return false;
310 
311         bool bStartInfoValid = _nProposedStartPageNum > 0 ||
312                                rProposedStartPos != Point(0,0);
313         if ( !bStartInfoValid )
314             nProposedStartPageNum = 1;
315     }
316 
317     // environment and parameter ok
318 
319     // update window size at preview setting data
320     maWinSize = mrParentViewShell.GetOut()->PixelToLogic( _rPxWinSize );
321 
322     mbNoPageVisible = false;
323     if ( nProposedStartPageNum > 0 )
324     {
325         // determine column and row of proposed start page in virtual preview layout
326         const sal_uInt16 nColOfProposed = GetColOfPage( nProposedStartPageNum );
327         const sal_uInt16 nRowOfProposed = GetRowOfPage( nProposedStartPageNum );
328         // determine start page
329         if ( _bStartWithPageAtFirstCol )
330         {
331             // leaving left-top-corner blank is
332             // controlled by <mbBookPreview>.
333             if ( mbBookPreview &&
334                  ( nProposedStartPageNum == 1 || nRowOfProposed == 1 )
335                )
336                 mnPaintPhyStartPageNum = 1;
337             else
338                 mnPaintPhyStartPageNum = nProposedStartPageNum - (nColOfProposed-1);
339         }
340         else
341             mnPaintPhyStartPageNum = nProposedStartPageNum;
342 
343         mnPaintPhyStartPageNum = ConvertRelativeToAbsolutePageNum( mnPaintPhyStartPageNum );
344 
345         // set starting column
346         if ( _bStartWithPageAtFirstCol )
347             mnPaintStartCol = 1;
348         else
349             mnPaintStartCol = nColOfProposed;
350         // set starting row
351         mnPaintStartRow = nRowOfProposed;
352         // page offset == (-1,-1), indicating no offset and paint of free space.
353         maPaintStartPageOffset.setX( -1 );
354         maPaintStartPageOffset.setY( -1 );
355         // virtual preview document offset.
356         if ( _bStartWithPageAtFirstCol )
357             maPaintPreviewDocOffset.setX( 0 );
358         else
359             maPaintPreviewDocOffset.setX( (nColOfProposed-1) * mnColWidth );
360         maPaintPreviewDocOffset.setY( (nRowOfProposed-1) * mnRowHeight );
361     }
362     else
363     {
364         // determine column and row of proposed start position.
365         // Note: paint starts at point (0,0)
366         const sal_uInt16 nColOfProposed =
367                 static_cast<sal_uInt16>(rProposedStartPos.X() / mnColWidth) + 1;
368         const sal_uInt16 nRowOfProposed =
369                 static_cast<sal_uInt16>(rProposedStartPos.Y() / mnRowHeight) + 1;
370         // determine start page == page at proposed start position
371         // leaving left-top-corner blank is
372         // controlled by <mbBookPreview>.
373         if ( mbBookPreview &&
374              ( nRowOfProposed == 1 && nColOfProposed == 1 )
375            )
376             mnPaintPhyStartPageNum = 1;
377         else
378         {
379             // leaving left-top-corner blank is
380             // controlled by <mbBookPreview>.
381             mnPaintPhyStartPageNum = (nRowOfProposed-1) * mnCols + nColOfProposed;
382             if ( mbBookPreview )
383                 --mnPaintPhyStartPageNum;
384             if ( mnPaintPhyStartPageNum > mnPages )
385             {
386                 // no page will be visible, because shown part of document
387                 // preview is the last row to the right of the last page
388                 mnPaintPhyStartPageNum = mnPages;
389                 mbNoPageVisible = true;
390             }
391         }
392         // set starting column and starting row
393         mnPaintStartCol = nColOfProposed;
394         mnPaintStartRow = nRowOfProposed;
395         // page offset
396         maPaintStartPageOffset.setX(
397                 (rProposedStartPos.X() % mnColWidth) - gnXFree );
398         maPaintStartPageOffset.setY(
399                 (rProposedStartPos.Y() % mnRowHeight) - gnYFree );
400         // virtual preview document offset.
401         maPaintPreviewDocOffset = rProposedStartPos;
402     }
403 
404     // determine additional paint offset, if preview layout fits into window.
405     CalcAdditionalPaintOffset();
406 
407     // determine rectangle to be painted from document preview
408     CalcDocPreviewPaintRect();
409     _orDocPreviewPaintRect = maPaintedPreviewDocRect;
410 
411     // shift visible preview document area to the left,
412     // if on the right is an area left blank.
413     if ( !mbDoesLayoutColsFitIntoWindow &&
414          maPaintedPreviewDocRect.GetWidth() < maWinSize.Width() )
415     {
416         maPaintedPreviewDocRect.Move(
417                 -(maWinSize.Width() - maPaintedPreviewDocRect.GetWidth()), 0 );
418         Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
419                  _rPxWinSize, _onStartPageNum,
420                  _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
421     }
422 
423     // shift visible preview document area to the top,
424     // if on the bottom is an area left blank.
425     if ( mbBookPreviewModeToggled &&
426          maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom() &&
427          maPaintedPreviewDocRect.GetHeight() < maWinSize.Height() )
428     {
429         if ( mbDoesLayoutRowsFitIntoWindow )
430         {
431             if ( maPaintedPreviewDocRect.GetHeight() < mnPreviewLayoutHeight)
432             {
433                 maPaintedPreviewDocRect.Move(
434                         0, -(mnPreviewLayoutHeight - maPaintedPreviewDocRect.GetHeight()) );
435                 Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
436                          _rPxWinSize, _onStartPageNum,
437                          _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
438             }
439         }
440         else
441         {
442             maPaintedPreviewDocRect.Move(
443                     0, -(maWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) );
444             Prepare( 0, maPaintedPreviewDocRect.TopLeft(),
445                      _rPxWinSize, _onStartPageNum,
446                      _orDocPreviewPaintRect, _bStartWithPageAtFirstCol );
447         }
448     }
449 
450     // determine preview pages - visible pages with needed data for paint and
451     // accessible pages with needed data.
452     CalcPreviewPages();
453 
454     // OD 07.11.2003 #i22014# - indicate new layout, if print preview is in paint
455     if ( mbInPaint )
456     {
457         mbNewLayoutDuringPaint = true;
458     }
459 
460     // validate paint data
461     mbPaintInfoValid = true;
462 
463     // return start page
464     _onStartPageNum = mnPaintPhyStartPageNum;
465 
466     return true;
467 }
468 
469 /** calculate additional paint offset
470 
471 */
CalcAdditionalPaintOffset()472 void SwPagePreviewLayout::CalcAdditionalPaintOffset()
473 {
474     if ( mnPreviewLayoutWidth <= maWinSize.Width() &&
475          maPaintStartPageOffset.X() <= 0 )
476     {
477         mbDoesLayoutColsFitIntoWindow = true;
478         maAdditionalPaintOffset.setX( (maWinSize.Width() - mnPreviewLayoutWidth) / 2 );
479     }
480     else
481     {
482         mbDoesLayoutColsFitIntoWindow = false;
483         maAdditionalPaintOffset.setX( 0 );
484     }
485 
486     if ( mnPreviewLayoutHeight <= maWinSize.Height() &&
487          maPaintStartPageOffset.Y() <= 0 )
488     {
489         mbDoesLayoutRowsFitIntoWindow = true;
490         maAdditionalPaintOffset.setY( (maWinSize.Height() - mnPreviewLayoutHeight) / 2 );
491     }
492     else
493     {
494         mbDoesLayoutRowsFitIntoWindow = false;
495         maAdditionalPaintOffset.setY( 0 );
496     }
497 }
498 
499 /** calculate painted preview document rectangle
500 
501 */
CalcDocPreviewPaintRect()502 void SwPagePreviewLayout::CalcDocPreviewPaintRect()
503 {
504     Point aTopLeftPos = maPaintPreviewDocOffset;
505     maPaintedPreviewDocRect.SetPos( aTopLeftPos );
506 
507     Size aSize;
508     if ( mbDoesLayoutColsFitIntoWindow )
509         aSize.setWidth( std::min( mnPreviewLayoutWidth,
510                              maPreviewDocRect.GetWidth() - aTopLeftPos.X() ) );
511     else
512         aSize.setWidth( std::min( maPreviewDocRect.GetWidth() - aTopLeftPos.X(),
513                              maWinSize.Width() - maAdditionalPaintOffset.X() ) );
514     if ( mbDoesLayoutRowsFitIntoWindow )
515         aSize.setHeight( std::min( mnPreviewLayoutHeight,
516                               maPreviewDocRect.GetHeight() - aTopLeftPos.Y() ) );
517     else
518         aSize.setHeight( std::min( maPreviewDocRect.GetHeight() - aTopLeftPos.Y(),
519                               maWinSize.Height() - maAdditionalPaintOffset.Y() ) );
520     maPaintedPreviewDocRect.SetSize( aSize );
521 }
522 
523 /** calculate preview pages
524 
525 */
CalcPreviewPages()526 void SwPagePreviewLayout::CalcPreviewPages()
527 {
528     vcl::RenderContext* pRenderContext = mrParentViewShell.GetOut();
529     ClearPreviewPageData();
530 
531     if ( mbNoPageVisible )
532         return;
533 
534     // determine start page frame
535     const SwPageFrame* pStartPage = mrLayoutRootFrame.GetPageByPageNum( mnPaintPhyStartPageNum );
536 
537     // calculate initial paint offset
538     Point aInitialPaintOffset;
539     /// check whether RTL interface or not
540     if(!AllSettings::GetLayoutRTL()){
541         if ( maPaintStartPageOffset != Point( -1, -1 ) )
542             aInitialPaintOffset = Point(0,0) - maPaintStartPageOffset;
543         else
544             aInitialPaintOffset = Point( gnXFree, gnYFree );
545     }
546     else {
547         if ( maPaintStartPageOffset != Point( -1, -1 ) )
548             aInitialPaintOffset = Point(0 + ((SwPagePreviewLayout::mnCols-1)*mnColWidth),0) - maPaintStartPageOffset;
549         else
550             aInitialPaintOffset = Point( gnXFree + ((SwPagePreviewLayout::mnCols-1)*mnColWidth), gnYFree );
551     }
552     aInitialPaintOffset += maAdditionalPaintOffset;
553 
554     // prepare loop data
555     const SwPageFrame* pPage = pStartPage;
556     sal_uInt16 nCurrCol = mnPaintStartCol;
557     sal_uInt16 nConsideredRows = 0;
558     Point aCurrPaintOffset = aInitialPaintOffset;
559     // loop on pages to determine preview background rectangles
560     while ( pPage &&
561             (!mbDoesLayoutRowsFitIntoWindow || nConsideredRows < mnRows) &&
562             aCurrPaintOffset.Y() < maWinSize.Height()
563           )
564     {
565         if ( !mbBookPreview && !mbPrintEmptyPages && pPage->IsEmptyPage() )
566         {
567             pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
568             continue;
569         }
570 
571         pPage->Calc(pRenderContext);
572 
573         // consider only pages, which have to be painted.
574         if ( nCurrCol < mnPaintStartCol )
575         {
576             // calculate data of unvisible page needed for accessibility
577             std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
578             Point aCurrAccOffset = aCurrPaintOffset -
579                            Point( (mnPaintStartCol-nCurrCol) * mnColWidth, 0 );
580             CalcPreviewDataForPage( *pPage, aCurrAccOffset, pPreviewPage.get() );
581             pPreviewPage->bVisible = false;
582             maPreviewPages.push_back( std::move(pPreviewPage) );
583             // continue with next page and next column
584             pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
585             ++nCurrCol;
586             continue;
587         }
588         if ( aCurrPaintOffset.X() < maWinSize.Width() )
589         {
590             // leaving left-top-corner blank is
591             // controlled by <mbBookPreview>.
592             if ( mbBookPreview && pPage->GetPhyPageNum() == 1 && mnCols != 1 && nCurrCol == 1
593                )
594             {
595                 // first page in 2nd column
596                 // --> continue with increased paint offset and next column
597                 /// check whether RTL interface or not
598                 if(!AllSettings::GetLayoutRTL())
599                     aCurrPaintOffset.AdjustX(mnColWidth );
600                 else aCurrPaintOffset.AdjustX( -mnColWidth );
601                 ++nCurrCol;
602                 continue;
603             }
604 
605             // calculate data of visible page
606             std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
607             CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() );
608             pPreviewPage->bVisible = true;
609             maPreviewPages.push_back( std::move(pPreviewPage) );
610         }
611         else
612         {
613             // calculate data of unvisible page needed for accessibility
614             std::unique_ptr<PreviewPage> pPreviewPage(new PreviewPage);
615             CalcPreviewDataForPage( *pPage, aCurrPaintOffset, pPreviewPage.get() );
616             pPreviewPage->bVisible = false;
617             maPreviewPages.push_back( std::move(pPreviewPage) );
618         }
619 
620         // prepare data for next loop
621         pPage = static_cast<const SwPageFrame*>(pPage->GetNext());
622 
623         /// check whether RTL interface or not
624         if(!AllSettings::GetLayoutRTL())
625             aCurrPaintOffset.AdjustX(mnColWidth );
626         else aCurrPaintOffset.AdjustX( -mnColWidth );
627         ++nCurrCol;
628         if ( nCurrCol > mnCols )
629         {
630             ++nConsideredRows;
631             aCurrPaintOffset.setX( aInitialPaintOffset.X() );
632             nCurrCol = 1;
633             aCurrPaintOffset.AdjustY(mnRowHeight );
634         }
635     }
636 }
637 
638 /** determines preview data for a given page and a given preview offset
639 
640     OD 13.12.2002 #103492#
641 */
CalcPreviewDataForPage(const SwPageFrame & _rPage,const Point & _rPreviewOffset,PreviewPage * _opPreviewPage)642 void SwPagePreviewLayout::CalcPreviewDataForPage( const SwPageFrame& _rPage,
643                                                    const Point& _rPreviewOffset,
644                                                    PreviewPage* _opPreviewPage )
645 {
646     // page frame
647     _opPreviewPage->pPage = &_rPage;
648     // size of page frame
649     if ( _rPage.IsEmptyPage() )
650     {
651         if ( _rPage.GetPhyPageNum() % 2 == 0 )
652             _opPreviewPage->aPageSize = _rPage.GetPrev()->getFrameArea().SSize();
653         else
654             _opPreviewPage->aPageSize = _rPage.GetNext()->getFrameArea().SSize();
655     }
656     else
657         _opPreviewPage->aPageSize = _rPage.getFrameArea().SSize();
658     // position of page in preview window
659     Point aPreviewWinOffset( _rPreviewOffset );
660     if ( _opPreviewPage->aPageSize.Width() < maMaxPageSize.Width() )
661         aPreviewWinOffset.AdjustX(( maMaxPageSize.Width() - _opPreviewPage->aPageSize.Width() ) / 2 );
662     if ( _opPreviewPage->aPageSize.Height() < maMaxPageSize.Height() )
663         aPreviewWinOffset.AdjustY(( maMaxPageSize.Height() - _opPreviewPage->aPageSize.Height() ) / 2 );
664     _opPreviewPage->aPreviewWinPos = aPreviewWinOffset;
665     // logic position of page and mapping offset for paint
666     if ( _rPage.IsEmptyPage() )
667     {
668         _opPreviewPage->aLogicPos = _opPreviewPage->aPreviewWinPos;
669         _opPreviewPage->aMapOffset = Point( 0, 0 );
670     }
671     else
672     {
673         _opPreviewPage->aLogicPos = _rPage.getFrameArea().Pos();
674         _opPreviewPage->aMapOffset = _opPreviewPage->aPreviewWinPos - _opPreviewPage->aLogicPos;
675     }
676 }
677 
678 /** enable/disable book preview
679 
680     OD 2004-03-04 #i18143#
681 */
SetBookPreviewMode(const bool _bEnableBookPreview,sal_uInt16 & _onStartPageNum,tools::Rectangle & _orDocPreviewPaintRect)682 bool SwPagePreviewLayout::SetBookPreviewMode( const bool _bEnableBookPreview,
683                                               sal_uInt16& _onStartPageNum,
684                                               tools::Rectangle&  _orDocPreviewPaintRect )
685 {
686     if ( mbBookPreview != _bEnableBookPreview)
687     {
688         mbBookPreview = _bEnableBookPreview;
689         // re-initialize page preview layout
690         ReInit();
691         // re-prepare page preview layout
692         {
693             mbBookPreviewModeToggled = true;
694             Point aProposedStartPos( maPaintPreviewDocOffset );
695             // if proposed start position is below virtual preview document
696             // bottom, adjust it to the virtual preview document bottom
697             if ( aProposedStartPos.Y() > maPreviewDocRect.Bottom() )
698             {
699                 aProposedStartPos.setY( maPreviewDocRect.Bottom() );
700             }
701             Prepare( 0, aProposedStartPos,
702                      mrParentViewShell.GetOut()->LogicToPixel( maWinSize ),
703                      _onStartPageNum, _orDocPreviewPaintRect );
704             mbBookPreviewModeToggled = false;
705         }
706 
707         return true;
708     }
709 
710     return false;
711 }
712 
713 // methods to determine new data for changing the current shown part of the
714 // document preview.
715 
716 /** calculate start position for new scale
717 
718 */
GetPreviewStartPosForNewScale(const Fraction & _aNewScale,const Fraction & _aOldScale,const Size & _aNewWinSize) const719 Point SwPagePreviewLayout::GetPreviewStartPosForNewScale(
720                           const Fraction& _aNewScale,
721                           const Fraction& _aOldScale,
722                           const Size&     _aNewWinSize ) const
723 {
724     Point aNewPaintStartPos = maPaintedPreviewDocRect.TopLeft();
725     if ( _aNewScale < _aOldScale )
726     {
727         // increase paint width by moving start point to left.
728         if ( mnPreviewLayoutWidth < _aNewWinSize.Width() )
729             aNewPaintStartPos.setX( 0 );
730         else if ( maPaintedPreviewDocRect.GetWidth() < _aNewWinSize.Width() )
731         {
732             aNewPaintStartPos.AdjustX( -(
733                 (_aNewWinSize.Width() - maPaintedPreviewDocRect.GetWidth()) / 2) );
734             if ( aNewPaintStartPos.X() < 0)
735                 aNewPaintStartPos.setX( 0 );
736         }
737 
738         if ( !mbDoesLayoutRowsFitIntoWindow )
739         {
740             // increase paint height by moving start point to top.
741             if ( mnPreviewLayoutHeight < _aNewWinSize.Height() )
742             {
743                 aNewPaintStartPos.setY(
744                     (mnPaintStartRow - 1) * mnRowHeight );
745             }
746             else if ( maPaintedPreviewDocRect.GetHeight() < _aNewWinSize.Height() )
747             {
748                 aNewPaintStartPos.AdjustY( -(
749                     (_aNewWinSize.Height() - maPaintedPreviewDocRect.GetHeight()) / 2) );
750                 if ( aNewPaintStartPos.Y() < 0)
751                     aNewPaintStartPos.setY( 0 );
752             }
753         }
754     }
755     else
756     {
757         // decrease paint width by moving start point to right
758         if ( maPaintedPreviewDocRect.GetWidth() > _aNewWinSize.Width() )
759             aNewPaintStartPos.AdjustX(
760                 (maPaintedPreviewDocRect.GetWidth() - _aNewWinSize.Width()) / 2 );
761         // decrease paint height by moving start point to bottom
762         if ( maPaintedPreviewDocRect.GetHeight() > _aNewWinSize.Height() )
763         {
764             aNewPaintStartPos.AdjustY(
765                 (maPaintedPreviewDocRect.GetHeight() - _aNewWinSize.Height()) / 2 );
766             // check, if new y-position is outside document preview
767             if ( aNewPaintStartPos.Y() > maPreviewDocRect.Bottom() )
768                 aNewPaintStartPos.setY(
769                         std::max( 0L, maPreviewDocRect.Bottom() - mnPreviewLayoutHeight ) );
770         }
771     }
772 
773     return aNewPaintStartPos;
774 }
775 
776 /** determines, if page with given page number is visible in preview
777 
778     @note _nPageNum is absolute
779 */
IsPageVisible(const sal_uInt16 _nPageNum) const780 bool SwPagePreviewLayout::IsPageVisible( const sal_uInt16 _nPageNum ) const
781 {
782     const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
783     return pPreviewPage && pPreviewPage->bVisible;
784 }
785 
786 /** calculate data to bring new selected page into view.
787 
788     @note IN/OUT parameters are absolute page numbers!!!
789 */
CalcStartValuesForSelectedPageMove(const sal_Int16 _nHoriMove,const sal_Int16 _nVertMove,sal_uInt16 & _orNewSelectedPage,sal_uInt16 & _orNewStartPage,Point & _orNewStartPos) const790 void SwPagePreviewLayout::CalcStartValuesForSelectedPageMove(
791                                 const sal_Int16  _nHoriMove,
792                                 const sal_Int16  _nVertMove,
793                                 sal_uInt16&      _orNewSelectedPage,
794                                 sal_uInt16&      _orNewStartPage,
795                                 Point&           _orNewStartPos ) const
796 {
797     // determine position of current selected page
798     sal_uInt16 nTmpRelSelPageNum = ConvertAbsoluteToRelativePageNum( mnSelectedPageNum );
799     sal_uInt16 nNewRelSelectedPageNum = nTmpRelSelPageNum;
800 
801     const sal_uInt16 nCurrRow = GetRowOfPage(nTmpRelSelPageNum);
802 
803     // determine new selected page number
804     {
805         if ( _nHoriMove != 0 )
806         {
807             if ( (nNewRelSelectedPageNum + _nHoriMove) < 1 )
808                 nNewRelSelectedPageNum = 1;
809             else if ( (nNewRelSelectedPageNum + _nHoriMove) > mnPages )
810                 nNewRelSelectedPageNum = mnPages;
811             else
812                 nNewRelSelectedPageNum = nNewRelSelectedPageNum + _nHoriMove;
813         }
814         if ( _nVertMove != 0 )
815         {
816             if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) < 1 )
817                 nNewRelSelectedPageNum = 1;
818             else if ( (nNewRelSelectedPageNum + (_nVertMove * mnCols)) > mnPages )
819                 nNewRelSelectedPageNum = mnPages;
820             else
821                 nNewRelSelectedPageNum += ( _nVertMove * mnCols );
822         }
823     }
824 
825     sal_uInt16 nNewStartPage = mnPaintPhyStartPageNum;
826     Point aNewStartPos(0,0);
827 
828     const sal_uInt16 nNewAbsSelectedPageNum = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum );
829     if ( !IsPageVisible( nNewAbsSelectedPageNum ) )
830     {
831         if ( _nHoriMove != 0 && _nVertMove != 0 )
832         {
833             OSL_FAIL( "missing implementation for moving preview selected page horizontal AND vertical");
834             return;
835         }
836 
837         // new selected page has to be brought into view considering current
838         // visible preview.
839         const sal_uInt16 nTotalRows = GetRowOfPage( mnPages );
840         if ( (_nHoriMove > 0 || _nVertMove > 0) &&
841              mbDoesLayoutRowsFitIntoWindow &&
842              mbDoesLayoutColsFitIntoWindow &&
843              nCurrRow > nTotalRows - mnRows )
844         {
845             // new proposed start page = left-top-corner of last possible
846             // preview page.
847             nNewStartPage = (nTotalRows - mnRows) * mnCols + 1;
848             // leaving left-top-corner blank is controlled
849             // by <mbBookPreview>.
850             if ( mbBookPreview )
851             {
852                 // Note: decrease new proposed start page number by one,
853                 // because of blank left-top-corner
854                 --nNewStartPage;
855             }
856             nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewStartPage );
857         }
858         else
859         {
860             // new proposed start page = new selected page.
861             nNewStartPage = ConvertRelativeToAbsolutePageNum( nNewRelSelectedPageNum );
862         }
863     }
864 
865     _orNewSelectedPage = nNewAbsSelectedPageNum;
866     _orNewStartPage = nNewStartPage;
867     _orNewStartPos = aNewStartPos;
868 }
869 
870 /** checks, if given position is inside a shown document page */
871 struct PreviewPosInsidePagePred
872 {
873     const Point mnPreviewPos;
PreviewPosInsidePagePredPreviewPosInsidePagePred874     explicit PreviewPosInsidePagePred(const Point& rPreviewPos)
875         : mnPreviewPos( rPreviewPos )
876     {}
operator ()PreviewPosInsidePagePred877     bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage )
878     {
879         if ( _pPreviewPage->bVisible )
880         {
881             tools::Rectangle aPreviewPageRect( _pPreviewPage->aPreviewWinPos, _pPreviewPage->aPageSize );
882             return aPreviewPageRect.IsInside( mnPreviewPos );
883         }
884         return false;
885     }
886 };
887 
IsPreviewPosInDocPreviewPage(const Point & rPreviewPos,Point & _orDocPos,bool & _obPosInEmptyPage,sal_uInt16 & _onPageNum) const888 bool SwPagePreviewLayout::IsPreviewPosInDocPreviewPage( const Point&  rPreviewPos,
889                                                     Point&       _orDocPos,
890                                                     bool&        _obPosInEmptyPage,
891                                                     sal_uInt16&  _onPageNum ) const
892 {
893     // initialize variable parameter values.
894     _orDocPos.setX( 0 );
895     _orDocPos.setY( 0 );
896     _obPosInEmptyPage = false;
897     _onPageNum = 0;
898 
899     auto aFoundPreviewPageIter =
900             std::find_if( maPreviewPages.begin(), maPreviewPages.end(),
901                           PreviewPosInsidePagePred( rPreviewPos ) );
902 
903     if ( aFoundPreviewPageIter != maPreviewPages.end() )
904     {
905         // given preview position is inside a document page.
906         _onPageNum = (*aFoundPreviewPageIter)->pPage->GetPhyPageNum();
907         _obPosInEmptyPage = (*aFoundPreviewPageIter)->pPage->IsEmptyPage();
908         if ( !_obPosInEmptyPage )
909         {
910             // given preview position inside a normal page
911             _orDocPos = rPreviewPos -
912                         (*aFoundPreviewPageIter)->aPreviewWinPos +
913                         (*aFoundPreviewPageIter)->aLogicPos;
914             return true;
915         }
916     }
917 
918     return false;
919 }
920 
921 /** determine window page scroll amount */
GetWinPagesScrollAmount(const sal_Int16 _nWinPagesToScroll) const922 SwTwips SwPagePreviewLayout::GetWinPagesScrollAmount(
923                                 const sal_Int16 _nWinPagesToScroll ) const
924 {
925     SwTwips nScrollAmount;
926     if ( mbDoesLayoutRowsFitIntoWindow )
927     {
928         nScrollAmount = (mnPreviewLayoutHeight - gnYFree) * _nWinPagesToScroll;
929     }
930     else
931         nScrollAmount = _nWinPagesToScroll * maPaintedPreviewDocRect.GetHeight();
932 
933     // check, if preview layout size values are valid.
934     // If not, the checks for an adjustment of the scroll amount aren't useful.
935     if ( mbLayoutSizesValid )
936     {
937         if ( (maPaintedPreviewDocRect.Top() + nScrollAmount) <= 0 )
938             nScrollAmount = -maPaintedPreviewDocRect.Top();
939 
940         // correct scroll amount
941         if ( nScrollAmount > 0 &&
942              maPaintedPreviewDocRect.Bottom() == maPreviewDocRect.Bottom()
943            )
944         {
945             nScrollAmount = 0;
946         }
947         else
948         {
949             while ( (maPaintedPreviewDocRect.Top() + nScrollAmount + gnYFree) >= maPreviewDocRect.GetHeight() )
950             {
951                 nScrollAmount -= mnRowHeight;
952             }
953         }
954     }
955 
956     return nScrollAmount;
957 }
958 
959 // methods to paint page preview layout
960 
961 namespace
962 {
963 /// Similar to RenderContextGuard, but does not touch the draw view.
964 class PreviewRenderContextGuard
965 {
966     VclPtr<vcl::RenderContext> m_pOriginalValue;
967     SwViewShell& m_rShell;
968 
969 public:
PreviewRenderContextGuard(SwViewShell & rShell,vcl::RenderContext * pValue)970     PreviewRenderContextGuard(SwViewShell& rShell, vcl::RenderContext* pValue)
971         : m_pOriginalValue(rShell.GetOut()),
972         m_rShell(rShell)
973     {
974         m_rShell.SetOut(pValue);
975     }
976 
~PreviewRenderContextGuard()977     ~PreviewRenderContextGuard()
978     {
979         m_rShell.SetOut(m_pOriginalValue);
980     }
981 };
982 }
983 
984 /** paint prepared preview
985 
986 */
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle & rOutRect) const987 bool SwPagePreviewLayout::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& rOutRect) const
988 {
989     PreviewRenderContextGuard aGuard(mrParentViewShell, &rRenderContext);
990     // check environment and parameters
991     {
992         if (!mrParentViewShell.GetWin() && !mrParentViewShell.GetOut()->GetConnectMetaFile())
993         {
994             return false;
995         }
996 
997         OSL_ENSURE(mbPaintInfoValid, "invalid preview settings - no paint of preview");
998         if (!mbPaintInfoValid)
999             return false;
1000     }
1001 
1002     // OD 17.11.2003 #i22014# - no paint, if <superfluous> flag is set at layout
1003     if (mrLayoutRootFrame.IsSuperfluous())
1004     {
1005         return true;
1006     }
1007 
1008     // environment and parameter ok
1009 
1010     if (mbInPaint)
1011     {
1012         return false;
1013     }
1014     mbInPaint = true;
1015 
1016     OutputDevice* pOutputDev = &rRenderContext;
1017 
1018     // prepare paint
1019     if ( !maPreviewPages.empty() )
1020     {
1021         mrParentViewShell.Imp()->m_bFirstPageInvalid = false;
1022         mrParentViewShell.Imp()->m_pFirstVisiblePage =
1023                 const_cast<SwPageFrame*>(maPreviewPages[0]->pPage);
1024     }
1025 
1026     // paint preview background
1027     {
1028         SwRegionRects aPreviewBackgrdRegion(rOutRect);
1029         // calculate preview background rectangles
1030         for ( auto & rpPreviewPage : maPreviewPages )
1031         {
1032             if ( rpPreviewPage->bVisible )
1033             {
1034                 aPreviewBackgrdRegion -=
1035                         SwRect( rpPreviewPage->aPreviewWinPos, rpPreviewPage->aPageSize );
1036             }
1037         }
1038         // paint preview background rectangles
1039         mrParentViewShell.PaintDesktop_(aPreviewBackgrdRegion);
1040     }
1041 
1042     // prepare data for paint of pages
1043     const tools::Rectangle aPxOutRect( pOutputDev->LogicToPixel(rOutRect) );
1044 
1045     MapMode aMapMode( pOutputDev->GetMapMode() );
1046     MapMode aSavedMapMode = aMapMode;
1047 
1048     const vcl::Font& rEmptyPgFont = SwPageFrame::GetEmptyPageFont();
1049 
1050     for ( auto & rpPreviewPage : maPreviewPages )
1051     {
1052         if ( !rpPreviewPage->bVisible )
1053             continue;
1054 
1055         tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize );
1056         aMapMode.SetOrigin( rpPreviewPage->aMapOffset );
1057         pOutputDev->SetMapMode( aMapMode );
1058         tools::Rectangle aPxPaintRect = pOutputDev->LogicToPixel( aPageRect );
1059         if ( aPxOutRect.IsOver( aPxPaintRect) )
1060         {
1061             const SwPageFrame* pPage = rpPreviewPage->pPage;
1062 
1063             if (pPage->IsEmptyPage())
1064             {
1065                 const Color aRetouche( mrParentViewShell.Imp()->GetRetoucheColor() );
1066                 if( pOutputDev->GetFillColor() != aRetouche )
1067                     pOutputDev->SetFillColor( aRetouche );
1068                 pOutputDev->SetLineColor(); // no line color
1069                 // use aligned page rectangle
1070                 {
1071                     SwRect aTmpPageRect( aPageRect );
1072                     ::SwAlignRect( aTmpPageRect, &mrParentViewShell, &rRenderContext );
1073                     aPageRect = aTmpPageRect.SVRect();
1074                 }
1075                 pOutputDev->DrawRect( aPageRect );
1076 
1077                 // paint empty page text
1078                 vcl::Font aOldFont( pOutputDev->GetFont() );
1079                 pOutputDev->SetFont( rEmptyPgFont );
1080                 pOutputDev->DrawText( aPageRect, SwResId( STR_EMPTYPAGE ),
1081                                     DrawTextFlags::VCenter |
1082                                     DrawTextFlags::Center |
1083                                     DrawTextFlags::Clip );
1084                 pOutputDev->SetFont( aOldFont );
1085                 // paint shadow and border for empty page
1086                 // use new method to paint page border and shadow
1087                 SwPageFrame::PaintBorderAndShadow( aPageRect, &mrParentViewShell, true, false, true );
1088             }
1089             else
1090             {
1091                 const bool bIsLeftShadowed = pPage->IsLeftShadowNeeded();
1092                 const bool bIsRightShadowed = pPage->IsRightShadowNeeded();
1093 
1094                 mrParentViewShell.maVisArea = aPageRect;
1095                 aPxPaintRect.Intersection( aPxOutRect );
1096                 tools::Rectangle aPaintRect = pOutputDev->PixelToLogic( aPxPaintRect );
1097                 mrParentViewShell.Paint(rRenderContext, aPaintRect);
1098 
1099                 // --> OD 2007-08-15 #i80691#
1100                 // paint page border and shadow
1101                 {
1102                     SwRect aPageBorderRect;
1103                     SwPageFrame::GetBorderAndShadowBoundRect( SwRect( aPageRect ), &mrParentViewShell, &rRenderContext, aPageBorderRect,
1104                         bIsLeftShadowed, bIsRightShadowed, true );
1105                     const vcl::Region aDLRegion(aPageBorderRect.SVRect());
1106                     mrParentViewShell.DLPrePaint2(aDLRegion);
1107                     SwPageFrame::PaintBorderAndShadow( aPageRect, &mrParentViewShell, true, false, true );
1108                     mrParentViewShell.DLPostPaint2(true);
1109                 }
1110                 // <--
1111             }
1112             // OD 07.11.2003 #i22014# - stop painting, because new print
1113             // preview layout is created during paint.
1114             if ( mbNewLayoutDuringPaint )
1115             {
1116                 break;
1117             }
1118 
1119             if (pPage->GetPhyPageNum() == mnSelectedPageNum)
1120             {
1121                 PaintSelectMarkAtPage(rRenderContext, rpPreviewPage.get());
1122             }
1123         }
1124     }
1125 
1126     // OD 17.11.2003 #i22014# - no update of accessible preview, if a new
1127     // print preview layout is created during paint.
1128     if ( !mbNewLayoutDuringPaint )
1129     {
1130         // update at accessibility interface
1131         mrParentViewShell.Imp()->UpdateAccessiblePreview(
1132                         maPreviewPages,
1133                         aMapMode.GetScaleX(),
1134                         mrLayoutRootFrame.GetPageByPageNum( mnSelectedPageNum ),
1135                         maWinSize );
1136     }
1137 
1138     pOutputDev->SetMapMode( aSavedMapMode );
1139     mrParentViewShell.maVisArea.Clear();
1140 
1141     // OD 07.11.2003 #i22014#
1142     mbInPaint = false;
1143     mbNewLayoutDuringPaint = false;
1144 
1145     return true;
1146 }
1147 
1148 /** repaint pages on page preview
1149 
1150     OD 18.12.2002 #103492#
1151 */
Repaint(const tools::Rectangle & rInvalidCoreRect) const1152 void SwPagePreviewLayout::Repaint( const tools::Rectangle& rInvalidCoreRect ) const
1153 {
1154     // check environment and parameters
1155     {
1156         if ( !mrParentViewShell.GetWin() &&
1157              !mrParentViewShell.GetOut()->GetConnectMetaFile() )
1158             return;
1159 
1160         OSL_ENSURE( mbPaintInfoValid,
1161                 "invalid preview settings - no paint of preview" );
1162         if ( !mbPaintInfoValid )
1163             return;
1164     }
1165 
1166     // environment and parameter ok
1167 
1168     // prepare paint
1169     if ( !maPreviewPages.empty() )
1170     {
1171         mrParentViewShell.Imp()->m_bFirstPageInvalid = false;
1172         mrParentViewShell.Imp()->m_pFirstVisiblePage =
1173                 const_cast<SwPageFrame*>(maPreviewPages[0]->pPage);
1174     }
1175 
1176     // invalidate visible pages, which overlap the invalid core rectangle
1177     for ( auto & rpPreviewPage : maPreviewPages )
1178     {
1179         if ( !rpPreviewPage->bVisible )
1180             continue;
1181 
1182         tools::Rectangle aPageRect( rpPreviewPage->aLogicPos, rpPreviewPage->aPageSize );
1183         if ( rInvalidCoreRect.IsOver( aPageRect ) )
1184         {
1185             aPageRect.Intersection(rInvalidCoreRect);
1186             tools::Rectangle aInvalidPreviewRect = aPageRect;
1187             aInvalidPreviewRect.SetPos( aInvalidPreviewRect.TopLeft() -
1188                                       rpPreviewPage->aLogicPos +
1189                                       rpPreviewPage->aPreviewWinPos );
1190             mrParentViewShell.GetWin()->Invalidate( aInvalidPreviewRect );
1191         }
1192     }
1193 }
1194 
1195 /** paint selection mark at page
1196 
1197     OD 17.12.2002 #103492#
1198 */
PaintSelectMarkAtPage(vcl::RenderContext & rRenderContext,const PreviewPage * _aSelectedPreviewPage) const1199 void SwPagePreviewLayout::PaintSelectMarkAtPage(vcl::RenderContext& rRenderContext,
1200                                     const PreviewPage* _aSelectedPreviewPage ) const
1201 {
1202     OutputDevice* pOutputDev = &rRenderContext;
1203     MapMode aMapMode( pOutputDev->GetMapMode() );
1204     // save mapping mode of output device
1205     MapMode aSavedMapMode = aMapMode;
1206     // save fill and line color of output device
1207     Color aFill( pOutputDev->GetFillColor() );
1208     Color aLine( pOutputDev->GetLineColor() );
1209 
1210     // determine selection mark color
1211     Color aSelPgLineColor(COL_LIGHTBLUE);
1212     const StyleSettings& rSettings =
1213         mrParentViewShell.GetWin()->GetSettings().GetStyleSettings();
1214     if ( rSettings.GetHighContrastMode() )
1215         aSelPgLineColor = rSettings.GetHighlightTextColor();
1216 
1217     // set needed mapping mode at output device
1218     aMapMode.SetOrigin( _aSelectedPreviewPage->aMapOffset );
1219     pOutputDev->SetMapMode( aMapMode );
1220 
1221     // calculate page rectangle in pixel coordinates
1222     SwRect aPageRect( _aSelectedPreviewPage->aLogicPos,
1223                          _aSelectedPreviewPage->aPageSize );
1224     // OD 19.02.2003 #107369# - use aligned page rectangle, as it is used for
1225     // page border and shadow paint - see <SwPageFrame::PaintBorderAndShadow(..)>
1226     ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev );
1227     tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
1228 
1229     // draw two rectangle
1230     // OD 19.02.2003 #107369# - adjust position of select mark rectangle
1231     tools::Rectangle aRect( aPxPageRect.Left(), aPxPageRect.Top(),
1232                        aPxPageRect.Right(), aPxPageRect.Bottom() );
1233     aRect = pOutputDev->PixelToLogic( aRect );
1234     pOutputDev->SetFillColor(); // OD 20.02.2003 #107369# - no fill color
1235     pOutputDev->SetLineColor( aSelPgLineColor );
1236     pOutputDev->DrawRect( aRect );
1237     // OD 19.02.2003 #107369# - adjust position of select mark rectangle
1238     aRect = tools::Rectangle( aPxPageRect.Left()+1, aPxPageRect.Top()+1,
1239                        aPxPageRect.Right()-1, aPxPageRect.Bottom()-1 );
1240     aRect = pOutputDev->PixelToLogic( aRect );
1241     pOutputDev->DrawRect( aRect );
1242 
1243     // reset fill and line color of output device
1244     pOutputDev->SetFillColor( aFill );
1245     pOutputDev->SetLineColor( aLine );
1246 
1247     // reset mapping mode of output device
1248     pOutputDev->SetMapMode( aSavedMapMode );
1249 }
1250 
1251 /** paint to mark new selected page
1252 
1253     OD 17.12.2002 #103492#
1254     Perform paint for current selected page in order to unmark it.
1255     Set new selected page and perform paint to mark this page.
1256 
1257     @note _nSelectedPage, mnSelectedPage are absolute
1258 */
MarkNewSelectedPage(const sal_uInt16 _nSelectedPage)1259 void SwPagePreviewLayout::MarkNewSelectedPage( const sal_uInt16 _nSelectedPage )
1260 {
1261     const sal_uInt16 nOldSelectedPageNum = mnSelectedPageNum;
1262     mnSelectedPageNum = _nSelectedPage;
1263 
1264     // re-paint for current selected page in order to unmark it.
1265     const PreviewPage* pOldSelectedPreviewPage = GetPreviewPageByPageNum( nOldSelectedPageNum );
1266     OutputDevice* pOutputDev = mrParentViewShell.GetOut();
1267     if ( pOldSelectedPreviewPage && pOldSelectedPreviewPage->bVisible )
1268     {
1269         // OD 20.02.2003 #107369# - invalidate only areas of selection mark.
1270         SwRect aPageRect( pOldSelectedPreviewPage->aPreviewWinPos,
1271                               pOldSelectedPreviewPage->aPageSize );
1272         ::SwAlignRect( aPageRect, &mrParentViewShell, pOutputDev );
1273         tools::Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
1274         // invalidate top mark line
1275         tools::Rectangle aInvalPxRect( aPxPageRect.Left(), aPxPageRect.Top(),
1276                                 aPxPageRect.Right(), aPxPageRect.Top()+1 );
1277         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1278         // invalidate right mark line
1279         aInvalPxRect = tools::Rectangle( aPxPageRect.Right()-1, aPxPageRect.Top(),
1280                                   aPxPageRect.Right(), aPxPageRect.Bottom() );
1281         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1282         // invalidate bottom mark line
1283         aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Bottom()-1,
1284                                   aPxPageRect.Right(), aPxPageRect.Bottom() );
1285         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1286         // invalidate left mark line
1287         aInvalPxRect = tools::Rectangle( aPxPageRect.Left(), aPxPageRect.Top(),
1288                                   aPxPageRect.Left()+1, aPxPageRect.Bottom() );
1289         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1290     }
1291 
1292     // re-paint for new selected page in order to mark it.
1293     const PreviewPage* pNewSelectedPreviewPage = GetPreviewPageByPageNum( _nSelectedPage );
1294     if ( pNewSelectedPreviewPage && pNewSelectedPreviewPage->bVisible )
1295     {
1296         const PreviewPage* pSelectedPreviewPage = GetPreviewPageByPageNum(mnSelectedPageNum);
1297         SwRect aPageRect(pSelectedPreviewPage->aPreviewWinPos, pSelectedPreviewPage->aPageSize);
1298         ::SwAlignRect(aPageRect, &mrParentViewShell, pOutputDev);
1299         mrParentViewShell.GetWin()->Invalidate(aPageRect.SVRect());
1300     }
1301 }
1302 
1303 // helper methods
1304 
1305 /** get preview page by physical page number
1306 
1307     OD 17.12.2002 #103492#
1308 */
1309 struct EqualsPageNumPred
1310 {
1311     const sal_uInt16 mnPageNum;
EqualsPageNumPredEqualsPageNumPred1312     explicit EqualsPageNumPred(const sal_uInt16 _nPageNum)
1313         : mnPageNum( _nPageNum )
1314     {}
operator ()EqualsPageNumPred1315     bool operator() ( const std::unique_ptr<PreviewPage> & _pPreviewPage )
1316     {
1317         return _pPreviewPage->pPage->GetPhyPageNum() == mnPageNum;
1318     }
1319 };
1320 
GetPreviewPageByPageNum(const sal_uInt16 _nPageNum) const1321 const PreviewPage* SwPagePreviewLayout::GetPreviewPageByPageNum( const sal_uInt16 _nPageNum ) const
1322 {
1323     auto aFoundPreviewPageIter =
1324             std::find_if( maPreviewPages.begin(), maPreviewPages.end(),
1325                           EqualsPageNumPred( _nPageNum ) );
1326 
1327     if ( aFoundPreviewPageIter == maPreviewPages.end() )
1328         return nullptr;
1329 
1330     return aFoundPreviewPageIter->get();
1331 }
1332 
1333 /** determine row the page with the given number is in
1334 
1335     OD 17.01.2003 #103492#
1336 
1337     @note _nPageNum is relative
1338 */
GetRowOfPage(sal_uInt16 _nPageNum) const1339 sal_uInt16 SwPagePreviewLayout::GetRowOfPage( sal_uInt16 _nPageNum ) const
1340 {
1341     // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
1342     // by <mbBookPreview>.
1343     if ( mbBookPreview )
1344     {
1345         // Note: increase given physical page number by one, because left-top-corner
1346         //       in the preview layout is left blank.
1347         ++_nPageNum;
1348     }
1349 
1350     return _nPageNum / mnCols + ((_nPageNum % mnCols)>0 ? 1 : 0);
1351 }
1352 
1353 /** determine column the page with the given number is in
1354 
1355     OD 17.01.2003 #103492#
1356 
1357     @note _nPageNum is relative
1358 */
GetColOfPage(sal_uInt16 _nPageNum) const1359 sal_uInt16 SwPagePreviewLayout::GetColOfPage( sal_uInt16 _nPageNum ) const
1360 {
1361     // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
1362     // by <mbBookPreview>.
1363     if ( mbBookPreview )
1364     {
1365         // Note: increase given physical page number by one, because left-top-corner
1366         //       in the preview layout is left blank.
1367         ++_nPageNum;
1368     }
1369 
1370     const sal_uInt16 nCol = _nPageNum % mnCols;
1371     return nCol ? nCol : mnCols;
1372 }
1373 
GetPreviewDocSize() const1374 Size SwPagePreviewLayout::GetPreviewDocSize() const
1375 {
1376     OSL_ENSURE( PreviewLayoutValid(), "PagePreviewLayout not valid" );
1377     return maPreviewDocRect.GetSize();
1378 }
1379 
1380 /** get size of a preview page by its physical page number
1381 
1382     OD 15.01.2003 #103492#
1383 */
GetPreviewPageSizeByPageNum(sal_uInt16 _nPageNum) const1384 Size SwPagePreviewLayout::GetPreviewPageSizeByPageNum( sal_uInt16 _nPageNum ) const
1385 {
1386     const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
1387     if ( pPreviewPage )
1388     {
1389         return pPreviewPage->aPageSize;
1390     }
1391     return Size( 0, 0 );
1392 }
1393 
1394 /** get virtual page number by its physical page number
1395 
1396     OD 21.03.2003 #108282#
1397 */
GetVirtPageNumByPageNum(sal_uInt16 _nPageNum) const1398 sal_uInt16 SwPagePreviewLayout::GetVirtPageNumByPageNum( sal_uInt16 _nPageNum ) const
1399 {
1400     const PreviewPage* pPreviewPage = GetPreviewPageByPageNum( _nPageNum );
1401     if ( pPreviewPage )
1402     {
1403         return pPreviewPage->pPage->GetVirtPageNum();
1404     }
1405     return 0;
1406 }
1407 
1408 /** Convert absolute to relative page numbers (see PrintEmptyPages) */
ConvertAbsoluteToRelativePageNum(sal_uInt16 _nAbsPageNum) const1409 sal_uInt16 SwPagePreviewLayout::ConvertAbsoluteToRelativePageNum( sal_uInt16 _nAbsPageNum ) const
1410 {
1411     if ( mbBookPreview || mbPrintEmptyPages || !_nAbsPageNum )
1412     {
1413         return _nAbsPageNum;
1414     }
1415 
1416     const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
1417 
1418     sal_uInt16 nRet = 1;
1419 
1420     while ( pTmpPage && pTmpPage->GetPhyPageNum() != _nAbsPageNum )
1421     {
1422         if ( !pTmpPage->IsEmptyPage() )
1423             ++nRet;
1424 
1425         pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() );
1426     }
1427 
1428     return nRet;
1429 }
1430 
1431 /** Convert relative to absolute page numbers (see PrintEmptyPages) */
ConvertRelativeToAbsolutePageNum(sal_uInt16 _nRelPageNum) const1432 sal_uInt16 SwPagePreviewLayout::ConvertRelativeToAbsolutePageNum( sal_uInt16 _nRelPageNum ) const
1433 {
1434     if ( mbBookPreview || mbPrintEmptyPages || !_nRelPageNum )
1435     {
1436         return _nRelPageNum;
1437     }
1438 
1439     const SwPageFrame* pTmpPage = static_cast<const SwPageFrame*>(mrLayoutRootFrame.Lower());
1440     const SwPageFrame* pRet = nullptr;
1441 
1442     sal_uInt16 i = 0;
1443     while( pTmpPage && i != _nRelPageNum )
1444     {
1445         if ( !pTmpPage->IsEmptyPage() )
1446             ++i;
1447 
1448         pRet = pTmpPage;
1449         pTmpPage = static_cast<const SwPageFrame*>( pTmpPage->GetNext() );
1450     }
1451 
1452     return pRet->GetPhyPageNum();
1453 }
1454 
1455 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1456