Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sd/source/ui/view/DocumentRenderer.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <com/sun/star/beans/XPropertySet.hpp>
21
22
#include <DocumentRenderer.hxx>
23
#include <DocumentRenderer.hrc>
24
#include <ViewShellBase.hxx>
25
26
#include <drawdoc.hxx>
27
#include <sdpage.hxx>
28
#include <sdresid.hxx>
29
#include <strings.hrc>
30
#include <drawview.hxx>
31
#include <DrawViewShell.hxx>
32
#include <FrameView.hxx>
33
#include <Outliner.hxx>
34
#include <OutlineViewShell.hxx>
35
#include <SlideSorterViewShell.hxx>
36
#include <DrawDocShell.hxx>
37
38
#include <tools/multisel.hxx>
39
#include <basegfx/polygon/b2dpolygon.hxx>
40
#include <basegfx/polygon/b2dpolypolygon.hxx>
41
#include <basegfx/matrix/b2dhommatrix.hxx>
42
#include <comphelper/propertyvalue.hxx>
43
#include <comphelper/sequence.hxx>
44
#include <rtl/ustrbuf.hxx>
45
#include <editeng/editstat.hxx>
46
#include <editeng/eeitem.hxx>
47
#include <editeng/outlobj.hxx>
48
#include <editeng/ulspitem.hxx>
49
#include <svx/sdtfsitm.hxx>
50
#include <svx/sdooitm.hxx>
51
#include <svx/svdetc.hxx>
52
#include <svx/svditer.hxx>
53
#include <svx/svdopage.hxx>
54
#include <svx/svdopath.hxx>
55
#include <svx/svdpagv.hxx>
56
#include <svx/xlineit0.hxx>
57
#include <svx/xlnclit.hxx>
58
#include <toolkit/awt/vclxdevice.hxx>
59
#include <unotools/localedatawrapper.hxx>
60
#include <utility>
61
#include <vcl/print.hxx>
62
#include <vcl/svapp.hxx>
63
#include <vcl/weld/weld.hxx>
64
#include <unotools/moduleoptions.hxx>
65
#include <xmloff/autolayout.hxx>
66
#include <sfx2/objsh.hxx>
67
68
#include <svl/cjkoptions.hxx>
69
#include <svl/ctloptions.hxx>
70
71
#include <officecfg/Office/Draw.hxx>
72
#include <officecfg/Office/Impress.hxx>
73
74
#include <algorithm>
75
#include <memory>
76
#include <vector>
77
78
using namespace ::com::sun::star;
79
using namespace ::com::sun::star::uno;
80
81
namespace sd {
82
83
namespace {
84
85
    void lcl_AdjustPageSize(Size& rPageSize, const Size& rPrintPageSize)
86
0
    {
87
0
        bool bOrientationDiff = (rPageSize.Width() < rPageSize.Height()
88
0
                                 && rPrintPageSize.Width() > rPrintPageSize.Height())
89
0
                                || (rPageSize.Width() > rPageSize.Height()
90
0
                                    && rPrintPageSize.Width() < rPrintPageSize.Height());
91
0
        if (bOrientationDiff)
92
0
        {
93
0
            ::tools::Long nTmp = rPageSize.Width();
94
0
            rPageSize.setWidth(rPageSize.Height());
95
0
            rPageSize.setHeight(nTmp);
96
0
        }
97
0
    }
98
99
    /** Convenience class to extract values from the sequence of properties
100
        given to one of the XRenderable methods.
101
    */
102
    class PrintOptions
103
    {
104
    public:
105
        PrintOptions (
106
            const vcl::PrinterOptionsHelper& rHelper,
107
            std::vector<sal_Int32>&& rSlidesPerPage)
108
0
            : mrProperties(rHelper),
109
0
              maSlidesPerPage(std::move(rSlidesPerPage))
110
0
        {
111
0
        }
112
113
        bool IsWarningOrientation() const
114
0
        {
115
0
            return GetBoolValue(nullptr, true);
116
0
        }
117
118
        bool IsPrintPageName() const
119
0
        {
120
0
            return GetBoolValue("IsPrintName", false);
121
0
        }
122
123
        bool IsDate() const
124
0
        {
125
0
            return GetBoolValue("IsPrintDateTime", false);
126
0
        }
127
128
        bool IsTime() const
129
0
        {
130
0
            return GetBoolValue("IsPrintDateTime", false);
131
0
        }
132
133
        bool IsHiddenPages() const
134
0
        {
135
0
            return GetBoolValue("IsPrintHidden", false);
136
0
        }
137
138
        bool IsHandoutHorizontal() const
139
0
        {
140
0
            return GetBoolValue("SlidesPerPageOrder", sal_Int32(0));
141
0
        }
142
143
        sal_Int32 GetHandoutPageCount() const
144
0
        {
145
0
            sal_uInt32 nIndex = static_cast<sal_Int32>(mrProperties.getIntValue("SlidesPerPage", sal_Int32(0)));
146
0
            if (nIndex<maSlidesPerPage.size())
147
0
                return maSlidesPerPage[nIndex];
148
0
            else if ( ! maSlidesPerPage.empty())
149
0
                return maSlidesPerPage[0];
150
0
            else
151
0
                return 0;
152
0
        }
153
154
        bool IsDraw() const
155
0
        {
156
0
            return GetBoolValue("PageContentType", sal_Int32(0));
157
0
        }
158
159
        bool IsHandout() const
160
0
        {
161
0
            return GetBoolValue("PageContentType", sal_Int32(1));
162
0
        }
163
164
        bool IsNotes() const
165
0
        {
166
0
            return GetBoolValue("PageContentType", sal_Int32(2));
167
0
        }
168
169
        bool IsOutline() const
170
0
        {
171
0
            return GetBoolValue("PageContentType", sal_Int32(3));
172
0
        }
173
174
        sal_uLong GetOutputQuality() const
175
0
        {
176
0
            sal_Int32 nQuality = static_cast<sal_Int32>(mrProperties.getIntValue( "Quality", sal_Int32(0) ));
177
0
            return nQuality;
178
0
        }
179
180
        bool IsPageSize() const
181
0
        {
182
0
            return GetBoolValue("PageOptions", sal_Int32(1));
183
0
        }
184
185
        bool IsTilePage() const
186
0
        {
187
0
            return GetBoolValue("PageOptions", sal_Int32(2)) || GetBoolValue("PageOptions", sal_Int32(3));
188
0
        }
189
190
        bool IsCutPage() const
191
0
        {
192
0
            return GetBoolValue("PageOptions", sal_Int32(0));
193
0
        }
194
195
        bool IsBooklet() const
196
0
        {
197
0
            return GetBoolValue("PrintProspect", false);
198
0
        }
199
200
        bool IsProspectRTL() const
201
0
        {
202
0
            return mrProperties.getIntValue( "PrintProspectRTL",  0 ) != 0;
203
0
        }
204
205
        bool IsPrinterPreferred(DocumentType eDocType) const
206
0
        {
207
0
            bool bIsDraw = eDocType == DocumentType::Draw;
208
0
            return IsTilePage() || IsPageSize() || IsBooklet() || (!bIsDraw && !IsNotes());
209
0
        }
210
211
        bool IsPrintExcluded() const
212
0
        {
213
0
            return (IsNotes() || IsDraw() || IsHandout()) &&  IsHiddenPages();
214
0
        }
215
216
        bool IsPrintFrontPage() const
217
0
        {
218
0
            sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
219
0
            return nInclude != 2;
220
0
        }
221
222
        bool IsPrintBackPage() const
223
0
        {
224
0
            sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
225
0
            return nInclude != 1;
226
0
        }
227
228
        bool IsPaperBin() const
229
0
        {
230
0
            return GetBoolValue("PrintPaperFromSetup", false);
231
0
        }
232
233
        bool IsPrintMarkedOnly() const
234
0
        {
235
0
            return GetBoolValue("PrintContent", sal_Int32(4));
236
0
        }
237
238
        OUString GetPrinterSelection (sal_Int32 nPageCount, sal_Int32 nCurrentPageIndex) const
239
0
        {
240
0
            sal_Int32 nContent = static_cast<sal_Int32>(mrProperties.getIntValue( "PrintContent", 0 ));
241
0
            OUString sFullRange = "1-" + OUString::number(nPageCount);
242
243
0
            if (nContent == 0) // all pages/slides
244
0
            {
245
0
                return sFullRange;
246
0
            }
247
248
0
            if (nContent == 1) // range
249
0
            {
250
0
                OUString sValue = mrProperties.getStringValue("PageRange");
251
0
                return sValue.isEmpty() ? sFullRange : sValue;
252
0
            }
253
254
0
            if (nContent == 2 && // selection
255
0
                nCurrentPageIndex >= 0)
256
0
            {
257
0
                return OUString::number(nCurrentPageIndex + 1);
258
0
            }
259
260
0
            return OUString();
261
0
        }
262
263
    private:
264
        const vcl::PrinterOptionsHelper& mrProperties;
265
        const std::vector<sal_Int32> maSlidesPerPage;
266
267
        /** When the value of the property with name pName is a boolean then
268
            return its value. When the property is unknown then
269
            bDefaultValue is returned.  Otherwise <FALSE/> is returned.
270
        */
271
        bool GetBoolValue (
272
            const char* pName,
273
            const bool bDefaultValue) const
274
0
        {
275
0
            bool bValue = mrProperties.getBoolValue( pName, bDefaultValue );
276
0
            return bValue;
277
0
        }
278
279
        /** Return <TRUE/> when the value of the property with name pName is
280
            an integer and its value is nTriggerValue. Otherwise <FALSE/> is
281
            returned.
282
        */
283
        bool GetBoolValue (
284
            const char* pName,
285
            const sal_Int32 nTriggerValue) const
286
0
        {
287
0
            sal_Int32 nValue = static_cast<sal_Int32>(mrProperties.getIntValue( pName, 0 ));
288
0
            return nValue == nTriggerValue;
289
0
        }
290
    };
291
292
    /** A collection of values that helps to reduce the number of arguments
293
        given to some functions.  Note that not all values are set at the
294
        same time.
295
    */
296
    class PrintInfo
297
    {
298
    public:
299
        PrintInfo (
300
            Printer* pPrinter,
301
            const bool bPrintMarkedOnly)
302
0
            : mpPrinter(pPrinter),
303
0
              mnDrawMode(DrawModeFlags::Default),
304
0
              maPrintSize(0,0),
305
0
              maPageSize(0,0),
306
0
              meOrientation(Orientation::Portrait),
307
0
              mbPrintMarkedOnly(bPrintMarkedOnly)
308
0
        {}
309
310
        const VclPtr<Printer> mpPrinter;
311
        DrawModeFlags mnDrawMode;
312
        OUString msTimeDate;
313
        OUString msPageString;
314
        Size maPrintSize;
315
        Size maPageSize;
316
        Orientation meOrientation;
317
        MapMode maMap;
318
        const bool mbPrintMarkedOnly;
319
    };
320
321
    /** Output one page of the document to the given printer.  Note that
322
        more than one document page may be output to one printer page.
323
    */
324
    void PrintPage (
325
        Printer& rPrinter,
326
        ::sd::View& rPrintView,
327
        SdPage& rPage,
328
        View const * pView,
329
        const bool bPrintMarkedOnly,
330
        const SdrLayerIDSet& rVisibleLayers,
331
        const SdrLayerIDSet& rPrintableLayers)
332
0
    {
333
0
        rPrintView.ShowSdrPage(&rPage);
334
335
0
        const MapMode aOriginalMapMode (rPrinter.GetMapMode());
336
337
        // Set the visible layers
338
0
        SdrPageView* pPageView = rPrintView.GetSdrPageView();
339
0
        OSL_ASSERT(pPageView!=nullptr);
340
0
        pPageView->SetVisibleLayers(rVisibleLayers);
341
0
        pPageView->SetPrintableLayers(rPrintableLayers);
342
343
0
        if (pView!=nullptr && bPrintMarkedOnly)
344
0
            pView->DrawMarkedObj(rPrinter);
345
0
        else
346
0
            rPrintView.CompleteRedraw(&rPrinter,
347
0
                    vcl::Region(::tools::Rectangle(Point(0,0), rPage.GetSize())));
348
349
0
        rPrinter.SetMapMode(aOriginalMapMode);
350
351
0
        rPrintView.HideSdrPage();
352
0
    }
353
354
    /** Output a string (that typically is not part of a document page) to
355
        the given printer.
356
    */
357
    void PrintMessage (
358
        Printer& rPrinter,
359
        const OUString& rsPageString,
360
        const Point& rPageStringOffset)
361
0
    {
362
0
        const vcl::Font aOriginalFont (rPrinter.OutputDevice::GetFont());
363
0
        rPrinter.SetFont(vcl::Font(FAMILY_SWISS, Size(0, 423)));
364
0
        rPrinter.DrawText(rPageStringOffset, rsPageString);
365
0
        rPrinter.SetFont(aOriginalFont);
366
0
    }
367
368
    /** Read the resources and process then into a sequence of properties
369
        that can be passed to the printing dialog.
370
    */
371
    class DialogCreator
372
    {
373
    public:
374
        DialogCreator (ViewShellBase &rBase, bool bImpress, sal_Int32 nCurPage)
375
0
            : mrBase(rBase)
376
0
            , mbImpress(bImpress)
377
0
            , mnCurPage(nCurPage)
378
0
        {
379
0
            ProcessResource();
380
0
        }
381
382
        const std::vector< beans::PropertyValue >& GetDialogControls() const
383
0
        {
384
0
            return maProperties;
385
0
        }
386
387
        const std::vector<sal_Int32>& GetSlidesPerPage() const
388
0
        {
389
0
            return maSlidesPerPage;
390
0
        }
391
392
    private:
393
        ViewShellBase &mrBase;
394
        std::vector<beans::PropertyValue> maProperties;
395
        std::vector<sal_Int32> maSlidesPerPage;
396
        bool mbImpress;
397
        sal_Int32 mnCurPage;
398
399
        void ProcessResource()
400
0
        {
401
            // load the impress or draw PrinterOptions into the custom tab
402
0
            beans::PropertyValue aOptionsUIFile;
403
0
            aOptionsUIFile.Name = "OptionsUIFile";
404
0
            if( mbImpress )
405
0
                aOptionsUIFile.Value <<= u"modules/simpress/ui/impressprinteroptions.ui"_ustr;
406
0
            else
407
0
                aOptionsUIFile.Value <<= u"modules/sdraw/ui/drawprinteroptions.ui"_ustr;
408
0
            maProperties.push_back(aOptionsUIFile);
409
410
0
            SvtModuleOptions aOpt;
411
0
            OUString aAppGroupname(SdResId(STR_IMPRESS_PRINT_UI_GROUP_NAME));
412
0
            aAppGroupname = aAppGroupname.replaceFirst("%s", aOpt.GetModuleName(
413
0
                mbImpress ? SvtModuleOptions::EModule::IMPRESS : SvtModuleOptions::EModule::DRAW));
414
0
            AddDialogControl(vcl::PrinterOptionsHelper::setGroupControlOpt(u"tabcontrol-page2"_ustr, aAppGroupname, u".HelpID:vcl:PrintDialog:TabPage:AppPage"_ustr));
415
416
0
            uno::Sequence< OUString > aHelpIds, aWidgetIds;
417
0
            if( mbImpress )
418
0
            {
419
0
                aHelpIds = { u".HelpID:vcl:PrintDialog:PageContentType:ListBox"_ustr };
420
0
                AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
421
0
                                    u"impressdocument"_ustr,
422
0
                                    SdResId(STR_IMPRESS_PRINT_UI_CONTENT),
423
0
                                    aHelpIds,
424
0
                                    u"PageContentType"_ustr ,
425
0
                                    CreateChoice(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES)),
426
0
                                    0)
427
0
                                );
428
429
0
                aHelpIds = { u".HelpID:vcl:PrintDialog:SlidesPerPage:ListBox"_ustr };
430
0
                vcl::PrinterOptionsHelper::UIControlOptions aContentOpt( u"PageContentType"_ustr , 1 );
431
0
                AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
432
0
                                    u"slidesperpage"_ustr,
433
0
                                    SdResId(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE),
434
0
                                    aHelpIds,
435
0
                                    u"SlidesPerPage"_ustr ,
436
0
                                    GetSlidesPerPageSequence(),
437
0
                                    0,
438
0
                                    Sequence< sal_Bool >(),
439
0
                                    aContentOpt
440
0
                                    )
441
0
                                );
442
443
0
                aHelpIds = { u".HelpID:vcl:PrintDialog:SlidesPerPageOrder:ListBox"_ustr };
444
0
                vcl::PrinterOptionsHelper::UIControlOptions aSlidesPerPageOpt( u"SlidesPerPage"_ustr , -1, true );
445
0
                AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
446
0
                                    u"slidesperpageorder"_ustr,
447
0
                                    SdResId(STR_IMPRESS_PRINT_UI_ORDER),
448
0
                                    aHelpIds,
449
0
                                    u"SlidesPerPageOrder"_ustr ,
450
0
                                    CreateChoice(STR_IMPRESS_PRINT_UI_ORDER_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_ORDER_CHOICES)),
451
0
                                    0,
452
0
                                    Sequence< sal_Bool >(),
453
0
                                    aSlidesPerPageOpt )
454
0
                                );
455
0
            }
456
457
0
            AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"contents"_ustr,
458
0
                               SdResId(STR_IMPRESS_PRINT_UI_INCLUDE_CONTENT), u""_ustr ) );
459
460
0
            if( mbImpress )
461
0
            {
462
0
                AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printname"_ustr,
463
0
                                    SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_NAME),
464
0
                                    u".HelpID:vcl:PrintDialog:IsPrintName:CheckBox"_ustr ,
465
0
                                    u"IsPrintName"_ustr ,
466
0
                                    officecfg::Office::Impress::Print::Other::PageName::get()
467
0
                                    )
468
0
                                );
469
0
            }
470
0
            else
471
0
            {
472
0
                AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printname"_ustr,
473
0
                                    SdResId(STR_DRAW_PRINT_UI_IS_PRINT_NAME),
474
0
                                    u".HelpID:vcl:PrintDialog:IsPrintName:CheckBox"_ustr ,
475
0
                                    u"IsPrintName"_ustr ,
476
0
                                    officecfg::Office::Draw::Print::Other::PageName::get()
477
0
                                    )
478
0
                                );
479
0
            }
480
481
0
            AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printdatetime"_ustr,
482
0
                                SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_DATE),
483
0
                                u".HelpID:vcl:PrintDialog:IsPrintDateTime:CheckBox"_ustr ,
484
0
                                u"IsPrintDateTime"_ustr ,
485
                                // Separate settings for time and date in Impress/Draw -> Print page, check that both are set
486
0
                                mbImpress ?
487
0
                                officecfg::Office::Impress::Print::Other::Date::get() &&
488
0
                                officecfg::Office::Impress::Print::Other::Time::get() :
489
0
                                officecfg::Office::Draw::Print::Other::Date::get() &&
490
0
                                officecfg::Office::Draw::Print::Other::Time::get()
491
0
                                )
492
0
                            );
493
494
0
            if( mbImpress )
495
0
            {
496
0
                AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printhidden"_ustr,
497
0
                                    SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_HIDDEN),
498
0
                                    u".HelpID:vcl:PrintDialog:IsPrintHidden:CheckBox"_ustr ,
499
0
                                    u"IsPrintHidden"_ustr ,
500
0
                                    officecfg::Office::Impress::Print::Other::HiddenPage::get()
501
0
                                    )
502
0
                                );
503
0
            }
504
505
0
            AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"color"_ustr,
506
0
                               SdResId(STR_IMPRESS_PRINT_UI_QUALITY), u""_ustr ) );
507
508
0
            aHelpIds = { u".HelpID:vcl:PrintDialog:Quality:RadioButton:0"_ustr,
509
0
                         u".HelpID:vcl:PrintDialog:Quality:RadioButton:1"_ustr,
510
0
                         u".HelpID:vcl:PrintDialog:Quality:RadioButton:2"_ustr };
511
0
            aWidgetIds = { u"originalcolors"_ustr, u"grayscale"_ustr, u"blackandwhite"_ustr };
512
0
            AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
513
0
                                aWidgetIds,
514
0
                                u""_ustr,
515
0
                                aHelpIds,
516
0
                                u"Quality"_ustr ,
517
0
                                CreateChoice(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES)),
518
0
                                mbImpress ? officecfg::Office::Impress::Print::Other::Quality::get() :
519
0
                                            officecfg::Office::Draw::Print::Other::Quality::get() )
520
521
0
                            );
522
523
0
            AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"pagesizes"_ustr,
524
0
                               SdResId(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS), u""_ustr ) );
525
526
0
            aHelpIds = { u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:0"_ustr,
527
0
                         u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:1"_ustr,
528
0
                         u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:2"_ustr,
529
0
                         u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:3"_ustr };
530
0
            aWidgetIds = { u"originalsize"_ustr, u"fittoprintable"_ustr, u"distributeonmultiple"_ustr, u"tilesheet"_ustr };
531
532
            // Mutually exclusive page options settings are stored in separate config keys...
533
            // TODO: There is no config key to set the distributeonmultiple option as default
534
0
            sal_Int32 nDefaultChoice = 0;
535
0
            if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageSize::get() :
536
0
                             officecfg::Office::Draw::Print::Page::PageSize::get() )
537
0
            {
538
0
                nDefaultChoice = 1;
539
0
            }
540
0
            else if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageTile::get() :
541
0
                                  officecfg::Office::Draw::Print::Page::PageTile::get() )
542
0
            {
543
0
                nDefaultChoice = 3;
544
0
            }
545
0
            vcl::PrinterOptionsHelper::UIControlOptions aPageOptionsOpt(u"PrintProspect"_ustr, 0);
546
0
            AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
547
0
                                aWidgetIds,
548
0
                                u""_ustr,
549
0
                                aHelpIds,
550
0
                                u"PageOptions"_ustr ,
551
0
                                mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES)) :
552
0
                                            CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW)),
553
0
                                nDefaultChoice,
554
0
                                Sequence< sal_Bool >(),
555
0
                                aPageOptionsOpt
556
0
                                )
557
0
                            );
558
559
0
            vcl::PrinterOptionsHelper::UIControlOptions aBrochureOpt;
560
0
            aBrochureOpt.maGroupHint = "LayoutPage" ;
561
0
            AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"pagesides"_ustr,
562
0
                               SdResId(STR_IMPRESS_PRINT_UI_PAGE_SIDES), u""_ustr,
563
0
                               aBrochureOpt ) );
564
565
            // brochure printing
566
0
            AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"brochure"_ustr,
567
0
                                SdResId(STR_IMPRESS_PRINT_UI_BROCHURE),
568
0
                                u".HelpID:vcl:PrintDialog:PrintProspect:CheckBox"_ustr ,
569
0
                                u"PrintProspect"_ustr ,
570
0
                                mbImpress ? officecfg::Office::Impress::Print::Page::Booklet::get() :
571
0
                                            officecfg::Office::Draw::Print::Page::Booklet::get(),
572
0
                                aBrochureOpt
573
0
                                )
574
0
                            );
575
576
            // check if either CJK or CTL is enabled
577
0
            bool bRTL = SvtCJKOptions::IsCJKFontEnabled() || SvtCTLOptions::IsCTLFontEnabled();
578
579
0
            if(bRTL)
580
0
            {
581
0
                uno::Sequence< OUString > aBRTLChoices{ SdResId(STR_IMPRESS_PRINT_UI_LEFT_SCRIPT),
582
0
                                                        SdResId(STR_IMPRESS_PRINT_UI_RIGHT_SCRIPT) };
583
0
                vcl::PrinterOptionsHelper::UIControlOptions
584
0
                    aIncludeOpt( u"PrintProspect"_ustr , -1, true );
585
0
                aIncludeOpt.maGroupHint =  "LayoutPage" ;
586
0
                aHelpIds = { u".HelpID:vcl:PrintDialog:PrintProspectRTL:ListBox"_ustr };
587
0
                AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
588
0
                                u"scriptdirection"_ustr,
589
0
                                SdResId(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE),
590
0
                                aHelpIds,
591
0
                                u"PrintProspectRTL"_ustr ,
592
0
                                aBRTLChoices,
593
0
                                0,
594
0
                                Sequence< sal_Bool >(),
595
0
                                aIncludeOpt
596
0
                                )
597
0
                            );
598
0
            }
599
            // paper tray (on options page)
600
0
            vcl::PrinterOptionsHelper::UIControlOptions aPaperTrayOpt;
601
0
            aPaperTrayOpt.maGroupHint = "OptionsPageOptGroup" ;
602
0
            AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printpaperfromsetup"_ustr,
603
0
                                SdResId(STR_IMPRESS_PRINT_UI_PAPER_TRAY),
604
0
                                u".HelpID:vcl:PrintDialog:PrintPaperFromSetup:CheckBox"_ustr ,
605
0
                                u"PrintPaperFromSetup"_ustr ,
606
0
                                false,
607
0
                                aPaperTrayOpt
608
0
                                )
609
0
                            );
610
            // print range selection
611
0
            vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
612
0
            aPrintRangeOpt.mbInternalOnly = true;
613
0
            aPrintRangeOpt.maGroupHint = "PrintRange" ;
614
0
            AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"printrange"_ustr,
615
0
                                mbImpress ? SdResId(STR_IMPRESS_PRINT_UI_SLIDE_RANGE) : SdResId(STR_IMPRESS_PRINT_UI_PAGE_RANGE),
616
0
                                u""_ustr,
617
0
                                aPrintRangeOpt )
618
0
                             );
619
620
            // check if there is a selection of slides
621
0
            OUString aPageRange(OUString::number(mnCurPage + 1));
622
0
            int nPrintRange(0);
623
0
            using sd::slidesorter::SlideSorterViewShell;
624
0
            SlideSorterViewShell* const pSSViewSh(SlideSorterViewShell::GetSlideSorter(mrBase));
625
0
            if (pSSViewSh)
626
0
            {
627
0
                const std::shared_ptr<SlideSorterViewShell::PageSelection> pPageSelection(pSSViewSh->GetPageSelection());
628
0
                if (bool(pPageSelection) && pPageSelection->size() > 1)
629
0
                {
630
0
                    OUStringBuffer aBuf;
631
                    // TODO: this could be improved by writing ranges instead of consecutive page
632
                    // numbers if appropriate. Do we have a helper function for that somewhere?
633
0
                    bool bFirst(true);
634
0
                    for (auto pPage: *pPageSelection)
635
0
                    {
636
0
                        if (bFirst)
637
0
                            bFirst = false;
638
0
                        else
639
0
                            aBuf.append(',');
640
0
                        aBuf.append(static_cast<sal_Int32>(pPage->GetPageNum() / 2 + 1));
641
0
                    }
642
0
                    aPageRange = aBuf.makeStringAndClear();
643
0
                    nPrintRange = 1;
644
0
                }
645
0
            }
646
/*
647
            OUString aPrintRangeName( "PrintContent" );
648
            aHelpIds.realloc( 1 );
649
            aHelpIds[0] = ".HelpID:vcl:PrintDialog:PageContentType:ListBox";
650
            AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( "printpagesbox", OUString(),
651
                                aHelpIds, aPrintRangeName,
652
                                mbImpress ? CreateChoice( STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE ) ) :
653
                                            CreateChoice( STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE ) ),
654
                                nPrintRange ) );
655
*/
656
0
            OUString aPrintRangeName( u"PrintContent"_ustr );
657
0
            aHelpIds = { u".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0"_ustr,
658
0
                         u".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1"_ustr,
659
0
                         u".HelpID:vcl:PrintDialog:PrintContent:RadioButton:2"_ustr };
660
0
            aWidgetIds = { u"rbAllPages"_ustr, u"rbRangePages"_ustr, u"rbRangeSelection"_ustr };
661
662
0
            AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(aWidgetIds, OUString(),
663
0
                                aHelpIds, aPrintRangeName,
664
0
                                mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE)) :
665
0
                                            CreateChoice(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE)),
666
0
                                nPrintRange )
667
0
                            );
668
            // create an Edit dependent on "Pages" selected
669
0
            vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
670
0
            AddDialogControl(vcl::PrinterOptionsHelper::setEditControlOpt(u"pagerange"_ustr, u""_ustr,
671
0
                                u".HelpID:vcl:PrintDialog:PageRange:Edit"_ustr, u"PageRange"_ustr,
672
0
                                aPageRange, aPageRangeOpt));
673
0
            vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, -1, true);
674
0
            AddDialogControl(vcl::PrinterOptionsHelper::setChoiceListControlOpt(u"evenoddbox"_ustr, u""_ustr,
675
0
                                uno::Sequence<OUString>(), u"EvenOdd"_ustr, uno::Sequence<OUString>(),
676
0
                                0, uno::Sequence<sal_Bool>(), aEvenOddOpt));
677
0
        }
678
679
        void AddDialogControl( const Any& i_rCtrl )
680
0
        {
681
0
            beans::PropertyValue aVal;
682
0
            aVal.Value = i_rCtrl;
683
0
            maProperties.push_back( aVal );
684
0
        }
685
686
        static Sequence<OUString> CreateChoice(const TranslateId* pResourceId, size_t nCount)
687
0
        {
688
0
            Sequence<OUString> aChoices (nCount);
689
0
            std::transform(pResourceId, pResourceId + nCount, aChoices.getArray(),
690
0
                           [](const auto& id) { return SdResId(id); });
691
0
            return aChoices;
692
0
        }
693
694
        Sequence<OUString> GetSlidesPerPageSequence()
695
0
        {
696
0
            const Sequence<OUString> aChoice (
697
0
                CreateChoice(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES)));
698
0
            maSlidesPerPage.clear();
699
0
            maSlidesPerPage.push_back(0); // first is using the default
700
0
            std::transform(std::next(aChoice.begin()), aChoice.end(), std::back_inserter(maSlidesPerPage),
701
0
                            [](const OUString& rChoice) -> sal_Int32 { return rChoice.toInt32(); });
702
0
            return aChoice;
703
0
        }
704
    };
705
706
    /** The Prepare... methods of the DocumentRenderer::Implementation class
707
        create a set of PrinterPage objects that contain all necessary
708
        information to do the actual printing.  There is one PrinterPage
709
        object per printed page.  Derived classes implement the actual, mode
710
        specific printing.
711
712
        This and all derived classes support the asynchronous printing
713
        process by not storing pointers to any data with lifetime shorter
714
        than the PrinterPage objects, i.e. slides, shapes, (one of) the
715
        outliner (of the document).
716
    */
717
    class PrinterPage
718
    {
719
    public:
720
        PrinterPage (
721
            const PageKind ePageKind,
722
            const MapMode& rMapMode,
723
            const bool bPrintMarkedOnly,
724
            OUString sPageString,
725
            const Point& rPageStringOffset,
726
            const DrawModeFlags nDrawMode,
727
            const Orientation eOrientation,
728
            const sal_uInt16 nPaperTray)
729
0
            : mePageKind(ePageKind),
730
0
              maMap(rMapMode),
731
0
              mbPrintMarkedOnly(bPrintMarkedOnly),
732
0
              msPageString(std::move(sPageString)),
733
0
              maPageStringOffset(rPageStringOffset),
734
0
              mnDrawMode(nDrawMode),
735
0
              meOrientation(eOrientation),
736
0
              mnPaperTray(nPaperTray)
737
0
        {
738
0
        }
739
740
0
        virtual ~PrinterPage() {}
741
742
        virtual void Print (
743
            Printer& rPrinter,
744
            SdDrawDocument& rDocument,
745
            ViewShell& rViewShell,
746
            View* pView,
747
            DrawView& rPrintView,
748
            const SdrLayerIDSet& rVisibleLayers,
749
            const SdrLayerIDSet& rPrintableLayers) const = 0;
750
751
0
        DrawModeFlags GetDrawMode() const { return mnDrawMode; }
752
0
        Orientation GetOrientation() const { return meOrientation; }
753
0
        sal_uInt16 GetPaperTray() const { return mnPaperTray; }
754
755
    protected:
756
        const PageKind mePageKind;
757
        const MapMode maMap;
758
        const bool mbPrintMarkedOnly;
759
        const OUString msPageString;
760
        const Point maPageStringOffset;
761
        const DrawModeFlags mnDrawMode;
762
        const Orientation meOrientation;
763
        const sal_uInt16 mnPaperTray;
764
    };
765
766
    /** The RegularPrinterPage is used for printing one regular slide (no
767
        notes, handout, or outline) to one printer page.
768
    */
769
    class RegularPrinterPage : public PrinterPage
770
    {
771
    public:
772
        RegularPrinterPage (
773
            const sal_uInt16 nPageIndex,
774
            const PageKind ePageKind,
775
            const MapMode& rMapMode,
776
            const bool bPrintMarkedOnly,
777
            const OUString& rsPageString,
778
            const Point& rPageStringOffset,
779
            const DrawModeFlags nDrawMode,
780
            const Orientation eOrientation,
781
            const sal_uInt16 nPaperTray)
782
0
            : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString,
783
0
                rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
784
0
              mnPageIndex(nPageIndex)
785
0
        {
786
0
        }
787
788
        virtual void Print (
789
            Printer& rPrinter,
790
            SdDrawDocument& rDocument,
791
            ViewShell&,
792
            View* pView,
793
            DrawView& rPrintView,
794
            const SdrLayerIDSet& rVisibleLayers,
795
            const SdrLayerIDSet& rPrintableLayers) const override
796
0
        {
797
0
            SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
798
0
            rPrinter.SetMapMode(maMap);
799
0
            PrintPage(
800
0
                rPrinter,
801
0
                rPrintView,
802
0
                *pPageToPrint,
803
0
                pView,
804
0
                mbPrintMarkedOnly,
805
0
                rVisibleLayers,
806
0
                rPrintableLayers);
807
0
            PrintMessage(
808
0
                rPrinter,
809
0
                msPageString,
810
0
                maPageStringOffset);
811
0
        }
812
813
    private:
814
        const sal_uInt16 mnPageIndex;
815
    };
816
817
    /** The NotesPrinterPage is used for printing notes pages onto one or more printer pages
818
    */
819
    class NotesPrinterPage : public PrinterPage
820
    {
821
    public:
822
        NotesPrinterPage(
823
            const sal_uInt16 nPageIndex,
824
            const sal_Int32 nPageNumb,
825
            const sal_Int32 nPageCount,
826
            const bool bScaled,
827
            const PageKind ePageKind,
828
            const MapMode& rMapMode,
829
            const bool bPrintMarkedOnly,
830
            const OUString& rsPageString,
831
            const Point& rPageStringOffset,
832
            const DrawModeFlags nDrawMode,
833
            const Orientation eOrientation,
834
            const sal_uInt16 nPaperTray)
835
0
            : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString, rPageStringOffset,
836
0
                          nDrawMode, eOrientation, nPaperTray),
837
0
              mnPageIndex(nPageIndex),
838
0
              mnPageNumb(nPageNumb),
839
0
              mnPageCount(nPageCount),
840
0
              mbScaled(bScaled)
841
0
        {
842
0
        }
843
844
        virtual void Print(
845
            Printer& rPrinter,
846
            SdDrawDocument& rDocument,
847
            ViewShell&,
848
            View* pView,
849
            DrawView& rPrintView,
850
            const SdrLayerIDSet& rVisibleLayers,
851
            const SdrLayerIDSet& rPrintableLayers) const override
852
0
        {
853
0
            SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
854
0
            rPrinter.SetMapMode(maMap);
855
856
            // Clone the current page to create an independent instance for modifications.
857
            // This ensures that changes made to pNotesPage do not affect the original page.
858
0
            rtl::Reference<SdPage> pNotesPage
859
0
                = static_cast<SdPage*>(pPageToPrint->CloneSdrPage(rDocument).get());
860
861
0
            Size aPageSize;
862
0
            if (mbScaled)
863
0
            {
864
0
                aPageSize = pNotesPage->GetSize();
865
0
                lcl_AdjustPageSize(aPageSize, rPrinter.GetPrintPageSize());
866
0
            }
867
0
            else
868
0
                aPageSize = rPrinter.GetPrintPageSize();
869
870
            // Adjusts the objects on the notes page to fit the new page size.
871
0
            ::tools::Rectangle aNewBorderRect(-1, -1, -1, -1);
872
0
            pNotesPage->ScaleObjects(aPageSize, aNewBorderRect, true);
873
874
0
            SdrObject* pNotesObj = pNotesPage->GetPresObj(PresObjKind::Notes);
875
0
            if (pNotesObj)
876
0
            {
877
                // new page(s) margins
878
0
                sal_Int32 nLeft = aPageSize.Width() * 0.1;
879
0
                sal_Int32 nRight = nLeft;
880
0
                sal_Int32 nTop = aPageSize.Height() * 0.075;
881
0
                sal_Int32 nBottom = nTop;
882
883
0
                Point aNotesPt = pNotesObj->GetRelativePos();
884
0
                Size aNotesSize = pNotesObj->GetLogicRect().GetSize();
885
886
0
                Outliner* pOut = rDocument.GetInternalOutliner();
887
0
                const OutlinerMode nSaveOutlMode(pOut->GetOutlinerMode());
888
0
                const bool bSavedUpdateMode(pOut->IsUpdateLayout());
889
0
                pOut->SetPaperSize(aNotesSize);
890
0
                pOut->SetUpdateLayout(true);
891
0
                pOut->Clear();
892
0
                if (OutlinerParaObject* pOutlinerParaObject = pNotesObj->GetOutlinerParaObject())
893
0
                    pOut->SetText(*pOutlinerParaObject);
894
895
0
                bool bAutoGrow = pNotesObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
896
897
                // If AutoGrowHeight property is enabled and the notes page has a lower border,
898
                // use the lower border but if there is no lower border, use the bottom margin
899
                // to determine the first page break position.
900
                // If AutoGrow is not enabled, the notes object defines the first page break.
901
0
                ::tools::Long nNotesPageBottom
902
0
                    = bAutoGrow ? (pNotesPage->GetLowerBorder() != 0)
903
0
                                      ? aPageSize.Height() - pNotesPage->GetLowerBorder()
904
0
                                      : aPageSize.Height() - nBottom
905
0
                                : aNotesPt.Y() + aNotesSize.Height();
906
0
                if (mbScaled)
907
0
                {
908
0
                    sal_Int32 nTextHeight = aNotesPt.Y() + pOut->GetTextHeight();
909
0
                    if (bAutoGrow && (nTextHeight > nNotesPageBottom))
910
0
                    {
911
0
                        pNotesObj->SetMergedItem(SdrOnOffItem(SDRATTR_TEXT_AUTOGROWHEIGHT, false));
912
913
0
                        ::tools::Long nObjW = aNotesSize.Width();
914
0
                        ::tools::Long nObjH = aPageSize.Height() - aNotesPt.Y() - nBottom;
915
916
0
                        pNotesObj->SetLogicRect(::tools::Rectangle(aNotesPt, Size(nObjW, nObjH)));
917
0
                    }
918
0
                    SdrTextFitToSizeTypeItem eFitToSize = drawing::TextFitToSizeType_AUTOFIT;
919
0
                    pNotesObj->SetMergedItem(eFitToSize);
920
0
                }
921
0
                else // original size
922
0
                {
923
0
                    bool bExit = false;
924
0
                    sal_Int32 nPrevLineLen = 0;
925
0
                    sal_Int32 nPrevParaIdx = 0;
926
0
                    sal_uInt16 nActualPageNumb = 1;
927
0
                    sal_uInt16 nPrevParaLowerSpace = 0;
928
0
                    ::tools::Long nCurrentPosY = aNotesPt.Y();
929
0
                    sal_Int32 nParaCount = pOut->GetParagraphCount();
930
0
                    std::vector<std::pair<sal_Int32, sal_Int32>> aPageBreaks;
931
932
0
                    for (sal_Int32 i = 0; i < nParaCount && !bExit; ++i)
933
0
                    {
934
0
                        sal_Int32 nActualLineLen = 0;
935
0
                        sal_Int32 nLineCount = pOut->GetLineCount(i);
936
937
0
                        sal_uInt16 nLowerSpace = 0;
938
0
                        sal_uInt16 nUpperSpace = nPrevParaLowerSpace;
939
0
                        const SfxItemSet* pItemSet = &pOut->GetParaAttribs(i);
940
0
                        if(pItemSet->HasItem(EE_PARA_ULSPACE))
941
0
                        {
942
0
                            nLowerSpace = pItemSet->Get(EE_PARA_ULSPACE).GetLower();
943
0
                            nUpperSpace = (i != 0) ? pItemSet->Get(EE_PARA_ULSPACE).GetUpper() : 0;
944
0
                            if (nPrevParaLowerSpace > nUpperSpace)
945
0
                                nUpperSpace = nPrevParaLowerSpace;
946
0
                        }
947
948
0
                        for (sal_Int32 j = 0; j < nLineCount; ++j)
949
0
                        {
950
0
                            nActualLineLen += pOut->GetLineLen(i, j);
951
0
                            sal_Int32 nLineHeight = pOut->GetLineHeight(i, j);
952
953
0
                            if (nUpperSpace != 0 && (i > 0) && (j == 0))
954
0
                                nLineHeight += nUpperSpace;
955
956
0
                            sal_Int32 nNextPosY = nCurrentPosY + nLineHeight;
957
958
0
                            if (nNextPosY > nNotesPageBottom)
959
0
                            {
960
                                // If the current or the next page matches the print page
961
                                // calculate and add a page break, since we only want to add
962
                                // a page break if the page is relevant.
963
0
                                if (mnPageNumb == nActualPageNumb
964
0
                                    || mnPageNumb == nActualPageNumb + 1)
965
0
                                {
966
0
                                    if (!aPageBreaks.empty())
967
0
                                    {
968
                                        // determine the page break at the bottom of the page
969
                                        // for pages that have both a previous and a following page
970
0
                                        aPageBreaks.emplace_back(
971
0
                                            nPrevParaIdx - aPageBreaks[0].first, nPrevLineLen);
972
0
                                    }
973
0
                                    else
974
0
                                    {
975
0
                                        if (mnPageNumb == 1 || (nLineCount > 1 && j != 0))
976
0
                                        {
977
                                            // first page or multi-line paragraphs
978
0
                                            aPageBreaks.emplace_back(nPrevParaIdx, nPrevLineLen);
979
0
                                        }
980
0
                                        else
981
0
                                        {   // single-line paragraphs
982
0
                                            aPageBreaks.emplace_back(nPrevParaIdx + 1, 0);
983
0
                                        }
984
0
                                    }
985
986
0
                                    if (mnPageNumb == nActualPageNumb || mnPageNumb == mnPageCount)
987
0
                                    {
988
0
                                        bExit = true;
989
0
                                        break;
990
0
                                    }
991
0
                                }
992
993
0
                                if (nUpperSpace > 0)
994
0
                                    nLineHeight -= nUpperSpace;
995
996
0
                                nNotesPageBottom = aPageSize.Height() - nBottom;
997
0
                                nCurrentPosY = nTop;
998
0
                                nActualPageNumb++;
999
0
                                nActualLineLen = 0;
1000
0
                            }
1001
0
                            nPrevParaIdx = i;
1002
0
                            nPrevLineLen = nActualLineLen;
1003
0
                            nCurrentPosY += nLineHeight;
1004
0
                        }
1005
0
                        nPrevParaLowerSpace = nLowerSpace;
1006
0
                    }
1007
1008
0
                    if (!aPageBreaks.empty())
1009
0
                    {
1010
0
                        ESelection aE;
1011
0
                        if (mnPageNumb == 1)
1012
0
                        {
1013
0
                            aE.start.nPara = aPageBreaks[0].first;
1014
0
                            aE.start.nIndex = aPageBreaks[0].second;
1015
0
                            aE.end.nPara = pOut->GetParagraphCount() - 1;
1016
0
                            aE.end.nIndex = pOut->GetText(pOut->GetParagraph(aE.end.nPara)).getLength();
1017
0
                            pOut->QuickDelete(aE);
1018
0
                        }
1019
0
                        else
1020
0
                        {
1021
0
                            sal_Int16 nDepth = pOut->GetDepth(aPageBreaks[0].first);
1022
0
                            SfxItemSet aItemSet = pOut->GetParaAttribs(aPageBreaks[0].first);
1023
1024
0
                            aE.start.nPara = 0;
1025
0
                            aE.start.nIndex = 0;
1026
0
                            aE.end.nPara = aPageBreaks[0].first;
1027
0
                            aE.end.nIndex = aPageBreaks[0].second;
1028
0
                            pOut->QuickDelete(aE);
1029
1030
0
                            Paragraph* pFirstPara = pOut->GetParagraph(0);
1031
0
                            pOut->SetDepth(pFirstPara, nDepth);
1032
0
                            pOut->SetParaAttribs(0, aItemSet);
1033
1034
0
                            if (aPageBreaks.size() > 1)
1035
0
                            {
1036
0
                                aE.start.nPara = aPageBreaks[1].first;
1037
0
                                aE.start.nIndex = aPageBreaks[1].second;
1038
0
                                aE.end.nPara = pOut->GetParagraphCount() - 1;
1039
0
                                aE.end.nIndex = pOut->GetText(pOut->GetParagraph(aE.end.nPara)).getLength();
1040
0
                                pOut->QuickDelete(aE);
1041
0
                            }
1042
0
                        }
1043
0
                    }
1044
0
                    pNotesObj->SetOutlinerParaObject(pOut->CreateParaObject());
1045
1046
0
                    Size aObjSize;
1047
0
                    if (mnPageNumb != 1) // new page(s)
1048
0
                    {
1049
0
                        SdrObjListIter aShapeIter(pNotesPage.get());
1050
0
                        while (aShapeIter.IsMore())
1051
0
                        {
1052
0
                            SdrObject* pObj = aShapeIter.Next();
1053
0
                            if (pObj && pObj->GetObjIdentifier() != SdrObjKind::Text)
1054
0
                                pNotesPage->RemoveObject(pObj->GetOrdNum());
1055
0
                        }
1056
1057
0
                        aNotesPt.setX(nLeft);
1058
0
                        aNotesPt.setY(nTop);
1059
0
                        ::tools::Long nWidth = aPageSize.Width() - nLeft - nRight;
1060
0
                        aObjSize = Size(nWidth, pOut->GetTextHeight());
1061
0
                    }
1062
0
                    else // first page
1063
0
                    {
1064
0
                        if (!bAutoGrow)
1065
0
                            aObjSize = aNotesSize;
1066
0
                        else
1067
0
                            aObjSize = Size(aNotesSize.Width(), pOut->GetTextHeight());
1068
0
                    }
1069
0
                    pNotesObj->SetLogicRect(::tools::Rectangle(aNotesPt, aObjSize));
1070
0
                }
1071
0
                pOut->Clear();
1072
0
                pOut->SetUpdateLayout(bSavedUpdateMode);
1073
0
                pOut->Init(nSaveOutlMode);
1074
0
            }
1075
0
            pNotesPage->SetSize(aPageSize);
1076
1077
0
            PrintPage(
1078
0
                rPrinter,
1079
0
                rPrintView,
1080
0
                *pNotesPage,
1081
0
                pView,
1082
0
                mbPrintMarkedOnly,
1083
0
                rVisibleLayers,
1084
0
                rPrintableLayers);
1085
0
            PrintMessage(
1086
0
                rPrinter,
1087
0
                msPageString,
1088
0
                maPageStringOffset);
1089
0
        }
1090
1091
    private:
1092
        const sal_uInt16 mnPageIndex;
1093
        const sal_Int32 mnPageNumb;
1094
        const sal_Int32 mnPageCount;
1095
        const bool mbScaled;
1096
    };
1097
1098
    /** Print one slide multiple times on a printer page so that the whole
1099
        printer page is covered.
1100
    */
1101
    class TiledPrinterPage : public PrinterPage
1102
    {
1103
    public:
1104
        TiledPrinterPage (
1105
            const sal_uInt16 nPageIndex,
1106
            const PageKind ePageKind,
1107
            const bool bPrintMarkedOnly,
1108
            const OUString& rsPageString,
1109
            const Point& rPageStringOffset,
1110
            const DrawModeFlags nDrawMode,
1111
            const Orientation eOrientation,
1112
            const sal_uInt16 nPaperTray)
1113
0
            : PrinterPage(ePageKind, MapMode(), bPrintMarkedOnly, rsPageString,
1114
0
                rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
1115
0
              mnPageIndex(nPageIndex)
1116
0
        {
1117
0
        }
1118
1119
        virtual void Print (
1120
            Printer& rPrinter,
1121
            SdDrawDocument& rDocument,
1122
            ViewShell&,
1123
            View* pView,
1124
            DrawView& rPrintView,
1125
            const SdrLayerIDSet& rVisibleLayers,
1126
            const SdrLayerIDSet& rPrintableLayers) const override
1127
0
        {
1128
0
            SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
1129
0
            if (pPageToPrint==nullptr)
1130
0
                return;
1131
0
            MapMode aMap (rPrinter.GetMapMode());
1132
1133
0
            const Size aPageSize (pPageToPrint->GetSize());
1134
0
            const Size aPrintSize (rPrinter.GetOutputSize());
1135
1136
0
            const sal_Int32 nPageWidth (aPageSize.Width() + mnGap
1137
0
                - pPageToPrint->GetLeftBorder() - pPageToPrint->GetRightBorder());
1138
0
            const sal_Int32 nPageHeight (aPageSize.Height() + mnGap
1139
0
                - pPageToPrint->GetUpperBorder() - pPageToPrint->GetLowerBorder());
1140
0
            if (nPageWidth<=0 || nPageHeight<=0)
1141
0
                return;
1142
1143
            // Print at least two rows and columns.  More if the document
1144
            // page fits completely onto the printer page.
1145
0
            const sal_Int32 nColumnCount (std::max(sal_Int32(2),
1146
0
                    sal_Int32(aPrintSize.Width() / nPageWidth)));
1147
0
            const sal_Int32 nRowCount (std::max(sal_Int32(2),
1148
0
                    sal_Int32(aPrintSize.Height() / nPageHeight)));
1149
0
            for (sal_Int32 nRow=0; nRow<nRowCount; ++nRow)
1150
0
                for (sal_Int32 nColumn=0; nColumn<nColumnCount; ++nColumn)
1151
0
                {
1152
0
                    aMap.SetOrigin(Point(nColumn*nPageWidth,nRow*nPageHeight));
1153
0
                    rPrinter.SetMapMode(aMap);
1154
0
                    PrintPage(
1155
0
                        rPrinter,
1156
0
                        rPrintView,
1157
0
                        *pPageToPrint,
1158
0
                        pView,
1159
0
                        mbPrintMarkedOnly,
1160
0
                        rVisibleLayers,
1161
0
                        rPrintableLayers);
1162
0
                }
1163
1164
0
            PrintMessage(
1165
0
                rPrinter,
1166
0
                msPageString,
1167
0
                maPageStringOffset);
1168
0
        }
1169
1170
    private:
1171
        const sal_uInt16 mnPageIndex;
1172
        static const sal_Int32 mnGap = 500;
1173
    };
1174
1175
    /** Print two slides to one printer page so that the resulting pages
1176
        form a booklet.
1177
    */
1178
    class BookletPrinterPage : public PrinterPage
1179
    {
1180
    public:
1181
        BookletPrinterPage (
1182
            const sal_uInt16 nFirstPageIndex,
1183
            const sal_uInt16 nSecondPageIndex,
1184
            const Point& rFirstOffset,
1185
            const Point& rSecondOffset,
1186
            const PageKind ePageKind,
1187
            const MapMode& rMapMode,
1188
            const bool bPrintMarkedOnly,
1189
            const DrawModeFlags nDrawMode,
1190
            const Orientation eOrientation,
1191
            const sal_uInt16 nPaperTray)
1192
0
            : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, u""_ustr,
1193
0
                Point(), nDrawMode, eOrientation, nPaperTray),
1194
0
              mnFirstPageIndex(nFirstPageIndex),
1195
0
              mnSecondPageIndex(nSecondPageIndex),
1196
0
              maFirstOffset(rFirstOffset),
1197
0
              maSecondOffset(rSecondOffset)
1198
0
        {
1199
0
        }
1200
1201
        virtual void Print (
1202
            Printer& rPrinter,
1203
            SdDrawDocument& rDocument,
1204
            ViewShell&,
1205
            View* pView,
1206
            DrawView& rPrintView,
1207
            const SdrLayerIDSet& rVisibleLayers,
1208
            const SdrLayerIDSet& rPrintableLayers) const override
1209
0
        {
1210
0
            MapMode aMap (maMap);
1211
0
            SdPage* pPageToPrint = rDocument.GetSdPage(mnFirstPageIndex, mePageKind);
1212
0
            if (pPageToPrint)
1213
0
            {
1214
0
                aMap.SetOrigin(maFirstOffset);
1215
0
                rPrinter.SetMapMode(aMap);
1216
0
                PrintPage(
1217
0
                    rPrinter,
1218
0
                    rPrintView,
1219
0
                    *pPageToPrint,
1220
0
                    pView,
1221
0
                    mbPrintMarkedOnly,
1222
0
                    rVisibleLayers,
1223
0
                    rPrintableLayers);
1224
0
            }
1225
1226
0
            pPageToPrint = rDocument.GetSdPage(mnSecondPageIndex, mePageKind);
1227
0
            if( !pPageToPrint )
1228
0
                return;
1229
1230
0
            aMap.SetOrigin(maSecondOffset);
1231
0
            rPrinter.SetMapMode(aMap);
1232
0
            PrintPage(
1233
0
                rPrinter,
1234
0
                rPrintView,
1235
0
                *pPageToPrint,
1236
0
                pView,
1237
0
                mbPrintMarkedOnly,
1238
0
                rVisibleLayers,
1239
0
                rPrintableLayers);
1240
0
        }
1241
1242
    private:
1243
        const sal_uInt16 mnFirstPageIndex;
1244
        const sal_uInt16 mnSecondPageIndex;
1245
        const Point maFirstOffset;
1246
        const Point maSecondOffset;
1247
    };
1248
1249
    /** One handout page displays one to nine slides.
1250
    */
1251
    class HandoutPrinterPage : public PrinterPage
1252
    {
1253
    public:
1254
        HandoutPrinterPage (
1255
            const sal_uInt16 nHandoutPageIndex,
1256
            std::vector<sal_uInt16>&& rPageIndices,
1257
            const MapMode& rMapMode,
1258
            const OUString& rsPageString,
1259
            const Point& rPageStringOffset,
1260
            const DrawModeFlags nDrawMode,
1261
            const Orientation eOrientation,
1262
            const sal_uInt16 nPaperTray)
1263
0
            : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
1264
0
                rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
1265
0
              mnHandoutPageIndex(nHandoutPageIndex),
1266
0
              maPageIndices(std::move(rPageIndices))
1267
0
        {
1268
0
        }
1269
1270
        virtual void Print (
1271
            Printer& rPrinter,
1272
            SdDrawDocument& rDocument,
1273
            ViewShell& rViewShell,
1274
            View* pView,
1275
            DrawView& rPrintView,
1276
            const SdrLayerIDSet& rVisibleLayers,
1277
            const SdrLayerIDSet& rPrintableLayers) const override
1278
0
        {
1279
0
            SdPage& rHandoutPage (*rDocument.GetSdPage(0, PageKind::Handout));
1280
1281
0
            Size aPageSize(rHandoutPage.GetSize());
1282
0
            Size aPrintPageSize = rPrinter.GetPrintPageSize();
1283
1284
0
            if ((aPageSize.Width() < aPageSize.Height()
1285
0
                 && aPrintPageSize.Width() > aPrintPageSize.Height())
1286
0
                || (aPageSize.Width() > aPageSize.Height()
1287
0
                    && aPrintPageSize.Width() < aPrintPageSize.Height()))
1288
0
            {
1289
0
                ::tools::Long nTmp = aPageSize.Width();
1290
0
                aPageSize.setWidth(aPageSize.Height());
1291
0
                aPageSize.setHeight(nTmp);
1292
1293
0
                rHandoutPage.SetSize(aPageSize);
1294
0
            }
1295
1296
0
            Reference< css::beans::XPropertySet > xHandoutPage( rHandoutPage.getUnoPage(), UNO_QUERY );
1297
0
            static constexpr OUString sPageNumber( u"Number"_ustr );
1298
1299
            // Collect the page objects of the handout master.
1300
0
            std::vector<SdrPageObj*> aHandoutPageObjects;
1301
0
            SdrObjListIter aShapeIter (&rHandoutPage);
1302
0
            while (aShapeIter.IsMore())
1303
0
            {
1304
0
                SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
1305
0
                if (pPageObj)
1306
0
                    aHandoutPageObjects.push_back(pPageObj);
1307
0
            }
1308
0
            if (aHandoutPageObjects.empty())
1309
0
                return;
1310
1311
            // Connect page objects with pages.
1312
0
            std::vector<SdrPageObj*>::iterator aPageObjIter (aHandoutPageObjects.begin());
1313
0
            for (std::vector<sal_uInt16>::const_iterator
1314
0
                     iPageIndex(maPageIndices.begin()),
1315
0
                     iEnd(maPageIndices.end());
1316
0
                 iPageIndex!=iEnd && aPageObjIter!=aHandoutPageObjects.end();
1317
0
                 ++iPageIndex)
1318
0
            {
1319
                // Check if the page still exists.
1320
0
                if (*iPageIndex >= rDocument.GetSdPageCount(PageKind::Standard))
1321
0
                    continue;
1322
1323
0
                SdrPageObj* pPageObj = *aPageObjIter++;
1324
0
                pPageObj->SetReferencedPage(rDocument.GetSdPage(*iPageIndex, PageKind::Standard));
1325
0
            }
1326
1327
            // if there are more page objects than pages left, set the rest to invisible
1328
0
            int nHangoverCount = 0;
1329
0
            while (aPageObjIter != aHandoutPageObjects.end())
1330
0
            {
1331
0
                (*aPageObjIter++)->SetReferencedPage(nullptr);
1332
0
                nHangoverCount++;
1333
0
            }
1334
1335
            // Hide outlines for objects that have pages attached.
1336
0
            if (nHangoverCount > 0)
1337
0
            {
1338
0
                int nSkip = aHandoutPageObjects.size() - nHangoverCount;
1339
0
                aShapeIter.Reset();
1340
0
                while (aShapeIter.IsMore())
1341
0
                {
1342
0
                    SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
1343
0
                    if (pPathObj)
1344
0
                    {
1345
0
                        if (nSkip > 0)
1346
0
                            --nSkip;
1347
0
                        else
1348
0
                            pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
1349
0
                    }
1350
0
                }
1351
0
            }
1352
1353
0
            if( xHandoutPage.is() ) try
1354
0
            {
1355
0
                xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(mnHandoutPageIndex) ) );
1356
0
            }
1357
0
            catch( Exception& )
1358
0
            {
1359
0
            }
1360
0
            rViewShell.SetPrintedHandoutPageNum( mnHandoutPageIndex + 1 );
1361
1362
0
            rPrinter.SetMapMode(maMap);
1363
1364
0
            PrintPage(
1365
0
                rPrinter,
1366
0
                rPrintView,
1367
0
                rHandoutPage,
1368
0
                pView,
1369
0
                false,
1370
0
                rVisibleLayers,
1371
0
                rPrintableLayers);
1372
0
            PrintMessage(
1373
0
                rPrinter,
1374
0
                msPageString,
1375
0
                maPageStringOffset);
1376
1377
0
            if( xHandoutPage.is() ) try
1378
0
            {
1379
0
                xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(0) ) );
1380
0
            }
1381
0
            catch( Exception& )
1382
0
            {
1383
0
            }
1384
0
            rViewShell.SetPrintedHandoutPageNum(1);
1385
1386
            // Restore outlines.
1387
0
            if (nHangoverCount > 0)
1388
0
            {
1389
0
                aShapeIter.Reset();
1390
0
                while (aShapeIter.IsMore())
1391
0
                {
1392
0
                    SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
1393
0
                    if (pPathObj != nullptr)
1394
0
                        pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
1395
0
                }
1396
0
            }
1397
1398
0
       }
1399
1400
    private:
1401
        const sal_uInt16 mnHandoutPageIndex;
1402
        const std::vector<sal_uInt16> maPageIndices;
1403
    };
1404
1405
    /** The outline information (title, subtitle, outline objects) of the
1406
        document.  There is no fixed mapping of slides to printer pages.
1407
    */
1408
    class OutlinerPrinterPage : public PrinterPage
1409
    {
1410
    public:
1411
        OutlinerPrinterPage (
1412
            std::optional<OutlinerParaObject> pParaObject,
1413
            const MapMode& rMapMode,
1414
            const OUString& rsPageString,
1415
            const Point& rPageStringOffset,
1416
            const DrawModeFlags nDrawMode,
1417
            const Orientation eOrientation,
1418
            const sal_uInt16 nPaperTray)
1419
0
            : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
1420
0
                rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
1421
0
              mpParaObject(std::move(pParaObject))
1422
0
        {
1423
0
        }
1424
1425
        virtual void Print (
1426
            Printer& rPrinter,
1427
            SdDrawDocument& rDocument,
1428
            ViewShell&,
1429
            View*,
1430
            DrawView&,
1431
            const SdrLayerIDSet&,
1432
            const SdrLayerIDSet&) const override
1433
0
        {
1434
            // Set up the printer.
1435
0
            rPrinter.SetMapMode(maMap);
1436
1437
            // Get and set up the outliner.
1438
0
            const ::tools::Rectangle aOutRect (rPrinter.GetPageOffset(), rPrinter.GetOutputSize());
1439
0
            Outliner* pOutliner = rDocument.GetInternalOutliner();
1440
0
            const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
1441
0
            const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
1442
0
            const Size aSavedPaperSize (pOutliner->GetPaperSize());
1443
1444
0
            pOutliner->Init(OutlinerMode::OutlineView);
1445
0
            pOutliner->SetPaperSize(aOutRect.GetSize());
1446
0
            pOutliner->SetUpdateLayout(true);
1447
0
            pOutliner->Clear();
1448
0
            pOutliner->SetText(*mpParaObject);
1449
1450
0
            pOutliner->DrawText_ToRectangle(rPrinter, aOutRect);
1451
1452
0
            PrintMessage(
1453
0
                rPrinter,
1454
0
                msPageString,
1455
0
                maPageStringOffset);
1456
1457
            // Restore outliner and printer.
1458
0
            pOutliner->Clear();
1459
0
            pOutliner->SetUpdateLayout(bSavedUpdateMode);
1460
0
            pOutliner->SetPaperSize(aSavedPaperSize);
1461
0
            pOutliner->Init(nSavedOutlMode);
1462
0
        }
1463
1464
    private:
1465
        std::optional<OutlinerParaObject> mpParaObject;
1466
    };
1467
}
1468
1469
//===== DocumentRenderer::Implementation ======================================
1470
1471
class DocumentRenderer::Implementation
1472
    : public SfxListener,
1473
      public vcl::PrinterOptionsHelper
1474
{
1475
public:
1476
    explicit Implementation (ViewShellBase& rBase)
1477
0
        : mxObjectShell(rBase.GetDocShell())
1478
0
        , mrBase(rBase)
1479
0
        , mbIsDisposed(false)
1480
0
        , mpPrinter(nullptr)
1481
0
        , mbHasOrientationWarningBeenShown(false)
1482
0
    {
1483
0
        DialogCreator aCreator( mrBase, mrBase.GetDocShell()->GetDocumentType() == DocumentType::Impress, GetCurrentPageIndex() );
1484
0
        m_aUIProperties = aCreator.GetDialogControls();
1485
0
        maSlidesPerPage = aCreator.GetSlidesPerPage();
1486
1487
0
        StartListening(mrBase);
1488
0
    }
1489
1490
    virtual ~Implementation() override
1491
0
    {
1492
0
        EndListening(mrBase);
1493
0
    }
1494
1495
    virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override
1496
0
    {
1497
0
        if (&rBroadcaster != &static_cast<SfxBroadcaster&>(mrBase))
1498
0
            return;
1499
1500
0
        if (rHint.GetId() == SfxHintId::Dying)
1501
0
        {
1502
0
            mbIsDisposed = true;
1503
0
        }
1504
0
    }
1505
1506
    /** Process the sequence of properties given to one of the XRenderable
1507
        methods.
1508
    */
1509
    void ProcessProperties (const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
1510
0
    {
1511
0
        OSL_ASSERT(!mbIsDisposed);
1512
0
        if (mbIsDisposed)
1513
0
            return;
1514
1515
0
        bool bIsValueChanged = processProperties( rOptions );
1516
0
        bool bIsPaperChanged = false;
1517
1518
        // The RenderDevice property is handled specially: its value is
1519
        // stored in mpPrinter instead of being retrieved on demand.
1520
0
        Any aDev( getValue( u"RenderDevice"_ustr ) );
1521
0
        Reference<awt::XDevice> xRenderDevice;
1522
1523
0
        if (aDev >>= xRenderDevice)
1524
0
        {
1525
0
            VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>(xRenderDevice.get());
1526
0
            VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice()
1527
0
                                                  : VclPtr< OutputDevice >();
1528
0
            mpPrinter = dynamic_cast<Printer*>(pOut.get());
1529
0
            Size aPageSizePixel = mpPrinter ? mpPrinter->GetPaperSizePixel() : Size();
1530
0
            Size aPrintPageSize = mpPrinter ? mpPrinter->GetPrintPageSize() : Size();
1531
1532
0
            lcl_AdjustPageSize(aPageSizePixel, aPrintPageSize);
1533
1534
0
            if (aPageSizePixel != maPrinterPageSizePixel)
1535
0
            {
1536
0
                bIsPaperChanged = true;
1537
0
                maPrinterPageSizePixel = aPageSizePixel;
1538
0
            }
1539
0
        }
1540
1541
0
        if (bIsValueChanged && ! mpOptions )
1542
0
            mpOptions.reset(new PrintOptions(*this, std::vector(maSlidesPerPage)));
1543
0
        if( bIsValueChanged || bIsPaperChanged )
1544
0
            PreparePages();
1545
0
    }
1546
1547
    /** Return the number of pages that are to be printed.
1548
    */
1549
    sal_Int32 GetPrintPageCount() const
1550
0
    {
1551
0
        OSL_ASSERT(!mbIsDisposed);
1552
0
        if (mbIsDisposed)
1553
0
            return 0;
1554
0
        else
1555
0
            return maPrinterPages.size();
1556
0
    }
1557
1558
    /** Return a sequence of properties that can be returned by the
1559
        XRenderable::getRenderer() method.
1560
    */
1561
    css::uno::Sequence<css::beans::PropertyValue> GetProperties () const
1562
0
    {
1563
0
        css::uno::Sequence<css::beans::PropertyValue> aProperties{
1564
0
            comphelper::makePropertyValue(u"ExtraPrintUIOptions"_ustr,
1565
0
                                          comphelper::containerToSequence(m_aUIProperties)),
1566
0
            comphelper::makePropertyValue(u"PageSize"_ustr, maPrintSize),
1567
            // FIXME: is this always true ?
1568
0
            comphelper::makePropertyValue(u"PageIncludesNonprintableArea"_ustr, true)
1569
0
        };
1570
1571
0
        return aProperties;
1572
0
    }
1573
1574
    /** Print one of the prepared pages.
1575
    */
1576
    void PrintPage (const sal_Int32 nIndex)
1577
0
    {
1578
0
        OSL_ASSERT(!mbIsDisposed);
1579
0
        if (mbIsDisposed)
1580
0
            return;
1581
1582
0
        Printer& rPrinter (*mpPrinter);
1583
1584
0
        std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
1585
0
        if ( ! pViewShell)
1586
0
            return;
1587
1588
0
        SdDrawDocument* pDocument = pViewShell->GetDoc();
1589
0
        assert(pDocument!=nullptr);
1590
1591
0
        std::shared_ptr<DrawViewShell> pDrawViewShell(
1592
0
            std::dynamic_pointer_cast<DrawViewShell>(pViewShell));
1593
1594
0
        if (!mpPrintView)
1595
0
            mpPrintView.reset(new DrawView(mrBase.GetDocShell(), &rPrinter, nullptr));
1596
1597
0
        if (nIndex<0 || sal::static_int_cast<sal_uInt32>(nIndex)>=maPrinterPages.size())
1598
0
            return;
1599
1600
0
        const std::shared_ptr<PrinterPage> pPage (maPrinterPages[nIndex]);
1601
0
        OSL_ASSERT(pPage);
1602
0
        if ( ! pPage)
1603
0
            return;
1604
1605
0
        const Orientation eSavedOrientation (rPrinter.GetOrientation());
1606
0
        const DrawModeFlags nSavedDrawMode (rPrinter.GetDrawMode());
1607
0
        const MapMode aSavedMapMode (rPrinter.GetMapMode());
1608
0
        const sal_uInt16 nSavedPaperBin (rPrinter.GetPaperBin());
1609
1610
        // Set page orientation.
1611
0
        if ( ! rPrinter.SetOrientation(pPage->GetOrientation()))
1612
0
        {
1613
0
            if ( ! mbHasOrientationWarningBeenShown
1614
0
                && mpOptions->IsWarningOrientation())
1615
0
            {
1616
0
                mbHasOrientationWarningBeenShown = true;
1617
                // Show warning that the orientation could not be set.
1618
0
                std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(
1619
0
                    pViewShell->GetFrameWeld(), VclMessageType::Warning, VclButtonsType::OkCancel,
1620
0
                    SdResId(STR_WARN_PRINTFORMAT_FAILURE)));
1621
0
                xWarn->set_default_response(RET_CANCEL);
1622
0
                if (xWarn->run() != RET_OK)
1623
0
                    return;
1624
0
            }
1625
0
        }
1626
1627
        // Set the draw mode.
1628
0
        rPrinter.SetDrawMode(pPage->GetDrawMode());
1629
1630
        // Set paper tray.
1631
0
        rPrinter.SetPaperBin(pPage->GetPaperTray());
1632
1633
        // Print the actual page.
1634
0
        pPage->Print(
1635
0
            rPrinter,
1636
0
            *pDocument,
1637
0
            *pViewShell,
1638
0
            pDrawViewShell ? pDrawViewShell->GetView() : nullptr,
1639
0
            *mpPrintView,
1640
0
            pViewShell->GetFrameView()->GetVisibleLayers(),
1641
0
            pViewShell->GetFrameView()->GetPrintableLayers());
1642
1643
0
        rPrinter.SetOrientation(eSavedOrientation);
1644
0
        rPrinter.SetDrawMode(nSavedDrawMode);
1645
0
        rPrinter.SetMapMode(aSavedMapMode);
1646
0
        rPrinter.SetPaperBin(nSavedPaperBin);
1647
0
    }
1648
1649
private:
1650
    // rhbz#657394: keep the document alive: prevents crash when
1651
    SfxObjectShellRef mxObjectShell; // destroying mpPrintView
1652
    ViewShellBase& mrBase;
1653
    bool mbIsDisposed;
1654
    VclPtr<Printer> mpPrinter;
1655
    Size maPrinterPageSizePixel;
1656
    std::unique_ptr<PrintOptions> mpOptions;
1657
    std::vector< std::shared_ptr< ::sd::PrinterPage> > maPrinterPages;
1658
    std::unique_ptr<DrawView> mpPrintView;
1659
    bool mbHasOrientationWarningBeenShown;
1660
    std::vector<sal_Int32> maSlidesPerPage;
1661
    awt::Size maPrintSize;
1662
1663
    sal_Int32 GetCurrentPageIndex() const
1664
0
    {
1665
0
        const ViewShell *pShell = mrBase.GetMainViewShell().get();
1666
0
        const SdPage *pCurrentPage = pShell ? pShell->getCurrentPage() : nullptr;
1667
0
        return pCurrentPage ? (pCurrentPage->GetPageNum()-1)/2 : -1;
1668
0
    }
1669
1670
    /** Determine and set the paper orientation.
1671
    */
1672
    void SetupPaperOrientation (
1673
        const PageKind ePageKind,
1674
        PrintInfo& rInfo)
1675
0
    {
1676
0
        SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
1677
0
        rInfo.meOrientation = Orientation::Portrait;
1678
1679
0
        if( ! mpOptions->IsBooklet())
1680
0
        {
1681
0
            rInfo.meOrientation = pDocument->GetSdPage(0, ePageKind)->GetOrientation();
1682
0
        }
1683
0
        else if (rInfo.maPageSize.Width() < rInfo.maPageSize.Height())
1684
0
            rInfo.meOrientation = Orientation::Landscape;
1685
1686
        // Draw and Notes should usually abide by their specified paper size
1687
0
        Size aPaperSize;
1688
0
        if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
1689
0
        {
1690
0
            aPaperSize.setWidth(rInfo.maPageSize.Width());
1691
0
            aPaperSize.setHeight(rInfo.maPageSize.Height());
1692
0
        }
1693
0
        else
1694
0
        {
1695
0
            aPaperSize.setWidth(rInfo.mpPrinter->GetPaperSize().Width());
1696
0
            aPaperSize.setHeight(rInfo.mpPrinter->GetPaperSize().Height());
1697
1698
0
            if (!mpOptions->IsBooklet())
1699
0
                lcl_AdjustPageSize(aPaperSize, rInfo.mpPrinter->GetPrintPageSize());
1700
0
        }
1701
1702
0
        maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
1703
1704
0
        if (mpOptions->IsPrinterPreferred(pDocument->GetDocumentType())
1705
0
            && ePageKind == PageKind::Standard && !mpOptions->IsBooklet())
1706
0
        {
1707
0
            if( (rInfo.meOrientation == Orientation::Landscape &&
1708
0
                  (aPaperSize.Width() < aPaperSize.Height()))
1709
0
               ||
1710
0
                (rInfo.meOrientation == Orientation::Portrait &&
1711
0
                  (aPaperSize.Width() > aPaperSize.Height()))
1712
0
              )
1713
0
            {
1714
0
                maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
1715
0
            }
1716
0
        }
1717
0
    }
1718
1719
    /** Top most method for preparing printer pages.  In this and the other
1720
        Prepare... methods the various special cases are detected and
1721
        handled.
1722
        For every page that is to be printed (that may contain several
1723
        slides) one PrinterPage object is created and inserted into
1724
        maPrinterPages.
1725
    */
1726
    void PreparePages()
1727
0
    {
1728
0
        mpPrintView.reset();
1729
0
        maPrinterPages.clear();
1730
0
        mbHasOrientationWarningBeenShown = false;
1731
1732
0
        ViewShell* pShell = mrBase.GetMainViewShell().get();
1733
1734
0
        PrintInfo aInfo (mpPrinter, mpOptions->IsPrintMarkedOnly());
1735
1736
0
        if (aInfo.mpPrinter==nullptr || pShell==nullptr)
1737
0
            return;
1738
1739
0
        MapMode aMap (aInfo.mpPrinter->GetMapMode());
1740
0
        aMap.SetMapUnit(MapUnit::Map100thMM);
1741
0
        aInfo.maMap = aMap;
1742
0
        mpPrinter->SetMapMode(aMap);
1743
1744
0
        ::Outliner& rOutliner = mrBase.GetDocument()->GetDrawOutliner();
1745
0
        const EEControlBits nSavedControlWord (rOutliner.GetControlWord());
1746
0
        EEControlBits nCntrl = nSavedControlWord;
1747
0
        nCntrl &= ~EEControlBits::MARKFIELDS;
1748
0
        nCntrl &= ~EEControlBits::ONLINESPELLING;
1749
0
        rOutliner.SetControlWord( nCntrl );
1750
1751
        // When in outline view then apply all pending changes to the model.
1752
0
        if( auto pOutlineViewShell = dynamic_cast< OutlineViewShell *>( pShell ) )
1753
0
            pOutlineViewShell->PrepareClose (false);
1754
1755
        // Collect some frequently used data.
1756
0
        if (mpOptions->IsDate())
1757
0
        {
1758
0
            aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getDate( Date( Date::SYSTEM ) );
1759
0
            aInfo.msTimeDate += " ";
1760
0
        }
1761
1762
0
        if (mpOptions->IsTime())
1763
0
            aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getTime( ::tools::Time( ::tools::Time::SYSTEM ), false );
1764
1765
        // Draw and Notes should usually use specified paper size when printing
1766
0
        if (!mpOptions->IsPrinterPreferred(mrBase.GetDocShell()->GetDocumentType()))
1767
0
        {
1768
0
            aInfo.maPrintSize = mrBase.GetDocument()->GetSdPage(0, PageKind::Standard)->GetSize();
1769
0
            maPrintSize = awt::Size(aInfo.maPrintSize.Width(),
1770
0
                                    aInfo.maPrintSize.Height());
1771
0
        }
1772
0
        else
1773
0
        {
1774
0
            aInfo.maPrintSize = aInfo.mpPrinter->GetOutputSize();
1775
0
            maPrintSize = awt::Size(
1776
0
                aInfo.mpPrinter->GetPaperSize().Width(),
1777
0
                aInfo.mpPrinter->GetPaperSize().Height());
1778
0
        }
1779
1780
0
        switch (mpOptions->GetOutputQuality())
1781
0
        {
1782
0
            case 1: // Grayscale
1783
0
                aInfo.mnDrawMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill
1784
0
                    | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap
1785
0
                    | DrawModeFlags::GrayGradient;
1786
0
                break;
1787
1788
0
            case 2: // Black & White
1789
0
                aInfo.mnDrawMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill
1790
0
                    | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap
1791
0
                    | DrawModeFlags::WhiteGradient;
1792
0
                break;
1793
1794
0
            default:
1795
0
                aInfo.mnDrawMode = DrawModeFlags::Default;
1796
0
        }
1797
1798
0
        if (mpOptions->IsDraw())
1799
0
            PrepareStdOrNotes(PageKind::Standard, aInfo);
1800
0
        if (mpOptions->IsNotes())
1801
0
            PrepareStdOrNotes(PageKind::Notes, aInfo);
1802
0
        if (mpOptions->IsHandout())
1803
0
        {
1804
0
            InitHandoutTemplate();
1805
0
            PrepareHandout(aInfo);
1806
0
        }
1807
0
        if (mpOptions->IsOutline())
1808
0
            PrepareOutline(aInfo);
1809
1810
0
        rOutliner.SetControlWord(nSavedControlWord);
1811
0
    }
1812
1813
    /** Create the page objects of the handout template.  When the actual
1814
        printing takes place then the page objects are assigned different
1815
        sets of slides for each printed page (see HandoutPrinterPage::Print).
1816
    */
1817
    void InitHandoutTemplate()
1818
0
    {
1819
0
        const sal_Int32 nSlidesPerHandout (mpOptions->GetHandoutPageCount());
1820
0
        const bool bHandoutHorizontal (mpOptions->IsHandoutHorizontal());
1821
1822
0
        AutoLayout eLayout = AUTOLAYOUT_HANDOUT6;
1823
0
        switch (nSlidesPerHandout)
1824
0
        {
1825
0
            case 0: eLayout = AUTOLAYOUT_NONE; break; // AUTOLAYOUT_HANDOUT1; break;
1826
0
            case 1: eLayout = AUTOLAYOUT_HANDOUT1; break;
1827
0
            case 2: eLayout = AUTOLAYOUT_HANDOUT2; break;
1828
0
            case 3: eLayout = AUTOLAYOUT_HANDOUT3; break;
1829
0
            case 4: eLayout = AUTOLAYOUT_HANDOUT4; break;
1830
0
            default:
1831
0
            case 6: eLayout = AUTOLAYOUT_HANDOUT6; break;
1832
0
            case 9: eLayout = AUTOLAYOUT_HANDOUT9; break;
1833
0
        }
1834
1835
0
        if( !mrBase.GetDocument() )
1836
0
            return;
1837
1838
0
        SdDrawDocument& rModel = *mrBase.GetDocument();
1839
1840
        // first, prepare handout page (not handout master)
1841
1842
0
        SdPage* pHandout = rModel.GetSdPage(0, PageKind::Handout);
1843
0
        if( !pHandout )
1844
0
            return;
1845
1846
        // delete all previous shapes from handout page
1847
0
        while( pHandout->GetObjCount() )
1848
0
            pHandout->NbcRemoveObject(0);
1849
1850
0
        const bool bDrawLines (eLayout == AUTOLAYOUT_HANDOUT3);
1851
1852
0
        Size aHandoutPageSize = pHandout->GetSize();
1853
0
        lcl_AdjustPageSize(aHandoutPageSize, mpPrinter->GetPrintPageSize());
1854
0
        Orientation eOrient = aHandoutPageSize.Width() > aHandoutPageSize.Height()
1855
0
                                  ? Orientation::Landscape
1856
0
                                  : Orientation::Portrait;
1857
1858
0
        std::vector< ::tools::Rectangle > aAreas;
1859
0
        SdPage::CalculateHandoutAreas( rModel, eLayout, bHandoutHorizontal, aAreas, eOrient );
1860
1861
0
        std::vector< ::tools::Rectangle >::iterator iter( aAreas.begin() );
1862
0
        while( iter != aAreas.end() )
1863
0
        {
1864
0
            pHandout->NbcInsertObject(
1865
0
                new SdrPageObj(
1866
0
                    rModel,
1867
0
                    (*iter++)));
1868
1869
0
            if( bDrawLines && (iter != aAreas.end())  )
1870
0
            {
1871
0
                ::tools::Rectangle aRect( *iter++ );
1872
1873
0
                basegfx::B2DPolygon aPoly;
1874
0
                aPoly.insert(0, basegfx::B2DPoint( aRect.Left(), aRect.Top() ) );
1875
0
                aPoly.insert(1, basegfx::B2DPoint( aRect.Right(), aRect.Top() ) );
1876
1877
0
                basegfx::B2DHomMatrix aMatrix;
1878
0
                aMatrix.translate( 0.0, static_cast< double >( aRect.GetHeight() / 7 ) );
1879
1880
0
                basegfx::B2DPolyPolygon aPathPoly;
1881
0
                for( sal_uInt16 nLine = 0; nLine < 7; nLine++ )
1882
0
                {
1883
0
                    aPoly.transform( aMatrix );
1884
0
                    aPathPoly.append( aPoly );
1885
0
                }
1886
1887
0
                rtl::Reference<SdrPathObj> pPathObj = new SdrPathObj(
1888
0
                    rModel,
1889
0
                    SdrObjKind::PathLine,
1890
0
                    std::move(aPathPoly));
1891
0
                pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
1892
0
                pPathObj->SetMergedItem(XLineColorItem(OUString(), COL_BLACK));
1893
1894
0
                pHandout->NbcInsertObject( pPathObj.get() );
1895
0
            }
1896
0
        }
1897
0
    }
1898
1899
    /** Detect whether the specified slide is to be printed.
1900
        @return
1901
            When the slide is not to be printed then <NULL/> is returned.
1902
            Otherwise a pointer to the slide is returned.
1903
    */
1904
    SdPage* GetFilteredPage (
1905
        const sal_Int32 nPageIndex,
1906
        const PageKind ePageKind) const
1907
0
    {
1908
0
        OSL_ASSERT(mrBase.GetDocument() != nullptr);
1909
0
        OSL_ASSERT(nPageIndex>=0);
1910
0
        SdPage* pPage = mrBase.GetDocument()->GetSdPage(
1911
0
            sal::static_int_cast<sal_uInt16>(nPageIndex),
1912
0
            ePageKind);
1913
0
        if (pPage == nullptr)
1914
0
            return nullptr;
1915
0
        if ( ! pPage->IsExcluded() || mpOptions->IsPrintExcluded())
1916
0
            return pPage;
1917
0
        else
1918
0
            return nullptr;
1919
0
    }
1920
1921
    /** Prepare the outline of the document for printing.  There is no fixed
1922
        number of slides whose outline data is put onto one printer page.
1923
        If the current printer page has enough room for the outline of the
1924
        current slide then that is added.  Otherwise a new printer page is
1925
        started.
1926
    */
1927
    void PrepareOutline (PrintInfo const & rInfo)
1928
0
    {
1929
0
        MapMode aMap (rInfo.maMap);
1930
0
        Point aPageOfs (rInfo.mpPrinter->GetPageOffset() );
1931
0
        aMap.SetScaleX(Fraction(1,2));
1932
0
        aMap.SetScaleY(Fraction(1,2));
1933
0
        mpPrinter->SetMapMode(aMap);
1934
1935
0
        ::tools::Rectangle aOutRect(aPageOfs, rInfo.mpPrinter->GetOutputSize());
1936
0
        if( aOutRect.GetWidth() > aOutRect.GetHeight() )
1937
0
        {
1938
0
            Size aPaperSize( rInfo.mpPrinter->PixelToLogic( rInfo.mpPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) );
1939
0
            maPrintSize.Width  = aPaperSize.Height();
1940
0
            maPrintSize.Height = aPaperSize.Width();
1941
0
            const auto nRotatedWidth = aOutRect.GetHeight();
1942
0
            const auto nRotatedHeight = aOutRect.GetWidth();
1943
0
            const auto nRotatedX = aPageOfs.Y();
1944
0
            const auto nRotatedY = aPageOfs.X();
1945
0
            aOutRect = ::tools::Rectangle(Point( nRotatedX, nRotatedY),
1946
0
                                  Size(nRotatedWidth, nRotatedHeight));
1947
0
        }
1948
1949
0
        Outliner* pOutliner = mrBase.GetDocument()->GetInternalOutliner();
1950
0
        pOutliner->Init(OutlinerMode::OutlineView);
1951
0
        const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
1952
0
        const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
1953
0
        const Size aSavedPaperSize (pOutliner->GetPaperSize());
1954
0
        const MapMode aSavedMapMode (pOutliner->GetRefMapMode());
1955
0
        pOutliner->SetPaperSize(aOutRect.GetSize());
1956
0
        pOutliner->SetUpdateLayout(true);
1957
1958
0
        ::tools::Long nPageH = aOutRect.GetHeight();
1959
1960
0
        std::vector< sal_Int32 > aPages;
1961
0
        sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
1962
0
        StringRangeEnumerator::getRangesFromString(
1963
0
            mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
1964
0
            aPages, 0, nPageCount-1);
1965
1966
0
        for (size_t nIndex = 0, nCount = aPages.size(); nIndex < nCount;)
1967
0
        {
1968
0
            pOutliner->Clear();
1969
1970
0
            Paragraph* pPara = nullptr;
1971
0
            ::tools::Long nH (0);
1972
0
            while (nH < nPageH && nIndex<nCount)
1973
0
            {
1974
0
                SdPage* pPage = GetFilteredPage(aPages[nIndex], PageKind::Standard);
1975
0
                ++nIndex;
1976
0
                if (pPage == nullptr)
1977
0
                    continue;
1978
1979
0
                SdrTextObj* pTextObj = nullptr;
1980
1981
0
                for (const rtl::Reference<SdrObject>& pObj : *pPage)
1982
0
                {
1983
0
                    if (pObj->GetObjInventor() == SdrInventor::Default
1984
0
                        && pObj->GetObjIdentifier() == SdrObjKind::TitleText)
1985
0
                    {
1986
0
                        pTextObj = DynCastSdrTextObj(pObj.get());
1987
0
                        if (pTextObj)
1988
0
                            break;
1989
0
                    }
1990
0
                }
1991
1992
0
                pPara = pOutliner->GetParagraph(pOutliner->GetParagraphCount() - 1);
1993
1994
0
                if (pTextObj!=nullptr
1995
0
                    && !pTextObj->IsEmptyPresObj()
1996
0
                    && pTextObj->GetOutlinerParaObject())
1997
0
                {
1998
0
                    pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
1999
0
                }
2000
0
                else
2001
0
                    pOutliner->Insert(OUString());
2002
2003
0
                pTextObj = nullptr;
2004
2005
0
                for (const rtl::Reference<SdrObject>& pObj : *pPage)
2006
0
                {
2007
0
                    if (pObj->GetObjInventor() == SdrInventor::Default
2008
0
                        && pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
2009
0
                    {
2010
0
                        pTextObj = DynCastSdrTextObj(pObj.get());
2011
0
                        if (pTextObj)
2012
0
                            break;
2013
0
                    }
2014
0
                }
2015
2016
0
                bool bSubTitle (false);
2017
0
                if (!pTextObj)
2018
0
                {
2019
0
                    bSubTitle = true;
2020
0
                    pTextObj = DynCastSdrTextObj(pPage->GetPresObj(PresObjKind::Text));  // is there a subtitle?
2021
0
                }
2022
2023
0
                sal_Int32 nParaCount1 = pOutliner->GetParagraphCount();
2024
2025
0
                if (pTextObj!=nullptr
2026
0
                    && !pTextObj->IsEmptyPresObj()
2027
0
                    && pTextObj->GetOutlinerParaObject())
2028
0
                {
2029
0
                    pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
2030
0
                }
2031
2032
0
                if (bSubTitle )
2033
0
                {
2034
0
                    const sal_Int32 nParaCount2 (pOutliner->GetParagraphCount());
2035
0
                    for (sal_Int32 nPara=nParaCount1; nPara<nParaCount2; ++nPara)
2036
0
                    {
2037
0
                        Paragraph* pP = pOutliner->GetParagraph(nPara);
2038
0
                        if (pP!=nullptr && pOutliner->GetDepth(nPara) > 0)
2039
0
                            pOutliner->SetDepth(pP, 0);
2040
0
                    }
2041
0
                }
2042
2043
0
                nH = pOutliner->GetTextHeight();
2044
0
            }
2045
2046
            // Remove the last paragraph when that does not fit completely on
2047
            // the current page.
2048
0
            if (nH > nPageH && pPara!=nullptr)
2049
0
            {
2050
0
                sal_Int32 nCnt = pOutliner->GetAbsPos(
2051
0
                    pOutliner->GetParagraph( pOutliner->GetParagraphCount() - 1 ) );
2052
0
                sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara );
2053
0
                nCnt -= nParaPos;
2054
0
                pPara = pOutliner->GetParagraph( ++nParaPos );
2055
0
                if ( nCnt && pPara )
2056
0
                {
2057
0
                    pOutliner->Remove(pPara, nCnt);
2058
0
                    --nIndex;
2059
0
                }
2060
0
            }
2061
2062
0
            if ( CheckForFrontBackPages( nIndex ) )
2063
0
            {
2064
0
                maPrinterPages.push_back(
2065
0
                    std::make_shared<OutlinerPrinterPage>(
2066
0
                        pOutliner->CreateParaObject(),
2067
0
                        aMap,
2068
0
                        rInfo.msTimeDate,
2069
0
                        aPageOfs,
2070
0
                        rInfo.mnDrawMode,
2071
0
                        rInfo.meOrientation,
2072
0
                        rInfo.mpPrinter->GetPaperBin()));
2073
0
            }
2074
0
        }
2075
2076
0
        pOutliner->SetRefMapMode(aSavedMapMode);
2077
0
        pOutliner->SetUpdateLayout(bSavedUpdateMode);
2078
0
        pOutliner->SetPaperSize(aSavedPaperSize);
2079
0
        pOutliner->Init(nSavedOutlMode);
2080
0
    }
2081
2082
    /** Prepare handout pages for slides that are to be printed.
2083
    */
2084
    void PrepareHandout (PrintInfo& rInfo)
2085
0
    {
2086
0
        SdDrawDocument* pDocument = mrBase.GetDocument();
2087
0
        assert(pDocument != nullptr);
2088
0
        SdPage& rHandoutPage (*pDocument->GetSdPage(0, PageKind::Handout));
2089
2090
0
        const bool bScalePage (mpOptions->IsPageSize());
2091
2092
0
        sal_uInt16 nPaperBin;
2093
0
        if ( ! mpOptions->IsPaperBin())
2094
0
            nPaperBin = rHandoutPage.GetPaperBin();
2095
0
        else
2096
0
            nPaperBin = rInfo.mpPrinter->GetPaperBin();
2097
2098
        // Change orientation?
2099
0
        SdPage& rMaster (dynamic_cast<SdPage&>(rHandoutPage.TRG_GetMasterPage()));
2100
0
        rInfo.meOrientation = rMaster.GetOrientation();
2101
2102
0
        Size aPaperSize (rInfo.mpPrinter->GetPaperSize());
2103
0
        lcl_AdjustPageSize(aPaperSize, rInfo.mpPrinter->GetPrintPageSize());
2104
0
        maPrintSize = awt::Size(aPaperSize.Width(),aPaperSize.Height());
2105
2106
0
        MapMode aMap (rInfo.maMap);
2107
0
        const Point aPageOfs (rInfo.mpPrinter->GetPageOffset());
2108
2109
0
        if ( bScalePage )
2110
0
        {
2111
0
            Size aPageSize (rHandoutPage.GetSize());
2112
0
            Size aPrintSize (rInfo.mpPrinter->GetOutputSize());
2113
0
            lcl_AdjustPageSize(aPageSize, aPrintSize);
2114
2115
0
            const double fHorz = static_cast<double>(aPrintSize.Width())    / aPageSize.Width();
2116
0
            const double fVert = static_cast<double>(aPrintSize.Height()) / aPageSize.Height();
2117
2118
0
            Fraction    aFract;
2119
0
            if ( fHorz < fVert )
2120
0
                aFract = Fraction(aPrintSize.Width(), aPageSize.Width());
2121
0
            else
2122
0
                aFract = Fraction(aPrintSize.Height(), aPageSize.Height());
2123
2124
0
            aMap.SetScaleX(aFract);
2125
0
            aMap.SetScaleY(aFract);
2126
0
            aMap.SetOrigin(Point());
2127
0
        }
2128
2129
0
        std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
2130
0
        pViewShell->WriteFrameViewData();
2131
2132
        // Count page shapes.
2133
0
        sal_uInt32 nShapeCount (0);
2134
0
        SdrObjListIter aShapeIter (&rHandoutPage);
2135
0
        while (aShapeIter.IsMore())
2136
0
        {
2137
0
            SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
2138
0
            if (pPageObj)
2139
0
                ++nShapeCount;
2140
0
        }
2141
2142
0
        const sal_uInt16 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
2143
0
        const sal_uInt16 nHandoutPageCount = nShapeCount ? (nPageCount + nShapeCount - 1) / nShapeCount : 0;
2144
0
        pViewShell->SetPrintedHandoutPageCount( nHandoutPageCount );
2145
0
        mrBase.GetDocument()->setHandoutPageCount( nHandoutPageCount );
2146
2147
        // Distribute pages to handout pages.
2148
0
        StringRangeEnumerator aRangeEnum(
2149
0
            mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
2150
0
            0, nPageCount-1);
2151
0
        std::vector<sal_uInt16> aPageIndices;
2152
0
        sal_uInt16 nPrinterPageIndex = 0;
2153
0
        StringRangeEnumerator::Iterator it = aRangeEnum.begin(), itEnd = aRangeEnum.end();
2154
0
        bool bLastLoop = (it == itEnd);
2155
0
        while (!bLastLoop)
2156
0
        {
2157
0
            sal_Int32 nPageIndex = *it;
2158
0
            ++it;
2159
0
            bLastLoop = (it == itEnd);
2160
2161
0
            if (GetFilteredPage(nPageIndex, PageKind::Standard))
2162
0
                aPageIndices.push_back(nPageIndex);
2163
0
            else if (!bLastLoop)
2164
0
                continue;
2165
2166
            // Create a printer page when we have found one page for each
2167
            // placeholder or when this is the last (and special) loop.
2168
0
            if ( !aPageIndices.empty() && CheckForFrontBackPages( nPageIndex )
2169
0
                && (aPageIndices.size() == nShapeCount || bLastLoop) )
2170
0
            {
2171
0
                maPrinterPages.push_back(
2172
0
                    std::make_shared<HandoutPrinterPage>(
2173
0
                            nPrinterPageIndex++,
2174
0
                            std::move(aPageIndices),
2175
0
                            aMap,
2176
0
                            rInfo.msTimeDate,
2177
0
                            aPageOfs,
2178
0
                            rInfo.mnDrawMode,
2179
0
                            rInfo.meOrientation,
2180
0
                            nPaperBin));
2181
0
                aPageIndices.clear();
2182
0
            }
2183
0
        }
2184
0
    }
2185
2186
    /** Prepare the notes pages or regular slides.
2187
    */
2188
    void PrepareStdOrNotes (
2189
        const PageKind ePageKind,
2190
        PrintInfo& rInfo)
2191
0
    {
2192
0
        OSL_ASSERT(rInfo.mpPrinter != nullptr);
2193
2194
        // Fill in page kind specific data.
2195
0
        SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
2196
0
        if (pDocument->GetSdPageCount(ePageKind) == 0)
2197
0
            return;
2198
0
        SdPage* pRefPage = pDocument->GetSdPage(0, ePageKind);
2199
2200
0
        if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()) && mpOptions->IsNotes())
2201
0
            rInfo.maPageSize = mpPrinter->GetPrintPageSize();
2202
0
        else
2203
0
            rInfo.maPageSize = pRefPage->GetSize();
2204
2205
0
        SetupPaperOrientation(ePageKind, rInfo);
2206
2207
0
        if (mpOptions->IsBooklet())
2208
0
            PrepareBooklet(ePageKind, rInfo);
2209
0
        else
2210
0
            PrepareRegularPages(ePageKind, rInfo);
2211
0
    }
2212
2213
    /** Prepare slides in a non-booklet way: one slide per one to many
2214
        printer pages.
2215
    */
2216
    void PrepareRegularPages (
2217
        const PageKind ePageKind,
2218
        PrintInfo& rInfo)
2219
0
    {
2220
0
        std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
2221
0
        pViewShell->WriteFrameViewData();
2222
2223
0
        sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
2224
0
        StringRangeEnumerator aRangeEnum(
2225
0
            mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
2226
0
            0, nPageCount-1);
2227
0
        for (StringRangeEnumerator::Iterator
2228
0
                 it = aRangeEnum.begin(),
2229
0
                 itEnd = aRangeEnum.end();
2230
0
             it != itEnd;
2231
0
             ++it)
2232
0
        {
2233
0
            SdPage* pPage = GetFilteredPage(*it, ePageKind);
2234
0
            if (pPage == nullptr)
2235
0
                continue;
2236
2237
0
            MapMode aMap (rInfo.maMap);
2238
2239
0
            Size aPageSize = pPage->GetSize();
2240
2241
0
            if (mpOptions->IsPageSize())
2242
0
            {
2243
0
                Size aPrintSize = rInfo.maPrintSize;
2244
0
                lcl_AdjustPageSize(aPageSize, aPrintSize);
2245
2246
0
                const double fHorz(static_cast<double>(aPrintSize.Width()) / aPageSize.Width());
2247
0
                const double fVert(static_cast<double>(aPrintSize.Height()) / aPageSize.Height());
2248
2249
0
                Fraction aFract;
2250
0
                if (fHorz < fVert)
2251
0
                    aFract = Fraction(aPrintSize.Width(), aPageSize.Width());
2252
0
                else
2253
0
                    aFract = Fraction(aPrintSize.Height(), aPageSize.Height());
2254
2255
0
                aMap.SetScaleX(aFract);
2256
0
                aMap.SetScaleY(aFract);
2257
0
                aMap.SetOrigin(Point());
2258
0
            }
2259
2260
0
            if (mpOptions->IsPrintPageName())
2261
0
            {
2262
0
                rInfo.msPageString = pPage->GetName() + " ";
2263
0
            }
2264
0
            else
2265
0
                rInfo.msPageString.clear();
2266
0
            rInfo.msPageString += rInfo.msTimeDate;
2267
2268
0
            ::tools::Long aPageWidth   = aPageSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder();
2269
0
            ::tools::Long aPageHeight  = aPageSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder();
2270
            // Bugfix for 44530:
2271
            // if it was implicitly changed (Landscape/Portrait),
2272
            // this is considered for tiling, respectively for the splitting up
2273
            // (Poster)
2274
0
            if( ( rInfo.maPrintSize.Width() > rInfo.maPrintSize.Height()
2275
0
                    && aPageWidth < aPageHeight )
2276
0
                || ( rInfo.maPrintSize.Width() < rInfo.maPrintSize.Height()
2277
0
                    && aPageWidth > aPageHeight ) )
2278
0
            {
2279
0
                const sal_Int32 nTmp (rInfo.maPrintSize.Width());
2280
0
                rInfo.maPrintSize.setWidth( rInfo.maPrintSize.Height() );
2281
0
                rInfo.maPrintSize.setHeight( nTmp );
2282
0
            }
2283
2284
0
            if (mpOptions->IsTilePage()
2285
0
                && aPageWidth < rInfo.maPrintSize.Width()
2286
0
                && aPageHeight < rInfo.maPrintSize.Height())
2287
0
            {
2288
                // Put multiple slides on one printer page.
2289
0
                PrepareTiledPage(*it, *pPage, ePageKind, rInfo);
2290
0
            }
2291
0
            else
2292
0
            {
2293
0
                rInfo.maMap = std::move(aMap);
2294
0
                PrepareScaledPage(*it, *pPage, ePageKind, rInfo);
2295
0
            }
2296
0
        }
2297
0
    }
2298
2299
    /** Put two slides on one printer page.
2300
    */
2301
    void PrepareBooklet (
2302
        const PageKind ePageKind,
2303
        const PrintInfo& rInfo)
2304
0
    {
2305
0
        MapMode aStdMap (rInfo.maMap);
2306
0
        Point aOffset;
2307
0
        Size aPrintSize_2 (rInfo.maPrintSize);
2308
0
        Size aPageSize_2 (rInfo.maPageSize);
2309
2310
0
        if (rInfo.meOrientation == Orientation::Landscape)
2311
0
            aPrintSize_2.setWidth( aPrintSize_2.Width() >> 1 );
2312
0
        else
2313
0
            aPrintSize_2.setHeight( aPrintSize_2.Height() >> 1 );
2314
2315
0
        const double fPageWH = static_cast<double>(aPageSize_2.Width()) / aPageSize_2.Height();
2316
0
        const double fPrintWH = static_cast<double>(aPrintSize_2.Width()) / aPrintSize_2.Height();
2317
2318
0
        if( fPageWH < fPrintWH )
2319
0
        {
2320
0
            aPageSize_2.setWidth(  static_cast<::tools::Long>( aPrintSize_2.Height() * fPageWH ) );
2321
0
            aPageSize_2.setHeight( aPrintSize_2.Height() );
2322
0
        }
2323
0
        else
2324
0
        {
2325
0
            aPageSize_2.setWidth( aPrintSize_2.Width() );
2326
0
            aPageSize_2.setHeight( static_cast<::tools::Long>( aPrintSize_2.Width() / fPageWH ) );
2327
0
        }
2328
2329
0
        MapMode aMap (rInfo.maMap);
2330
0
        aMap.SetScaleX( Fraction( aPageSize_2.Width(), rInfo.maPageSize.Width() ) );
2331
0
        aMap.SetScaleY( Fraction( aPageSize_2.Height(), rInfo.maPageSize.Height() ) );
2332
2333
        // calculate adjusted print size
2334
0
        const Size aAdjustedPrintSize (OutputDevice::LogicToLogic(
2335
0
            rInfo.maPrintSize,
2336
0
            aStdMap,
2337
0
            aMap));
2338
2339
0
        if (rInfo.meOrientation == Orientation::Landscape)
2340
0
        {
2341
0
            aOffset.setX( ( ( aAdjustedPrintSize.Width() >> 1 ) - rInfo.maPageSize.Width() ) >> 1 );
2342
0
            aOffset.setY( ( aAdjustedPrintSize.Height() - rInfo.maPageSize.Height() ) >> 1 );
2343
0
        }
2344
0
        else
2345
0
        {
2346
0
            aOffset.setX( ( aAdjustedPrintSize.Width() - rInfo.maPageSize.Width() ) >> 1 );
2347
0
            aOffset.setY( ( ( aAdjustedPrintSize.Height() >> 1 ) - rInfo.maPageSize.Height() ) >> 1 );
2348
0
        }
2349
2350
        // create vector of pages to print
2351
0
        sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(ePageKind);
2352
0
        StringRangeEnumerator aRangeEnum(
2353
0
            mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
2354
0
            0, nPageCount-1);
2355
0
        std::vector< sal_uInt16 > aPageVector;
2356
0
        for (StringRangeEnumerator::Iterator
2357
0
                 it = aRangeEnum.begin(),
2358
0
                 itEnd = aRangeEnum.end();
2359
0
             it != itEnd;
2360
0
             ++it)
2361
0
        {
2362
0
            SdPage* pPage = GetFilteredPage(*it, ePageKind);
2363
0
            if (pPage != nullptr)
2364
0
                aPageVector.push_back(*it);
2365
0
        }
2366
2367
        // create pairs of pages to print on each page
2368
0
        std::vector< std::pair< sal_uInt16, sal_uInt16 > > aPairVector;
2369
0
        if ( ! aPageVector.empty())
2370
0
        {
2371
0
            sal_uInt32 nFirstIndex = 0, nLastIndex = aPageVector.size() - 1;
2372
2373
0
            if( aPageVector.size() & 1 )
2374
0
                aPairVector.emplace_back( sal_uInt16(65535), aPageVector[ nFirstIndex++ ] );
2375
0
            else
2376
0
                aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
2377
2378
0
            while( nFirstIndex < nLastIndex )
2379
0
            {
2380
0
                if( nFirstIndex & 1 )
2381
0
                    aPairVector.emplace_back( aPageVector[ nFirstIndex++ ], aPageVector[ nLastIndex-- ] );
2382
0
                else
2383
0
                    aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
2384
0
            }
2385
0
        }
2386
2387
0
        bool bPrintBookletRTL = mpOptions->IsProspectRTL();
2388
2389
0
        for (sal_uInt32
2390
0
                 nIndex=0,
2391
0
                 nCount=aPairVector.size();
2392
0
             nIndex < nCount;
2393
0
             ++nIndex)
2394
0
        {
2395
0
            if ( CheckForFrontBackPages( nIndex ) )
2396
0
            {
2397
0
                std::pair<sal_uInt16, sal_uInt16> aPair (aPairVector[nIndex]);
2398
0
                if( bPrintBookletRTL )
2399
0
                    std::swap(aPair.first, aPair.second);
2400
0
                Point aSecondOffset (aOffset);
2401
0
                if (rInfo.meOrientation == Orientation::Landscape)
2402
0
                    aSecondOffset.AdjustX( aAdjustedPrintSize.Width() / 2 );
2403
0
                else
2404
0
                    aSecondOffset.AdjustY( aAdjustedPrintSize.Height() / 2 );
2405
0
                maPrinterPages.push_back(
2406
0
                    std::make_shared<BookletPrinterPage>(
2407
0
                            aPair.first,
2408
0
                            aPair.second,
2409
0
                            aOffset,
2410
0
                            aSecondOffset,
2411
0
                            ePageKind,
2412
0
                            aMap,
2413
0
                            rInfo.mbPrintMarkedOnly,
2414
0
                            rInfo.mnDrawMode,
2415
0
                            rInfo.meOrientation,
2416
0
                            rInfo.mpPrinter->GetPaperBin()));
2417
2418
0
            }
2419
0
        }
2420
0
    }
2421
2422
    /** Print one slide multiple times on one printer page so that the whole
2423
        printer page is covered.
2424
    */
2425
    void PrepareTiledPage (
2426
        const sal_Int32 nPageIndex,
2427
        const SdPage& rPage,
2428
        const PageKind ePageKind,
2429
        const PrintInfo& rInfo)
2430
0
    {
2431
0
        sal_uInt16 nPaperBin;
2432
0
        if ( ! mpOptions->IsPaperBin())
2433
0
            nPaperBin = rPage.GetPaperBin();
2434
0
        else
2435
0
            nPaperBin = rInfo.mpPrinter->GetPaperBin();
2436
2437
0
        if ( !CheckForFrontBackPages( nPageIndex ) )
2438
0
            return;
2439
2440
0
        maPrinterPages.push_back(
2441
0
            std::make_shared<TiledPrinterPage>(
2442
0
                sal::static_int_cast<sal_uInt16>(nPageIndex),
2443
0
                ePageKind,
2444
0
                rInfo.mbPrintMarkedOnly,
2445
0
                rInfo.msPageString,
2446
0
                rInfo.mpPrinter->GetPageOffset(),
2447
0
                rInfo.mnDrawMode,
2448
0
                rInfo.meOrientation,
2449
0
                nPaperBin));
2450
0
    }
2451
2452
    /** Print one standard slide or notes page on one to many printer
2453
        pages.  More than on printer page is used when the slide is larger
2454
        than the printable area.
2455
    */
2456
    void PrepareScaledPage (
2457
        const sal_Int32 nPageIndex,
2458
        const SdPage& rPage,
2459
        const PageKind ePageKind,
2460
        const PrintInfo& rInfo)
2461
0
    {
2462
0
        const Point aPageOffset (rInfo.mpPrinter->GetPageOffset());
2463
2464
0
        sal_uInt16 nPaperBin;
2465
0
        if ( ! mpOptions->IsPaperBin())
2466
0
            nPaperBin = rPage.GetPaperBin();
2467
0
        else
2468
0
            nPaperBin = rInfo.mpPrinter->GetPaperBin();
2469
2470
        // For pages larger than the printable area there are three options:
2471
        // 1. Scale down to the page to the printable area.
2472
        // 2. Print only the upper left part of the page (without the unprintable borders).
2473
        // 3. Split the page into parts of the size of the printable area.
2474
0
        const bool bScalePage (mpOptions->IsPageSize());
2475
0
        const bool bCutPage (mpOptions->IsCutPage());
2476
0
        MapMode aMap (rInfo.maMap);
2477
0
        if ( (bScalePage || bCutPage) && CheckForFrontBackPages( nPageIndex ) )
2478
0
        {
2479
            // Handle 1 and 2.
2480
2481
            // if CutPage is set then do not move it, otherwise move the
2482
            // scaled page to printable area
2483
0
            if (ePageKind == PageKind::Standard)
2484
0
            {
2485
0
                maPrinterPages.push_back(
2486
0
                    std::make_shared<RegularPrinterPage>(
2487
0
                            sal::static_int_cast<sal_uInt16>(nPageIndex),
2488
0
                            ePageKind,
2489
0
                            aMap,
2490
0
                            rInfo.mbPrintMarkedOnly,
2491
0
                            rInfo.msPageString,
2492
0
                            aPageOffset,
2493
0
                            rInfo.mnDrawMode,
2494
0
                            rInfo.meOrientation,
2495
0
                            nPaperBin));
2496
0
            }
2497
0
            else if (SdPage* pPage = GetFilteredPage(nPageIndex, PageKind::Notes))// Notes
2498
0
            {
2499
0
                SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
2500
2501
                // Clone the current page to create an independent instance.
2502
                // This ensures that changes made to pNotesPage do not affect the original page.
2503
0
                rtl::Reference<SdPage> pNotesPage
2504
0
                    = static_cast<SdPage*>(pPage->CloneSdrPage(*pDocument).get());
2505
2506
0
                Size aPageSize = bScalePage ? pNotesPage->GetSize() : rInfo.mpPrinter->GetPrintPageSize();
2507
                // Adjusts the objects on the notes page to fit the new page size.
2508
0
                ::tools::Rectangle aNewBorderRect(-1, -1, -1, -1);
2509
0
                pNotesPage->ScaleObjects(aPageSize, aNewBorderRect, true);
2510
2511
0
                SdrObject* pNotesObj = pNotesPage->GetPresObj(PresObjKind::Notes);
2512
0
                if (pNotesObj && bCutPage)
2513
0
                {
2514
                    // default margins
2515
0
                    sal_Int32 nTopMargin = aPageSize.Height() * 0.075;
2516
0
                    sal_Int32 nBottomMargin = nTopMargin;
2517
2518
0
                    Size nNotesObjSize = pNotesObj->GetLogicRect().GetSize();
2519
2520
0
                    Outliner* pOut = pDocument->GetInternalOutliner();
2521
0
                    const OutlinerMode nSaveOutlMode(pOut->GetOutlinerMode());
2522
0
                    const bool bSavedUpdateMode(pOut->IsUpdateLayout());
2523
0
                    pOut->Init(OutlinerMode::OutlineView);
2524
0
                    pOut->SetPaperSize(nNotesObjSize);
2525
0
                    pOut->SetUpdateLayout(true);
2526
0
                    pOut->Clear();
2527
0
                    if (OutlinerParaObject* pOutlinerParaObject = pNotesObj->GetOutlinerParaObject())
2528
0
                        pOut->SetText(*pOutlinerParaObject);
2529
2530
0
                    sal_Int32 nFirstPageBottomMargin = 0;
2531
0
                    ::tools::Long nNotesHeight = nNotesObjSize.Height();
2532
0
                    bool bAutoGrow = pNotesObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
2533
0
                    if (bAutoGrow)
2534
0
                    {
2535
0
                        nNotesHeight += pNotesObj->GetRelativePos().Y();
2536
0
                        nFirstPageBottomMargin = (pNotesPage->GetLowerBorder() != 0)
2537
0
                                                     ? pNotesPage->GetLowerBorder()
2538
0
                                                     : nBottomMargin;
2539
0
                    }
2540
0
                    double nOverflowedTextHeight = 0;
2541
0
                    ::tools::Long nFirstPageBottom = aPageSize.Height() - nFirstPageBottomMargin;
2542
0
                    if (nNotesHeight > nFirstPageBottom)
2543
0
                    {
2544
                        // Calculate the height of the overflow text
2545
                        // when the AutoGrowHeight property of the notes object is enabled
2546
                        // and the height of the object exceeds the page height.
2547
0
                        nOverflowedTextHeight = pNotesObj->GetRelativePos().Y()
2548
0
                                                + pOut->GetTextHeight() - nFirstPageBottom;
2549
0
                    }
2550
0
                    else
2551
0
                        nOverflowedTextHeight = pOut->GetTextHeight() - nNotesObjSize.Height();
2552
2553
0
                    sal_Int32 nNotePageCount = 1;
2554
0
                    double nNewPageHeight = aPageSize.Height() - nTopMargin - nBottomMargin;
2555
0
                    if (nOverflowedTextHeight > 0)
2556
0
                    {
2557
0
                        nNotePageCount += std::ceil(nOverflowedTextHeight / nNewPageHeight);
2558
0
                    }
2559
2560
0
                    for (sal_Int32 i = 1; i <= nNotePageCount; i++)
2561
0
                    {
2562
                        // set page numbers
2563
0
                        sal_Int32 nPageNumb = i;
2564
0
                        OUString sPageNumb = rInfo.msPageString;
2565
0
                        if (!sPageNumb.isEmpty() && nNotePageCount > 1)
2566
0
                        {
2567
0
                            OUString sTmp;
2568
0
                            if (!rInfo.msTimeDate.isEmpty())
2569
0
                            {
2570
0
                                sTmp += " ";
2571
0
                            }
2572
0
                            sTmp += SdResId(STR_PAGE_NAME) + " " + OUString::number(i);
2573
0
                            sPageNumb += sTmp;
2574
0
                        }
2575
2576
0
                        maPrinterPages.push_back(
2577
0
                            std::make_shared<NotesPrinterPage>(
2578
0
                                    sal::static_int_cast<sal_uInt16>(nPageIndex),
2579
0
                                    nPageNumb,
2580
0
                                    nNotePageCount,
2581
0
                                    bScalePage,
2582
0
                                    PageKind::Notes,
2583
0
                                    aMap,
2584
0
                                    rInfo.mbPrintMarkedOnly,
2585
0
                                    sPageNumb,
2586
0
                                    aPageOffset,
2587
0
                                    rInfo.mnDrawMode,
2588
0
                                    rInfo.meOrientation,
2589
0
                                    nPaperBin));
2590
0
                    }
2591
0
                    pOut->Clear();
2592
0
                    pOut->SetUpdateLayout(bSavedUpdateMode);
2593
0
                    pOut->Init(nSaveOutlMode);
2594
0
                }
2595
0
                else // scaled page
2596
0
                {
2597
0
                    maPrinterPages.push_back(
2598
0
                        std::make_shared<NotesPrinterPage>(
2599
0
                                sal::static_int_cast<sal_uInt16>(nPageIndex),
2600
0
                                sal_Int32(0),
2601
0
                                sal_Int32(0),
2602
0
                                bScalePage,
2603
0
                                PageKind::Notes,
2604
0
                                aMap,
2605
0
                                rInfo.mbPrintMarkedOnly,
2606
0
                                rInfo.msPageString,
2607
0
                                aPageOffset,
2608
0
                                rInfo.mnDrawMode,
2609
0
                                rInfo.meOrientation,
2610
0
                                nPaperBin));
2611
0
                }
2612
0
            }
2613
0
        }
2614
0
        else
2615
0
        {
2616
            // Handle 3.  Print parts of the page in the size of the
2617
            // printable area until the whole page is covered.
2618
2619
            // keep the page content at its position if it fits, otherwise
2620
            // move it to the printable area
2621
0
            const ::tools::Long nPageWidth (
2622
0
                rInfo.maPageSize.Width() - rPage.GetLeftBorder() - rPage.GetRightBorder());
2623
0
            const ::tools::Long nPageHeight (
2624
0
                rInfo.maPageSize.Height() - rPage.GetUpperBorder() - rPage.GetLowerBorder());
2625
2626
0
            Point aOrigin ( 0, 0 );
2627
2628
0
            for (Point aPageOrigin = aOrigin;
2629
0
                 -aPageOrigin.Y()<nPageHeight;
2630
0
                 aPageOrigin.AdjustY( -rInfo.maPrintSize.Height() ))
2631
0
            {
2632
0
                for (aPageOrigin.setX(aOrigin.X());
2633
0
                     -aPageOrigin.X()<nPageWidth;
2634
0
                     aPageOrigin.AdjustX(-rInfo.maPrintSize.Width()))
2635
0
                {
2636
0
                    if ( CheckForFrontBackPages( nPageIndex ) )
2637
0
                    {
2638
0
                        aMap.SetOrigin(aPageOrigin);
2639
0
                        maPrinterPages.push_back(
2640
0
                            std::make_shared<RegularPrinterPage>(
2641
0
                                    sal::static_int_cast<sal_uInt16>(nPageIndex),
2642
0
                                    ePageKind,
2643
0
                                    aMap,
2644
0
                                    rInfo.mbPrintMarkedOnly,
2645
0
                                    rInfo.msPageString,
2646
0
                                    aPageOffset,
2647
0
                                    rInfo.mnDrawMode,
2648
0
                                    rInfo.meOrientation,
2649
0
                                    nPaperBin));
2650
0
                    }
2651
0
                }
2652
0
            }
2653
0
        }
2654
0
    }
2655
2656
bool CheckForFrontBackPages( sal_Int32 nPage )
2657
0
{
2658
0
    const bool bIsIndexOdd(nPage & 1);
2659
0
    if ((!bIsIndexOdd && mpOptions->IsPrintFrontPage())
2660
0
        || (bIsIndexOdd && mpOptions->IsPrintBackPage()))
2661
0
    {
2662
0
        return true;
2663
0
    }
2664
0
    else
2665
0
        return false;
2666
0
}
2667
};
2668
2669
//===== DocumentRenderer ======================================================
2670
2671
DocumentRenderer::DocumentRenderer (ViewShellBase& rBase)
2672
0
    : mpImpl(new Implementation(rBase))
2673
0
{
2674
0
}
Unexecuted instantiation: sd::DocumentRenderer::DocumentRenderer(sd::ViewShellBase&)
Unexecuted instantiation: sd::DocumentRenderer::DocumentRenderer(sd::ViewShellBase&)
2675
2676
DocumentRenderer::~DocumentRenderer()
2677
0
{
2678
0
}
2679
2680
//----- XRenderable -----------------------------------------------------------
2681
2682
sal_Int32 SAL_CALL DocumentRenderer::getRendererCount (
2683
    const css::uno::Any&,
2684
    const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
2685
0
{
2686
0
    mpImpl->ProcessProperties(rOptions);
2687
0
    return mpImpl->GetPrintPageCount();
2688
0
}
2689
2690
Sequence<beans::PropertyValue> SAL_CALL DocumentRenderer::getRenderer (
2691
    sal_Int32,
2692
    const css::uno::Any&,
2693
    const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
2694
0
{
2695
0
    mpImpl->ProcessProperties(rOptions);
2696
0
    return mpImpl->GetProperties();
2697
0
}
2698
2699
void SAL_CALL DocumentRenderer::render (
2700
    sal_Int32 nRenderer,
2701
    const css::uno::Any&,
2702
    const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
2703
0
{
2704
0
    mpImpl->ProcessProperties(rOptions);
2705
0
    mpImpl->PrintPage(nRenderer);
2706
0
}
2707
2708
} // end of namespace sd
2709
2710
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */