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 ( 3 * 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     for ( std::vector<PrevwPage*>::const_iterator aPageIter = maPrevwPages.begin();
1116           aPageIter != maPrevwPages.end();
1117           ++aPageIter )
1118     {
1119         if ( !(*aPageIter)->bVisible )
1120             continue;
1121 
1122         Rectangle aPageRect( (*aPageIter)->aLogicPos, (*aPageIter)->aPageSize );
1123         aMapMode.SetOrigin( (*aPageIter)->aMapOffset );
1124         pOutputDev->SetMapMode( aMapMode );
1125         Rectangle aPxPaintRect = pOutputDev->LogicToPixel( aPageRect );
1126         if ( aPxOutRect.IsOver( aPxPaintRect) )
1127         {
1128             if ( (*aPageIter)->pPage->IsEmptyPage() )
1129             {
1130                 const Color aRetouche( mrParentViewShell.Imp()->GetRetoucheColor() );
1131                 if( pOutputDev->GetFillColor() != aRetouche )
1132                     pOutputDev->SetFillColor( aRetouche );
1133                 pOutputDev->SetLineColor(); // OD 20.02.2003 #107369# - no line color
1134                 // OD 20.02.2003 #107369# - use aligned page rectangle
1135                 {
1136                     SwRect aTmpPageRect( aPageRect );
1137                     ::SwAlignRect( aTmpPageRect, &mrParentViewShell);
1138                     aPageRect = aTmpPageRect.SVRect();
1139                 }
1140                 pOutputDev->DrawRect( aPageRect );
1141 
1142                 // paint empty page text
1143                 Font aOldFont( pOutputDev->GetFont() );
1144                 pOutputDev->SetFont( rEmptyPgFont );
1145                 pOutputDev->DrawText( aPageRect, SW_RESSTR( STR_EMPTYPAGE ),
1146                                     TEXT_DRAW_VCENTER |
1147                                     TEXT_DRAW_CENTER |
1148                                     TEXT_DRAW_CLIP );
1149                 pOutputDev->SetFont( aOldFont );
1150                 // paint border for empty page (shadow removed now)
1151                 // OD 19.02.2003 #107369# - use new method to paint page border
1152                 SwPageFrm::PaintPageBorder( aPageRect, &mrParentViewShell, true );
1153             }
1154             else
1155             {
1156                 mrParentViewShell.aVisArea = aPageRect;
1157                 aPxPaintRect.Intersection( aPxOutRect );
1158                 Rectangle aPaintRect = pOutputDev->PixelToLogic( aPxPaintRect );
1159                 mrParentViewShell.Paint( aPaintRect );
1160                 // --> OD 2007-08-15 #i80691#
1161                 // paint page border (shadow removed now)
1162                 {
1163                     SwRect aPageBorderRect;
1164                     SwPageFrm::GetBorderAndShadowBoundRect( SwRect( aPageRect ), &mrParentViewShell, aPageBorderRect, true );
1165                     const Region aDLRegion(aPageBorderRect.SVRect());
1166                     mrParentViewShell.DLPrePaint2(aDLRegion);
1167                     SwPageFrm::PaintPageBorder( aPageRect, &mrParentViewShell, true );
1168                     mrParentViewShell.DLPostPaint2(true);
1169                 }
1170                 // <--
1171             }
1172             // OD 07.11.2003 #i22014# - stop painting, because new print
1173             // preview layout is created during paint.
1174             if ( mbNewLayoutDuringPaint )
1175             {
1176                 break;
1177             }
1178 
1179             if ( (*aPageIter)->pPage->GetPhyPageNum() == mnSelectedPageNum )
1180             {
1181                 _PaintSelectMarkAtPage( (*aPageIter) );
1182             }
1183 
1184         }
1185     }
1186 
1187     // OD 17.11.2003 #i22014# - no update of accessible preview, if a new
1188     // print preview layout is created during paint.
1189     if ( !mbNewLayoutDuringPaint )
1190     {
1191         // update at accessibility interface
1192         mrParentViewShell.Imp()->UpdateAccessiblePreview(
1193                         maPrevwPages,
1194                         aMapMode.GetScaleX(),
1195                         mrLayoutRootFrm.GetPageByPageNum( mnSelectedPageNum ),
1196                         maWinSize );
1197     }
1198 
1199     pOutputDev->SetMapMode( aSavedMapMode );
1200     mrParentViewShell.aVisArea.Clear();
1201 
1202     // OD 07.11.2003 #i22014#
1203     mbInPaint = false;
1204     mbNewLayoutDuringPaint = false;
1205 
1206     return true;
1207 }
1208 
1209 /** repaint pages on page preview
1210 
1211     OD 18.12.2002 #103492#
1212 
1213     @author OD
1214 */
1215 void SwPagePreviewLayout::Repaint( const Rectangle _aInvalidCoreRect ) const
1216 {
1217     // check environment and parameters
1218     {
1219         if ( !mrParentViewShell.GetWin() &&
1220              !mrParentViewShell.GetOut()->GetConnectMetaFile() )
1221             return;
1222 
1223         ASSERT( mbPaintInfoValid,
1224                 "invalid preview settings - no paint of preview" );
1225         if ( !mbPaintInfoValid )
1226             return;
1227     }
1228 
1229     // environment and parameter OK
1230 
1231     // prepare paint
1232     if ( maPrevwPages.size() > 0 )
1233     {
1234         mrParentViewShell.Imp()->bFirstPageInvalid = sal_False;
1235         mrParentViewShell.Imp()->pFirstVisPage =
1236                 const_cast<SwPageFrm*>(maPrevwPages[0]->pPage);
1237     }
1238 
1239     // invalidate visible pages, which overlap the invalid core rectangle
1240     for ( std::vector<PrevwPage*>::const_iterator aPageIter = maPrevwPages.begin();
1241           aPageIter != maPrevwPages.end();
1242           ++aPageIter )
1243     {
1244         if ( !(*aPageIter)->bVisible )
1245             continue;
1246 
1247         Rectangle aPageRect( (*aPageIter)->aLogicPos, (*aPageIter)->aPageSize );
1248         if ( _aInvalidCoreRect.IsOver( aPageRect ) )
1249         {
1250             aPageRect.Intersection( _aInvalidCoreRect );
1251             Rectangle aInvalidPrevwRect = aPageRect;
1252             aInvalidPrevwRect.SetPos( aInvalidPrevwRect.TopLeft() -
1253                                       (*aPageIter)->aLogicPos +
1254                                       (*aPageIter)->aPrevwWinPos );
1255             mrParentViewShell.GetWin()->Invalidate( aInvalidPrevwRect );
1256         }
1257     }
1258 }
1259 
1260 /** paint selection mark at page
1261 
1262     OD 17.12.2002 #103492#
1263 
1264     @author OD
1265 */
1266 void SwPagePreviewLayout::_PaintSelectMarkAtPage(
1267                                     const PrevwPage* _aSelectedPrevwPage ) const
1268 {
1269     OutputDevice* pOutputDev = mrParentViewShell.GetOut();
1270     MapMode aMapMode( pOutputDev->GetMapMode() );
1271     // save mapping mode of output device
1272     MapMode aSavedMapMode = aMapMode;
1273     // save fill and line color of output device
1274     Color aFill( pOutputDev->GetFillColor() );
1275     Color aLine( pOutputDev->GetLineColor() );
1276 
1277     // determine selection mark color
1278     Color aSelPgLineColor(COL_LIGHTBLUE);
1279     const StyleSettings& rSettings =
1280         mrParentViewShell.GetWin()->GetSettings().GetStyleSettings();
1281     if ( rSettings.GetHighContrastMode() )
1282         aSelPgLineColor = rSettings.GetHighlightTextColor();
1283 
1284     // set needed mapping mode at output device
1285     aMapMode.SetOrigin( _aSelectedPrevwPage->aMapOffset );
1286     pOutputDev->SetMapMode( aMapMode );
1287 
1288     // calculate page rectangle in pixel coordinates
1289     SwRect aPageRect( _aSelectedPrevwPage->aLogicPos,
1290                          _aSelectedPrevwPage->aPageSize );
1291     // OD 19.02.2003 #107369# - use aligned page rectangle, as it is used for
1292     // page border paint - see <SwPageFrm::PaintPageBorder(..)>
1293     ::SwAlignRect( aPageRect, &mrParentViewShell);
1294     Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
1295 
1296     // draw two rectangles
1297     // OD 19.02.2003 #107369# - adjust position of select mark rectangle
1298     Rectangle aRect( aPxPageRect.Left(), aPxPageRect.Top(),
1299                        aPxPageRect.Right(), aPxPageRect.Bottom() );
1300     aRect = pOutputDev->PixelToLogic( aRect );
1301     pOutputDev->SetFillColor(); // OD 20.02.2003 #107369# - no fill color
1302     pOutputDev->SetLineColor( aSelPgLineColor );
1303     pOutputDev->DrawRect( aRect );
1304     // OD 19.02.2003 #107369# - adjust position of select mark rectangle
1305     aRect = Rectangle( aPxPageRect.Left()+1, aPxPageRect.Top()+1,
1306                        aPxPageRect.Right()-1, aPxPageRect.Bottom()-1 );
1307     aRect = pOutputDev->PixelToLogic( aRect );
1308     pOutputDev->DrawRect( aRect );
1309 
1310     // reset fill and line color of output device
1311     pOutputDev->SetFillColor( aFill );
1312     pOutputDev->SetLineColor( aLine );
1313 
1314     // reset mapping mode of output device
1315     pOutputDev->SetMapMode( aSavedMapMode );
1316 }
1317 
1318 /** paint to mark new selected page
1319 
1320     OD 17.12.2002 #103492#
1321     Perform paint for current selected page in order to unmark it.
1322     Set new selected page and perform paint to mark this page.
1323 
1324     @author OD, _nSelectedPage, mnSelectedPage are absolute
1325 */
1326 void SwPagePreviewLayout::MarkNewSelectedPage( const sal_uInt16 _nSelectedPage )
1327 {
1328     sal_uInt16 nOldSelectedPageNum = mnSelectedPageNum;
1329     mnSelectedPageNum = _nSelectedPage;
1330 
1331     // re-paint for current selected page in order to unmark it.
1332     const PrevwPage* pOldSelectedPrevwPage = _GetPrevwPageByPageNum( nOldSelectedPageNum );
1333     if ( pOldSelectedPrevwPage && pOldSelectedPrevwPage->bVisible )
1334     {
1335         // OD 20.02.2003 #107369# - invalidate only areas of selection mark.
1336         SwRect aPageRect( pOldSelectedPrevwPage->aPrevwWinPos,
1337                               pOldSelectedPrevwPage->aPageSize );
1338         ::SwAlignRect( aPageRect, &mrParentViewShell);
1339         OutputDevice* pOutputDev = mrParentViewShell.GetOut();
1340         Rectangle aPxPageRect = pOutputDev->LogicToPixel( aPageRect.SVRect() );
1341         // invalidate top mark line
1342         Rectangle aInvalPxRect( aPxPageRect.Left(), aPxPageRect.Top(),
1343                                 aPxPageRect.Right(), aPxPageRect.Top()+1 );
1344         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1345         // invalidate right mark line
1346         aInvalPxRect = Rectangle( aPxPageRect.Right()-1, aPxPageRect.Top(),
1347                                   aPxPageRect.Right(), aPxPageRect.Bottom() );
1348         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1349         // invalidate bottom mark line
1350         aInvalPxRect = Rectangle( aPxPageRect.Left(), aPxPageRect.Bottom()-1,
1351                                   aPxPageRect.Right(), aPxPageRect.Bottom() );
1352         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1353         // invalidate left mark line
1354         aInvalPxRect = Rectangle( aPxPageRect.Left(), aPxPageRect.Top(),
1355                                   aPxPageRect.Left()+1, aPxPageRect.Bottom() );
1356         mrParentViewShell.GetWin()->Invalidate( pOutputDev->PixelToLogic( aInvalPxRect ) );
1357     }
1358 
1359     // re-paint for new selected page in order to mark it.
1360     const PrevwPage* pNewSelectedPrevwPage = _GetPrevwPageByPageNum( _nSelectedPage );
1361     if ( pNewSelectedPrevwPage && pNewSelectedPrevwPage->bVisible )
1362         _PaintSelectMarkAtPage( pNewSelectedPrevwPage );
1363 }
1364 
1365 
1366 // =============================================================================
1367 // helper methods
1368 // =============================================================================
1369 /** get preview page by physical page number
1370 
1371     OD 17.12.2002 #103492#
1372 
1373     @author OD
1374 */
1375 struct EqualsPageNumPred
1376 {
1377     const sal_uInt16 mnPageNum;
1378     EqualsPageNumPred( const sal_uInt16 _nPageNum ) : mnPageNum( _nPageNum ) {};
1379     bool operator() ( const PrevwPage* _pPrevwPage )
1380     {
1381         return _pPrevwPage->pPage->GetPhyPageNum() == mnPageNum;
1382     }
1383 };
1384 
1385 const PrevwPage* SwPagePreviewLayout::_GetPrevwPageByPageNum( const sal_uInt16 _nPageNum ) const
1386 {
1387     std::vector<PrevwPage*>::const_iterator aFoundPrevwPageIter =
1388             std::find_if( maPrevwPages.begin(), maPrevwPages.end(),
1389                           EqualsPageNumPred( _nPageNum ) );
1390 
1391     if ( aFoundPrevwPageIter == maPrevwPages.end() )
1392         return 0;
1393     else
1394         return (*aFoundPrevwPageIter);
1395 }
1396 
1397 /** determine row the page with the given number is in
1398 
1399     OD 17.01.2003 #103492#
1400 
1401     @author OD, _nPageNum is relative
1402 */
1403 sal_uInt16 SwPagePreviewLayout::GetRowOfPage( sal_uInt16 _nPageNum ) const
1404 {
1405     // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
1406     // by <mbBookPreview>.
1407     if ( mbBookPreview )
1408     {
1409         // Note: increase given physical page number by one, because left-top-corner
1410         //       in the preview layout is left blank.
1411         ++_nPageNum;
1412     }
1413 
1414     sal_uInt16 nRow = (_nPageNum) / mnCols;
1415     if ( ( (_nPageNum) % mnCols ) > 0 )
1416         ++nRow;
1417 
1418     return nRow;
1419 }
1420 
1421 /** determine column the page with the given number is in
1422 
1423     OD 17.01.2003 #103492#
1424 
1425     @author OD, _nPageNum is relative
1426 */
1427 sal_uInt16 SwPagePreviewLayout::GetColOfPage( sal_uInt16 _nPageNum ) const
1428 {
1429     // OD 19.02.2003 #107369# - leaving left-top-corner blank is controlled
1430     // by <mbBookPreview>.
1431     if ( mbBookPreview )
1432     {
1433         // Note: increase given physical page number by one, because left-top-corner
1434         //       in the preview layout is left blank.
1435         ++_nPageNum;
1436     }
1437 
1438     sal_uInt16 nCol = (_nPageNum) % mnCols;
1439     if ( nCol == 0 )
1440         nCol = mnCols;
1441 
1442     return nCol;
1443 }
1444 
1445 Size SwPagePreviewLayout::GetPrevwDocSize() const
1446 {
1447     ASSERT( PreviewLayoutValid(), "PagePreviewLayout not valid" );
1448     return maPreviewDocRect.GetSize();
1449 }
1450 
1451 /** get size of a preview page by its physical page number
1452 
1453     OD 15.01.2003 #103492#
1454 
1455     @author OD
1456 */
1457 Size SwPagePreviewLayout::GetPrevwPageSizeByPageNum( sal_uInt16 _nPageNum ) const
1458 {
1459     const PrevwPage* pPrevwPage = _GetPrevwPageByPageNum( _nPageNum );
1460     if ( pPrevwPage )
1461     {
1462         return pPrevwPage->aPageSize;
1463     }
1464     else
1465     {
1466         return Size( 0, 0 );
1467     }
1468 }
1469 
1470 /** get virtual page number by its physical page number
1471 
1472     OD 21.03.2003 #108282#
1473 
1474     @author OD
1475 */
1476 sal_uInt16 SwPagePreviewLayout::GetVirtPageNumByPageNum( sal_uInt16 _nPageNum ) const
1477 {
1478     const PrevwPage* pPrevwPage = _GetPrevwPageByPageNum( _nPageNum );
1479     if ( pPrevwPage )
1480     {
1481         return pPrevwPage->pPage->GetVirtPageNum();
1482     }
1483     else
1484     {
1485         return 0;
1486     }
1487 }
1488 
1489 /** Convert absolute to relative page numbers (see PrintEmptyPages)
1490 
1491     @author FME
1492 */
1493 sal_uInt16 SwPagePreviewLayout::ConvertAbsoluteToRelativePageNum( sal_uInt16 _nAbsPageNum ) const
1494 {
1495     if ( mbBookPreview || mbPrintEmptyPages || !_nAbsPageNum )
1496     {
1497         return _nAbsPageNum;
1498     }
1499 
1500     const SwPageFrm* pTmpPage = static_cast<const SwPageFrm*>(mrLayoutRootFrm.Lower());
1501 
1502     sal_uInt16 nRet = 1;
1503 
1504     while ( pTmpPage && pTmpPage->GetPhyPageNum() != _nAbsPageNum )
1505     {
1506         if ( !pTmpPage->IsEmptyPage() )
1507             ++nRet;
1508 
1509         pTmpPage = static_cast<const SwPageFrm*>( pTmpPage->GetNext() );
1510     }
1511 
1512     return nRet;
1513 }
1514 
1515 /** Convert relative to absolute page numbers (see PrintEmptyPages)
1516 
1517     @author FME
1518 */
1519 sal_uInt16 SwPagePreviewLayout::ConvertRelativeToAbsolutePageNum( sal_uInt16 _nRelPageNum ) const
1520 {
1521     if ( mbBookPreview || mbPrintEmptyPages || !_nRelPageNum )
1522     {
1523         return _nRelPageNum;
1524     }
1525 
1526     const SwPageFrm* pTmpPage = static_cast<const SwPageFrm*>(mrLayoutRootFrm.Lower());
1527     const SwPageFrm* pRet = 0;
1528 
1529     sal_uInt16 i = 0;
1530     while( pTmpPage && i != _nRelPageNum )
1531     {
1532         if ( !pTmpPage->IsEmptyPage() )
1533             ++i;
1534 
1535         pRet = pTmpPage;
1536         pTmpPage = static_cast<const SwPageFrm*>( pTmpPage->GetNext() );
1537     }
1538 
1539     return pRet->GetPhyPageNum();
1540 }
1541