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