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