tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / sd / source / ui / view / DocumentRenderer.cxx
blob2b666dbc2b896a079c8a29ad3b6568c44d9f3f9d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <com/sun/star/beans/XPropertySet.hpp>
22 #include <DocumentRenderer.hxx>
23 #include <DocumentRenderer.hrc>
24 #include <ViewShellBase.hxx>
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>
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.hxx>
64 #include <unotools/moduleoptions.hxx>
65 #include <xmloff/autolayout.hxx>
66 #include <sfx2/objsh.hxx>
68 #include <officecfg/Office/Draw.hxx>
69 #include <officecfg/Office/Impress.hxx>
71 #include <algorithm>
72 #include <memory>
73 #include <vector>
75 using namespace ::com::sun::star;
76 using namespace ::com::sun::star::uno;
78 namespace sd {
80 namespace {
82 void lcl_AdjustPageSize(Size& rPageSize, const Size& rPrintPageSize)
84 bool bOrientationDiff = (rPageSize.Width() < rPageSize.Height()
85 && rPrintPageSize.Width() > rPrintPageSize.Height())
86 || (rPageSize.Width() > rPageSize.Height()
87 && rPrintPageSize.Width() < rPrintPageSize.Height());
88 if (bOrientationDiff)
90 ::tools::Long nTmp = rPageSize.Width();
91 rPageSize.setWidth(rPageSize.Height());
92 rPageSize.setHeight(nTmp);
96 /** Convenience class to extract values from the sequence of properties
97 given to one of the XRenderable methods.
99 class PrintOptions
101 public:
102 PrintOptions (
103 const vcl::PrinterOptionsHelper& rHelper,
104 std::vector<sal_Int32>&& rSlidesPerPage)
105 : mrProperties(rHelper),
106 maSlidesPerPage(std::move(rSlidesPerPage))
110 bool IsWarningOrientation() const
112 return GetBoolValue(nullptr, true);
115 bool IsPrintPageName() const
117 return GetBoolValue("IsPrintName", false);
120 bool IsDate() const
122 return GetBoolValue("IsPrintDateTime", false);
125 bool IsTime() const
127 return GetBoolValue("IsPrintDateTime", false);
130 bool IsHiddenPages() const
132 return GetBoolValue("IsPrintHidden", false);
135 bool IsHandoutHorizontal() const
137 return GetBoolValue("SlidesPerPageOrder", sal_Int32(0));
140 sal_Int32 GetHandoutPageCount() const
142 sal_uInt32 nIndex = static_cast<sal_Int32>(mrProperties.getIntValue("SlidesPerPage", sal_Int32(0)));
143 if (nIndex<maSlidesPerPage.size())
144 return maSlidesPerPage[nIndex];
145 else if ( ! maSlidesPerPage.empty())
146 return maSlidesPerPage[0];
147 else
148 return 0;
151 bool IsDraw() const
153 return GetBoolValue("PageContentType", sal_Int32(0));
156 bool IsHandout() const
158 return GetBoolValue("PageContentType", sal_Int32(1));
161 bool IsNotes() const
163 return GetBoolValue("PageContentType", sal_Int32(2));
166 bool IsOutline() const
168 return GetBoolValue("PageContentType", sal_Int32(3));
171 sal_uLong GetOutputQuality() const
173 sal_Int32 nQuality = static_cast<sal_Int32>(mrProperties.getIntValue( "Quality", sal_Int32(0) ));
174 return nQuality;
177 bool IsPageSize() const
179 return GetBoolValue("PageOptions", sal_Int32(1));
182 bool IsTilePage() const
184 return GetBoolValue("PageOptions", sal_Int32(2)) || GetBoolValue("PageOptions", sal_Int32(3));
187 bool IsCutPage() const
189 return GetBoolValue("PageOptions", sal_Int32(0));
192 bool IsBooklet() const
194 return GetBoolValue("PrintProspect", false);
197 bool IsPrinterPreferred(DocumentType eDocType) const
199 bool bIsDraw = eDocType == DocumentType::Draw;
200 return IsTilePage() || IsPageSize() || IsBooklet() || (!bIsDraw && !IsNotes());
203 bool IsPrintExcluded() const
205 return (IsNotes() || IsDraw() || IsHandout()) && IsHiddenPages();
208 bool IsPrintFrontPage() const
210 sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
211 return nInclude != 2;
214 bool IsPrintBackPage() const
216 sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
217 return nInclude != 1;
220 bool IsPaperBin() const
222 return GetBoolValue("PrintPaperFromSetup", false);
225 bool IsPrintMarkedOnly() const
227 return GetBoolValue("PrintContent", sal_Int32(4));
230 OUString GetPrinterSelection (sal_Int32 nPageCount, sal_Int32 nCurrentPageIndex) const
232 sal_Int32 nContent = static_cast<sal_Int32>(mrProperties.getIntValue( "PrintContent", 0 ));
233 OUString sFullRange = "1-" + OUString::number(nPageCount);
235 if (nContent == 0) // all pages/slides
237 return sFullRange;
240 if (nContent == 1) // range
242 OUString sValue = mrProperties.getStringValue("PageRange");
243 return sValue.isEmpty() ? sFullRange : sValue;
246 if (nContent == 2 && // selection
247 nCurrentPageIndex >= 0)
249 return OUString::number(nCurrentPageIndex + 1);
252 return OUString();
255 private:
256 const vcl::PrinterOptionsHelper& mrProperties;
257 const std::vector<sal_Int32> maSlidesPerPage;
259 /** When the value of the property with name pName is a boolean then
260 return its value. When the property is unknown then
261 bDefaultValue is returned. Otherwise <FALSE/> is returned.
263 bool GetBoolValue (
264 const char* pName,
265 const bool bDefaultValue) const
267 bool bValue = mrProperties.getBoolValue( pName, bDefaultValue );
268 return bValue;
271 /** Return <TRUE/> when the value of the property with name pName is
272 an integer and its value is nTriggerValue. Otherwise <FALSE/> is
273 returned.
275 bool GetBoolValue (
276 const char* pName,
277 const sal_Int32 nTriggerValue) const
279 sal_Int32 nValue = static_cast<sal_Int32>(mrProperties.getIntValue( pName, 0 ));
280 return nValue == nTriggerValue;
284 /** A collection of values that helps to reduce the number of arguments
285 given to some functions. Note that not all values are set at the
286 same time.
288 class PrintInfo
290 public:
291 PrintInfo (
292 Printer* pPrinter,
293 const bool bPrintMarkedOnly)
294 : mpPrinter(pPrinter),
295 mnDrawMode(DrawModeFlags::Default),
296 maPrintSize(0,0),
297 maPageSize(0,0),
298 meOrientation(Orientation::Portrait),
299 mbPrintMarkedOnly(bPrintMarkedOnly)
302 const VclPtr<Printer> mpPrinter;
303 DrawModeFlags mnDrawMode;
304 OUString msTimeDate;
305 OUString msPageString;
306 Size maPrintSize;
307 Size maPageSize;
308 Orientation meOrientation;
309 MapMode maMap;
310 const bool mbPrintMarkedOnly;
313 /** Output one page of the document to the given printer. Note that
314 more than one document page may be output to one printer page.
316 void PrintPage (
317 Printer& rPrinter,
318 ::sd::View& rPrintView,
319 SdPage& rPage,
320 View const * pView,
321 const bool bPrintMarkedOnly,
322 const SdrLayerIDSet& rVisibleLayers,
323 const SdrLayerIDSet& rPrintableLayers)
325 rPrintView.ShowSdrPage(&rPage);
327 const MapMode aOriginalMapMode (rPrinter.GetMapMode());
329 // Set the visible layers
330 SdrPageView* pPageView = rPrintView.GetSdrPageView();
331 OSL_ASSERT(pPageView!=nullptr);
332 pPageView->SetVisibleLayers(rVisibleLayers);
333 pPageView->SetPrintableLayers(rPrintableLayers);
335 if (pView!=nullptr && bPrintMarkedOnly)
336 pView->DrawMarkedObj(rPrinter);
337 else
338 rPrintView.CompleteRedraw(&rPrinter,
339 vcl::Region(::tools::Rectangle(Point(0,0), rPage.GetSize())));
341 rPrinter.SetMapMode(aOriginalMapMode);
343 rPrintView.HideSdrPage();
346 /** Output a string (that typically is not part of a document page) to
347 the given printer.
349 void PrintMessage (
350 Printer& rPrinter,
351 const OUString& rsPageString,
352 const Point& rPageStringOffset)
354 const vcl::Font aOriginalFont (rPrinter.OutputDevice::GetFont());
355 rPrinter.SetFont(vcl::Font(FAMILY_SWISS, Size(0, 423)));
356 rPrinter.DrawText(rPageStringOffset, rsPageString);
357 rPrinter.SetFont(aOriginalFont);
360 /** Read the resources and process then into a sequence of properties
361 that can be passed to the printing dialog.
363 class DialogCreator
365 public:
366 DialogCreator (ViewShellBase &rBase, bool bImpress, sal_Int32 nCurPage)
367 : mrBase(rBase)
368 , mbImpress(bImpress)
369 , mnCurPage(nCurPage)
371 ProcessResource();
374 const std::vector< beans::PropertyValue >& GetDialogControls() const
376 return maProperties;
379 const std::vector<sal_Int32>& GetSlidesPerPage() const
381 return maSlidesPerPage;
384 private:
385 ViewShellBase &mrBase;
386 std::vector<beans::PropertyValue> maProperties;
387 std::vector<sal_Int32> maSlidesPerPage;
388 bool mbImpress;
389 sal_Int32 mnCurPage;
391 void ProcessResource()
393 // load the writer PrinterOptions into the custom tab
394 beans::PropertyValue aOptionsUIFile;
395 aOptionsUIFile.Name = "OptionsUIFile";
396 if( mbImpress )
397 aOptionsUIFile.Value <<= u"modules/simpress/ui/impressprinteroptions.ui"_ustr;
398 else
399 aOptionsUIFile.Value <<= u"modules/sdraw/ui/drawprinteroptions.ui"_ustr;
400 maProperties.push_back(aOptionsUIFile);
402 SvtModuleOptions aOpt;
403 OUString aAppGroupname(SdResId(STR_IMPRESS_PRINT_UI_GROUP_NAME));
404 aAppGroupname = aAppGroupname.replaceFirst("%s", aOpt.GetModuleName(
405 mbImpress ? SvtModuleOptions::EModule::IMPRESS : SvtModuleOptions::EModule::DRAW));
406 AddDialogControl(vcl::PrinterOptionsHelper::setGroupControlOpt(u"tabcontrol-page2"_ustr, aAppGroupname, u".HelpID:vcl:PrintDialog:TabPage:AppPage"_ustr));
408 uno::Sequence< OUString > aHelpIds, aWidgetIds;
409 if( mbImpress )
411 aHelpIds = { u".HelpID:vcl:PrintDialog:PageContentType:ListBox"_ustr };
412 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
413 u"impressdocument"_ustr,
414 SdResId(STR_IMPRESS_PRINT_UI_CONTENT),
415 aHelpIds,
416 u"PageContentType"_ustr ,
417 CreateChoice(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES)),
421 aHelpIds = { u".HelpID:vcl:PrintDialog:SlidesPerPage:ListBox"_ustr };
422 vcl::PrinterOptionsHelper::UIControlOptions aContentOpt( u"PageContentType"_ustr , 1 );
423 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
424 u"slidesperpage"_ustr,
425 SdResId(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE),
426 aHelpIds,
427 u"SlidesPerPage"_ustr ,
428 GetSlidesPerPageSequence(),
430 Sequence< sal_Bool >(),
431 aContentOpt
435 aHelpIds = { u".HelpID:vcl:PrintDialog:SlidesPerPageOrder:ListBox"_ustr };
436 vcl::PrinterOptionsHelper::UIControlOptions aSlidesPerPageOpt( u"SlidesPerPage"_ustr , -1, true );
437 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
438 u"slidesperpageorder"_ustr,
439 SdResId(STR_IMPRESS_PRINT_UI_ORDER),
440 aHelpIds,
441 u"SlidesPerPageOrder"_ustr ,
442 CreateChoice(STR_IMPRESS_PRINT_UI_ORDER_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_ORDER_CHOICES)),
444 Sequence< sal_Bool >(),
445 aSlidesPerPageOpt )
449 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"contents"_ustr,
450 SdResId(STR_IMPRESS_PRINT_UI_INCLUDE_CONTENT), u""_ustr ) );
452 if( mbImpress )
454 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printname"_ustr,
455 SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_NAME),
456 u".HelpID:vcl:PrintDialog:IsPrintName:CheckBox"_ustr ,
457 u"IsPrintName"_ustr ,
458 officecfg::Office::Impress::Print::Other::PageName::get()
462 else
464 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printname"_ustr,
465 SdResId(STR_DRAW_PRINT_UI_IS_PRINT_NAME),
466 u".HelpID:vcl:PrintDialog:IsPrintName:CheckBox"_ustr ,
467 u"IsPrintName"_ustr ,
468 officecfg::Office::Draw::Print::Other::PageName::get()
473 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printdatetime"_ustr,
474 SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_DATE),
475 u".HelpID:vcl:PrintDialog:IsPrintDateTime:CheckBox"_ustr ,
476 u"IsPrintDateTime"_ustr ,
477 // Separate settings for time and date in Impress/Draw -> Print page, check that both are set
478 mbImpress ?
479 officecfg::Office::Impress::Print::Other::Date::get() &&
480 officecfg::Office::Impress::Print::Other::Time::get() :
481 officecfg::Office::Draw::Print::Other::Date::get() &&
482 officecfg::Office::Draw::Print::Other::Time::get()
486 if( mbImpress )
488 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printhidden"_ustr,
489 SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_HIDDEN),
490 u".HelpID:vcl:PrintDialog:IsPrintHidden:CheckBox"_ustr ,
491 u"IsPrintHidden"_ustr ,
492 officecfg::Office::Impress::Print::Other::HiddenPage::get()
497 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"color"_ustr,
498 SdResId(STR_IMPRESS_PRINT_UI_QUALITY), u""_ustr ) );
500 aHelpIds = { u".HelpID:vcl:PrintDialog:Quality:RadioButton:0"_ustr,
501 u".HelpID:vcl:PrintDialog:Quality:RadioButton:1"_ustr,
502 u".HelpID:vcl:PrintDialog:Quality:RadioButton:2"_ustr };
503 aWidgetIds = { u"originalcolors"_ustr, u"grayscale"_ustr, u"blackandwhite"_ustr };
504 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
505 aWidgetIds,
506 u""_ustr,
507 aHelpIds,
508 u"Quality"_ustr ,
509 CreateChoice(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES)),
510 mbImpress ? officecfg::Office::Impress::Print::Other::Quality::get() :
511 officecfg::Office::Draw::Print::Other::Quality::get() )
515 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"pagesizes"_ustr,
516 SdResId(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS), u""_ustr ) );
518 aHelpIds = { u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:0"_ustr,
519 u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:1"_ustr,
520 u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:2"_ustr,
521 u".HelpID:vcl:PrintDialog:PageOptions:RadioButton:3"_ustr };
522 aWidgetIds = { u"originalsize"_ustr, u"fittoprintable"_ustr, u"distributeonmultiple"_ustr, u"tilesheet"_ustr };
524 // Mutually exclusive page options settings are stored in separate config keys...
525 // TODO: There is no config key to set the distributeonmultiple option as default
526 sal_Int32 nDefaultChoice = 0;
527 if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageSize::get() :
528 officecfg::Office::Draw::Print::Page::PageSize::get() )
530 nDefaultChoice = 1;
532 else if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageTile::get() :
533 officecfg::Office::Draw::Print::Page::PageTile::get() )
535 nDefaultChoice = 3;
537 vcl::PrinterOptionsHelper::UIControlOptions aPageOptionsOpt(u"PrintProspect"_ustr, 0);
538 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
539 aWidgetIds,
540 u""_ustr,
541 aHelpIds,
542 u"PageOptions"_ustr ,
543 mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES)) :
544 CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW)),
545 nDefaultChoice,
546 Sequence< sal_Bool >(),
547 aPageOptionsOpt
551 vcl::PrinterOptionsHelper::UIControlOptions aBrochureOpt;
552 aBrochureOpt.maGroupHint = "LayoutPage" ;
553 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"pagesides"_ustr,
554 SdResId(STR_IMPRESS_PRINT_UI_PAGE_SIDES), u""_ustr,
555 aBrochureOpt ) );
557 // brochure printing
558 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"brochure"_ustr,
559 SdResId(STR_IMPRESS_PRINT_UI_BROCHURE),
560 u".HelpID:vcl:PrintDialog:PrintProspect:CheckBox"_ustr ,
561 u"PrintProspect"_ustr ,
562 mbImpress ? officecfg::Office::Impress::Print::Page::Booklet::get() :
563 officecfg::Office::Draw::Print::Page::Booklet::get(),
564 aBrochureOpt
568 vcl::PrinterOptionsHelper::UIControlOptions
569 aIncludeOpt( u"PrintProspect"_ustr , -1, false );
570 aIncludeOpt.maGroupHint = "LayoutPage" ;
571 aHelpIds = { u".HelpID:vcl:PrintDialog:PrintProspectInclude:ListBox"_ustr };
572 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
573 u"brochureinclude"_ustr,
574 SdResId(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE),
575 aHelpIds,
576 u"PrintProspectInclude"_ustr ,
577 CreateChoice(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST)),
579 Sequence< sal_Bool >(),
580 aIncludeOpt
584 // paper tray (on options page)
585 vcl::PrinterOptionsHelper::UIControlOptions aPaperTrayOpt;
586 aPaperTrayOpt.maGroupHint = "OptionsPageOptGroup" ;
587 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt(u"printpaperfromsetup"_ustr,
588 SdResId(STR_IMPRESS_PRINT_UI_PAPER_TRAY),
589 u".HelpID:vcl:PrintDialog:PrintPaperFromSetup:CheckBox"_ustr ,
590 u"PrintPaperFromSetup"_ustr ,
591 false,
592 aPaperTrayOpt
595 // print range selection
596 vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
597 aPrintRangeOpt.mbInternalOnly = true;
598 aPrintRangeOpt.maGroupHint = "PrintRange" ;
599 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt(u"printrange"_ustr,
600 mbImpress ? SdResId(STR_IMPRESS_PRINT_UI_SLIDE_RANGE) : SdResId(STR_IMPRESS_PRINT_UI_PAGE_RANGE),
601 u""_ustr,
602 aPrintRangeOpt )
605 // check if there is a selection of slides
606 OUString aPageRange(OUString::number(mnCurPage + 1));
607 int nPrintRange(0);
608 using sd::slidesorter::SlideSorterViewShell;
609 SlideSorterViewShell* const pSSViewSh(SlideSorterViewShell::GetSlideSorter(mrBase));
610 if (pSSViewSh)
612 const std::shared_ptr<SlideSorterViewShell::PageSelection> pPageSelection(pSSViewSh->GetPageSelection());
613 if (bool(pPageSelection) && pPageSelection->size() > 1)
615 OUStringBuffer aBuf;
616 // TODO: this could be improved by writing ranges instead of consecutive page
617 // numbers if appropriate. Do we have a helper function for that somewhere?
618 bool bFirst(true);
619 for (auto pPage: *pPageSelection)
621 if (bFirst)
622 bFirst = false;
623 else
624 aBuf.append(',');
625 aBuf.append(static_cast<sal_Int32>(pPage->GetPageNum() / 2 + 1));
627 aPageRange = aBuf.makeStringAndClear();
628 nPrintRange = 1;
632 OUString aPrintRangeName( "PrintContent" );
633 aHelpIds.realloc( 1 );
634 aHelpIds[0] = ".HelpID:vcl:PrintDialog:PageContentType:ListBox";
635 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( "printpagesbox", OUString(),
636 aHelpIds, aPrintRangeName,
637 mbImpress ? CreateChoice( STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE ) ) :
638 CreateChoice( STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE ) ),
639 nPrintRange ) );
641 OUString aPrintRangeName( u"PrintContent"_ustr );
642 aHelpIds = { u".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0"_ustr,
643 u".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1"_ustr,
644 u".HelpID:vcl:PrintDialog:PrintContent:RadioButton:2"_ustr };
645 aWidgetIds = { u"rbAllPages"_ustr, u"rbRangePages"_ustr, u"rbRangeSelection"_ustr };
647 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(aWidgetIds, OUString(),
648 aHelpIds, aPrintRangeName,
649 mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE)) :
650 CreateChoice(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE)),
651 nPrintRange )
653 // create an Edit dependent on "Pages" selected
654 vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
655 AddDialogControl(vcl::PrinterOptionsHelper::setEditControlOpt(u"pagerange"_ustr, u""_ustr,
656 u".HelpID:vcl:PrintDialog:PageRange:Edit"_ustr, u"PageRange"_ustr,
657 aPageRange, aPageRangeOpt));
658 vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, -1, true);
659 AddDialogControl(vcl::PrinterOptionsHelper::setChoiceListControlOpt(u"evenoddbox"_ustr, u""_ustr,
660 uno::Sequence<OUString>(), u"EvenOdd"_ustr, uno::Sequence<OUString>(),
661 0, uno::Sequence<sal_Bool>(), aEvenOddOpt));
664 void AddDialogControl( const Any& i_rCtrl )
666 beans::PropertyValue aVal;
667 aVal.Value = i_rCtrl;
668 maProperties.push_back( aVal );
671 static Sequence<OUString> CreateChoice(const TranslateId* pResourceId, size_t nCount)
673 Sequence<OUString> aChoices (nCount);
674 std::transform(pResourceId, pResourceId + nCount, aChoices.getArray(),
675 [](const auto& id) { return SdResId(id); });
676 return aChoices;
679 Sequence<OUString> GetSlidesPerPageSequence()
681 const Sequence<OUString> aChoice (
682 CreateChoice(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES)));
683 maSlidesPerPage.clear();
684 maSlidesPerPage.push_back(0); // first is using the default
685 std::transform(std::next(aChoice.begin()), aChoice.end(), std::back_inserter(maSlidesPerPage),
686 [](const OUString& rChoice) -> sal_Int32 { return rChoice.toInt32(); });
687 return aChoice;
691 /** The Prepare... methods of the DocumentRenderer::Implementation class
692 create a set of PrinterPage objects that contain all necessary
693 information to do the actual printing. There is one PrinterPage
694 object per printed page. Derived classes implement the actual, mode
695 specific printing.
697 This and all derived classes support the asynchronous printing
698 process by not storing pointers to any data with lifetime shorter
699 than the PrinterPage objects, i.e. slides, shapes, (one of) the
700 outliner (of the document).
702 class PrinterPage
704 public:
705 PrinterPage (
706 const PageKind ePageKind,
707 const MapMode& rMapMode,
708 const bool bPrintMarkedOnly,
709 OUString sPageString,
710 const Point& rPageStringOffset,
711 const DrawModeFlags nDrawMode,
712 const Orientation eOrientation,
713 const sal_uInt16 nPaperTray)
714 : mePageKind(ePageKind),
715 maMap(rMapMode),
716 mbPrintMarkedOnly(bPrintMarkedOnly),
717 msPageString(std::move(sPageString)),
718 maPageStringOffset(rPageStringOffset),
719 mnDrawMode(nDrawMode),
720 meOrientation(eOrientation),
721 mnPaperTray(nPaperTray)
725 virtual ~PrinterPage() {}
727 virtual void Print (
728 Printer& rPrinter,
729 SdDrawDocument& rDocument,
730 ViewShell& rViewShell,
731 View* pView,
732 DrawView& rPrintView,
733 const SdrLayerIDSet& rVisibleLayers,
734 const SdrLayerIDSet& rPrintableLayers) const = 0;
736 DrawModeFlags GetDrawMode() const { return mnDrawMode; }
737 Orientation GetOrientation() const { return meOrientation; }
738 sal_uInt16 GetPaperTray() const { return mnPaperTray; }
740 protected:
741 const PageKind mePageKind;
742 const MapMode maMap;
743 const bool mbPrintMarkedOnly;
744 const OUString msPageString;
745 const Point maPageStringOffset;
746 const DrawModeFlags mnDrawMode;
747 const Orientation meOrientation;
748 const sal_uInt16 mnPaperTray;
751 /** The RegularPrinterPage is used for printing one regular slide (no
752 notes, handout, or outline) to one printer page.
754 class RegularPrinterPage : public PrinterPage
756 public:
757 RegularPrinterPage (
758 const sal_uInt16 nPageIndex,
759 const PageKind ePageKind,
760 const MapMode& rMapMode,
761 const bool bPrintMarkedOnly,
762 const OUString& rsPageString,
763 const Point& rPageStringOffset,
764 const DrawModeFlags nDrawMode,
765 const Orientation eOrientation,
766 const sal_uInt16 nPaperTray)
767 : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString,
768 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
769 mnPageIndex(nPageIndex)
773 virtual void Print (
774 Printer& rPrinter,
775 SdDrawDocument& rDocument,
776 ViewShell&,
777 View* pView,
778 DrawView& rPrintView,
779 const SdrLayerIDSet& rVisibleLayers,
780 const SdrLayerIDSet& rPrintableLayers) const override
782 SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
783 rPrinter.SetMapMode(maMap);
784 PrintPage(
785 rPrinter,
786 rPrintView,
787 *pPageToPrint,
788 pView,
789 mbPrintMarkedOnly,
790 rVisibleLayers,
791 rPrintableLayers);
792 PrintMessage(
793 rPrinter,
794 msPageString,
795 maPageStringOffset);
798 private:
799 const sal_uInt16 mnPageIndex;
802 /** The NotesPrinterPage is used for printing notes pages onto one or more printer pages
804 class NotesPrinterPage : public PrinterPage
806 public:
807 NotesPrinterPage(
808 const sal_uInt16 nPageIndex,
809 const sal_Int32 nPageNumb,
810 const sal_Int32 nPageCount,
811 const bool bScaled,
812 const PageKind ePageKind,
813 const MapMode& rMapMode,
814 const bool bPrintMarkedOnly,
815 const OUString& rsPageString,
816 const Point& rPageStringOffset,
817 const DrawModeFlags nDrawMode,
818 const Orientation eOrientation,
819 const sal_uInt16 nPaperTray)
820 : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString, rPageStringOffset,
821 nDrawMode, eOrientation, nPaperTray),
822 mnPageIndex(nPageIndex),
823 mnPageNumb(nPageNumb),
824 mnPageCount(nPageCount),
825 mbScaled(bScaled)
829 virtual void Print(
830 Printer& rPrinter,
831 SdDrawDocument& rDocument,
832 ViewShell&,
833 View* pView,
834 DrawView& rPrintView,
835 const SdrLayerIDSet& rVisibleLayers,
836 const SdrLayerIDSet& rPrintableLayers) const override
838 SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
839 rPrinter.SetMapMode(maMap);
841 // Clone the current page to create an independent instance for modifications.
842 // This ensures that changes made to pNotesPage do not affect the original page.
843 rtl::Reference<SdPage> pNotesPage
844 = static_cast<SdPage*>(pPageToPrint->CloneSdrPage(rDocument).get());
846 Size aPageSize;
847 if (mbScaled)
849 aPageSize = pNotesPage->GetSize();
850 lcl_AdjustPageSize(aPageSize, rPrinter.GetPrintPageSize());
852 else
853 aPageSize = rPrinter.GetPrintPageSize();
855 // Adjusts the objects on the notes page to fit the new page size.
856 ::tools::Rectangle aNewBorderRect(-1, -1, -1, -1);
857 pNotesPage->ScaleObjects(aPageSize, aNewBorderRect, true);
859 SdrObject* pNotesObj = pNotesPage->GetPresObj(PresObjKind::Notes);
860 if (pNotesObj)
862 // new page(s) margins
863 sal_Int32 nLeft = aPageSize.Width() * 0.1;
864 sal_Int32 nRight = nLeft;
865 sal_Int32 nTop = aPageSize.Height() * 0.075;
866 sal_Int32 nBottom = nTop;
868 Point aNotesPt = pNotesObj->GetRelativePos();
869 Size aNotesSize = pNotesObj->GetLogicRect().GetSize();
871 Outliner* pOut = rDocument.GetInternalOutliner();
872 const OutlinerMode nSaveOutlMode(pOut->GetOutlinerMode());
873 const bool bSavedUpdateMode(pOut->IsUpdateLayout());
874 pOut->SetPaperSize(aNotesSize);
875 pOut->SetUpdateLayout(true);
876 pOut->Clear();
877 pOut->SetText(*pNotesObj->GetOutlinerParaObject());
879 bool bAutoGrow = pNotesObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
881 // If AutoGrowHeight property is enabled and the notes page has a lower border,
882 // use the lower border but if there is no lower border, use the bottom margin
883 // to determine the first page break position.
884 // If AutoGrow is not enabled, the notes object defines the first page break.
885 ::tools::Long nNotesPageBottom
886 = bAutoGrow ? (pNotesPage->GetLowerBorder() != 0)
887 ? aPageSize.Height() - pNotesPage->GetLowerBorder()
888 : aPageSize.Height() - nBottom
889 : aNotesPt.Y() + aNotesSize.Height();
890 if (mbScaled)
892 sal_Int32 nTextHeight = aNotesPt.Y() + pOut->GetTextHeight();
893 if (bAutoGrow && (nTextHeight > nNotesPageBottom))
895 pNotesObj->SetMergedItem(SdrOnOffItem(SDRATTR_TEXT_AUTOGROWHEIGHT, false));
897 ::tools::Long nObjW = aNotesSize.Width();
898 ::tools::Long nObjH = aPageSize.Height() - aNotesPt.Y() - nBottom;
900 pNotesObj->SetLogicRect(::tools::Rectangle(aNotesPt, Size(nObjW, nObjH)));
902 SdrTextFitToSizeTypeItem eFitToSize = drawing::TextFitToSizeType_AUTOFIT;
903 pNotesObj->SetMergedItem(eFitToSize);
905 else // original size
907 bool bExit = false;
908 sal_Int32 nPrevLineLen = 0;
909 sal_Int32 nPrevParaIdx = 0;
910 sal_uInt16 nActualPageNumb = 1;
911 sal_uInt16 nPrevParaLowerSpace = 0;
912 ::tools::Long nCurrentPosY = aNotesPt.Y();
913 sal_Int32 nParaCount = pOut->GetParagraphCount();
914 std::vector<std::pair<sal_Int32, sal_Int32>> aPageBreaks;
916 for (sal_Int32 i = 0; i < nParaCount && !bExit; ++i)
918 sal_Int32 nActualLineLen = 0;
919 sal_Int32 nLineCount = pOut->GetLineCount(i);
921 sal_uInt16 nLowerSpace = 0;
922 sal_uInt16 nUpperSpace = nPrevParaLowerSpace;
923 const SfxItemSet* pItemSet = &pOut->GetParaAttribs(i);
924 if(pItemSet->HasItem(EE_PARA_ULSPACE))
926 nLowerSpace = pItemSet->Get(EE_PARA_ULSPACE).GetLower();
927 nUpperSpace = (i != 0) ? pItemSet->Get(EE_PARA_ULSPACE).GetUpper() : 0;
928 if (nPrevParaLowerSpace > nUpperSpace)
929 nUpperSpace = nPrevParaLowerSpace;
932 for (sal_Int32 j = 0; j < nLineCount; ++j)
934 nActualLineLen += pOut->GetLineLen(i, j);
935 sal_Int32 nLineHeight = pOut->GetLineHeight(i, j);
937 if (nUpperSpace != 0 && (i > 0) && (j == 0))
938 nLineHeight += nUpperSpace;
940 sal_Int32 nNextPosY = nCurrentPosY + nLineHeight;
942 if (nNextPosY > nNotesPageBottom)
944 // If the current or the next page matches the print page
945 // calculate and add a page break, since we only want to add
946 // a page break if the page is relevant.
947 if (mnPageNumb == nActualPageNumb
948 || mnPageNumb == nActualPageNumb + 1)
950 if (!aPageBreaks.empty())
952 // determine the page break at the bottom of the page
953 // for pages that have both a previous and a following page
954 aPageBreaks.emplace_back(
955 nPrevParaIdx - aPageBreaks[0].first, nPrevLineLen);
957 else
959 if (mnPageNumb == 1 || (nLineCount > 1 && j != 0))
961 // first page or multi-line paragraphs
962 aPageBreaks.emplace_back(nPrevParaIdx, nPrevLineLen);
964 else
965 { // single-line paragraphs
966 aPageBreaks.emplace_back(nPrevParaIdx + 1, 0);
970 if (mnPageNumb == nActualPageNumb || mnPageNumb == mnPageCount)
972 bExit = true;
973 break;
977 if (nUpperSpace > 0)
978 nLineHeight -= nUpperSpace;
980 nNotesPageBottom = aPageSize.Height() - nBottom;
981 nCurrentPosY = nTop;
982 nActualPageNumb++;
983 nActualLineLen = 0;
985 nPrevParaIdx = i;
986 nPrevLineLen = nActualLineLen;
987 nCurrentPosY += nLineHeight;
989 nPrevParaLowerSpace = nLowerSpace;
992 if (!aPageBreaks.empty())
994 ESelection aE;
995 if (mnPageNumb == 1)
997 aE.start.nPara = aPageBreaks[0].first;
998 aE.start.nIndex = aPageBreaks[0].second;
999 aE.end.nPara = pOut->GetParagraphCount() - 1;
1000 aE.end.nIndex = pOut->GetText(pOut->GetParagraph(aE.end.nPara)).getLength();
1001 pOut->QuickDelete(aE);
1003 else
1005 sal_Int16 nDepth = pOut->GetDepth(aPageBreaks[0].first);
1006 SfxItemSet aItemSet = pOut->GetParaAttribs(aPageBreaks[0].first);
1008 aE.start.nPara = 0;
1009 aE.start.nIndex = 0;
1010 aE.end.nPara = aPageBreaks[0].first;
1011 aE.end.nIndex = aPageBreaks[0].second;
1012 pOut->QuickDelete(aE);
1014 Paragraph* pFirstPara = pOut->GetParagraph(0);
1015 pOut->SetDepth(pFirstPara, nDepth);
1016 pOut->SetParaAttribs(0, aItemSet);
1018 if (aPageBreaks.size() > 1)
1020 aE.start.nPara = aPageBreaks[1].first;
1021 aE.start.nIndex = aPageBreaks[1].second;
1022 aE.end.nPara = pOut->GetParagraphCount() - 1;
1023 aE.end.nIndex = pOut->GetText(pOut->GetParagraph(aE.end.nPara)).getLength();
1024 pOut->QuickDelete(aE);
1028 pNotesObj->SetOutlinerParaObject(pOut->CreateParaObject());
1030 Size aObjSize;
1031 if (mnPageNumb != 1) // new page(s)
1033 SdrObjListIter aShapeIter(pNotesPage.get());
1034 while (aShapeIter.IsMore())
1036 SdrObject* pObj = aShapeIter.Next();
1037 if (pObj && pObj->GetObjIdentifier() != SdrObjKind::Text)
1038 pNotesPage->RemoveObject(pObj->GetOrdNum());
1041 aNotesPt.setX(nLeft);
1042 aNotesPt.setY(nTop);
1043 ::tools::Long nWidth = aPageSize.Width() - nLeft - nRight;
1044 aObjSize = Size(nWidth, pOut->GetTextHeight());
1046 else // first page
1048 if (!bAutoGrow)
1049 aObjSize = aNotesSize;
1050 else
1051 aObjSize = Size(aNotesSize.Width(), pOut->GetTextHeight());
1053 pNotesObj->SetLogicRect(::tools::Rectangle(aNotesPt, aObjSize));
1055 pOut->Clear();
1056 pOut->SetUpdateLayout(bSavedUpdateMode);
1057 pOut->Init(nSaveOutlMode);
1059 pNotesPage->SetSize(aPageSize);
1061 PrintPage(
1062 rPrinter,
1063 rPrintView,
1064 *pNotesPage,
1065 pView,
1066 mbPrintMarkedOnly,
1067 rVisibleLayers,
1068 rPrintableLayers);
1069 PrintMessage(
1070 rPrinter,
1071 msPageString,
1072 maPageStringOffset);
1075 private:
1076 const sal_uInt16 mnPageIndex;
1077 const sal_Int32 mnPageNumb;
1078 const sal_Int32 mnPageCount;
1079 const bool mbScaled;
1082 /** Print one slide multiple times on a printer page so that the whole
1083 printer page is covered.
1085 class TiledPrinterPage : public PrinterPage
1087 public:
1088 TiledPrinterPage (
1089 const sal_uInt16 nPageIndex,
1090 const PageKind ePageKind,
1091 const bool bPrintMarkedOnly,
1092 const OUString& rsPageString,
1093 const Point& rPageStringOffset,
1094 const DrawModeFlags nDrawMode,
1095 const Orientation eOrientation,
1096 const sal_uInt16 nPaperTray)
1097 : PrinterPage(ePageKind, MapMode(), bPrintMarkedOnly, rsPageString,
1098 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
1099 mnPageIndex(nPageIndex)
1103 virtual void Print (
1104 Printer& rPrinter,
1105 SdDrawDocument& rDocument,
1106 ViewShell&,
1107 View* pView,
1108 DrawView& rPrintView,
1109 const SdrLayerIDSet& rVisibleLayers,
1110 const SdrLayerIDSet& rPrintableLayers) const override
1112 SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
1113 if (pPageToPrint==nullptr)
1114 return;
1115 MapMode aMap (rPrinter.GetMapMode());
1117 const Size aPageSize (pPageToPrint->GetSize());
1118 const Size aPrintSize (rPrinter.GetOutputSize());
1120 const sal_Int32 nPageWidth (aPageSize.Width() + mnGap
1121 - pPageToPrint->GetLeftBorder() - pPageToPrint->GetRightBorder());
1122 const sal_Int32 nPageHeight (aPageSize.Height() + mnGap
1123 - pPageToPrint->GetUpperBorder() - pPageToPrint->GetLowerBorder());
1124 if (nPageWidth<=0 || nPageHeight<=0)
1125 return;
1127 // Print at least two rows and columns. More if the document
1128 // page fits completely onto the printer page.
1129 const sal_Int32 nColumnCount (std::max(sal_Int32(2),
1130 sal_Int32(aPrintSize.Width() / nPageWidth)));
1131 const sal_Int32 nRowCount (std::max(sal_Int32(2),
1132 sal_Int32(aPrintSize.Height() / nPageHeight)));
1133 for (sal_Int32 nRow=0; nRow<nRowCount; ++nRow)
1134 for (sal_Int32 nColumn=0; nColumn<nColumnCount; ++nColumn)
1136 aMap.SetOrigin(Point(nColumn*nPageWidth,nRow*nPageHeight));
1137 rPrinter.SetMapMode(aMap);
1138 PrintPage(
1139 rPrinter,
1140 rPrintView,
1141 *pPageToPrint,
1142 pView,
1143 mbPrintMarkedOnly,
1144 rVisibleLayers,
1145 rPrintableLayers);
1148 PrintMessage(
1149 rPrinter,
1150 msPageString,
1151 maPageStringOffset);
1154 private:
1155 const sal_uInt16 mnPageIndex;
1156 static const sal_Int32 mnGap = 500;
1159 /** Print two slides to one printer page so that the resulting pages
1160 form a booklet.
1162 class BookletPrinterPage : public PrinterPage
1164 public:
1165 BookletPrinterPage (
1166 const sal_uInt16 nFirstPageIndex,
1167 const sal_uInt16 nSecondPageIndex,
1168 const Point& rFirstOffset,
1169 const Point& rSecondOffset,
1170 const PageKind ePageKind,
1171 const MapMode& rMapMode,
1172 const bool bPrintMarkedOnly,
1173 const DrawModeFlags nDrawMode,
1174 const Orientation eOrientation,
1175 const sal_uInt16 nPaperTray)
1176 : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, u""_ustr,
1177 Point(), nDrawMode, eOrientation, nPaperTray),
1178 mnFirstPageIndex(nFirstPageIndex),
1179 mnSecondPageIndex(nSecondPageIndex),
1180 maFirstOffset(rFirstOffset),
1181 maSecondOffset(rSecondOffset)
1185 virtual void Print (
1186 Printer& rPrinter,
1187 SdDrawDocument& rDocument,
1188 ViewShell&,
1189 View* pView,
1190 DrawView& rPrintView,
1191 const SdrLayerIDSet& rVisibleLayers,
1192 const SdrLayerIDSet& rPrintableLayers) const override
1194 MapMode aMap (maMap);
1195 SdPage* pPageToPrint = rDocument.GetSdPage(mnFirstPageIndex, mePageKind);
1196 if (pPageToPrint)
1198 aMap.SetOrigin(maFirstOffset);
1199 rPrinter.SetMapMode(aMap);
1200 PrintPage(
1201 rPrinter,
1202 rPrintView,
1203 *pPageToPrint,
1204 pView,
1205 mbPrintMarkedOnly,
1206 rVisibleLayers,
1207 rPrintableLayers);
1210 pPageToPrint = rDocument.GetSdPage(mnSecondPageIndex, mePageKind);
1211 if( !pPageToPrint )
1212 return;
1214 aMap.SetOrigin(maSecondOffset);
1215 rPrinter.SetMapMode(aMap);
1216 PrintPage(
1217 rPrinter,
1218 rPrintView,
1219 *pPageToPrint,
1220 pView,
1221 mbPrintMarkedOnly,
1222 rVisibleLayers,
1223 rPrintableLayers);
1226 private:
1227 const sal_uInt16 mnFirstPageIndex;
1228 const sal_uInt16 mnSecondPageIndex;
1229 const Point maFirstOffset;
1230 const Point maSecondOffset;
1233 /** One handout page displays one to nine slides.
1235 class HandoutPrinterPage : public PrinterPage
1237 public:
1238 HandoutPrinterPage (
1239 const sal_uInt16 nHandoutPageIndex,
1240 std::vector<sal_uInt16>&& rPageIndices,
1241 const MapMode& rMapMode,
1242 const OUString& rsPageString,
1243 const Point& rPageStringOffset,
1244 const DrawModeFlags nDrawMode,
1245 const Orientation eOrientation,
1246 const sal_uInt16 nPaperTray)
1247 : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
1248 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
1249 mnHandoutPageIndex(nHandoutPageIndex),
1250 maPageIndices(std::move(rPageIndices))
1254 virtual void Print (
1255 Printer& rPrinter,
1256 SdDrawDocument& rDocument,
1257 ViewShell& rViewShell,
1258 View* pView,
1259 DrawView& rPrintView,
1260 const SdrLayerIDSet& rVisibleLayers,
1261 const SdrLayerIDSet& rPrintableLayers) const override
1263 SdPage& rHandoutPage (*rDocument.GetSdPage(0, PageKind::Handout));
1265 Size aPageSize(rHandoutPage.GetSize());
1266 Size aPrintPageSize = rPrinter.GetPrintPageSize();
1268 if ((aPageSize.Width() < aPageSize.Height()
1269 && aPrintPageSize.Width() > aPrintPageSize.Height())
1270 || (aPageSize.Width() > aPageSize.Height()
1271 && aPrintPageSize.Width() < aPrintPageSize.Height()))
1273 ::tools::Long nTmp = aPageSize.Width();
1274 aPageSize.setWidth(aPageSize.Height());
1275 aPageSize.setHeight(nTmp);
1277 rHandoutPage.SetSize(aPageSize);
1280 Reference< css::beans::XPropertySet > xHandoutPage( rHandoutPage.getUnoPage(), UNO_QUERY );
1281 static constexpr OUString sPageNumber( u"Number"_ustr );
1283 // Collect the page objects of the handout master.
1284 std::vector<SdrPageObj*> aHandoutPageObjects;
1285 SdrObjListIter aShapeIter (&rHandoutPage);
1286 while (aShapeIter.IsMore())
1288 SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
1289 if (pPageObj)
1290 aHandoutPageObjects.push_back(pPageObj);
1292 if (aHandoutPageObjects.empty())
1293 return;
1295 // Connect page objects with pages.
1296 std::vector<SdrPageObj*>::iterator aPageObjIter (aHandoutPageObjects.begin());
1297 for (std::vector<sal_uInt16>::const_iterator
1298 iPageIndex(maPageIndices.begin()),
1299 iEnd(maPageIndices.end());
1300 iPageIndex!=iEnd && aPageObjIter!=aHandoutPageObjects.end();
1301 ++iPageIndex)
1303 // Check if the page still exists.
1304 if (*iPageIndex >= rDocument.GetSdPageCount(PageKind::Standard))
1305 continue;
1307 SdrPageObj* pPageObj = *aPageObjIter++;
1308 pPageObj->SetReferencedPage(rDocument.GetSdPage(*iPageIndex, PageKind::Standard));
1311 // if there are more page objects than pages left, set the rest to invisible
1312 int nHangoverCount = 0;
1313 while (aPageObjIter != aHandoutPageObjects.end())
1315 (*aPageObjIter++)->SetReferencedPage(nullptr);
1316 nHangoverCount++;
1319 // Hide outlines for objects that have pages attached.
1320 if (nHangoverCount > 0)
1322 int nSkip = aHandoutPageObjects.size() - nHangoverCount;
1323 aShapeIter.Reset();
1324 while (aShapeIter.IsMore())
1326 SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
1327 if (pPathObj)
1329 if (nSkip > 0)
1330 --nSkip;
1331 else
1332 pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
1337 if( xHandoutPage.is() ) try
1339 xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(mnHandoutPageIndex) ) );
1341 catch( Exception& )
1344 rViewShell.SetPrintedHandoutPageNum( mnHandoutPageIndex + 1 );
1346 rPrinter.SetMapMode(maMap);
1348 PrintPage(
1349 rPrinter,
1350 rPrintView,
1351 rHandoutPage,
1352 pView,
1353 false,
1354 rVisibleLayers,
1355 rPrintableLayers);
1356 PrintMessage(
1357 rPrinter,
1358 msPageString,
1359 maPageStringOffset);
1361 if( xHandoutPage.is() ) try
1363 xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(0) ) );
1365 catch( Exception& )
1368 rViewShell.SetPrintedHandoutPageNum(1);
1370 // Restore outlines.
1371 if (nHangoverCount > 0)
1373 aShapeIter.Reset();
1374 while (aShapeIter.IsMore())
1376 SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
1377 if (pPathObj != nullptr)
1378 pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
1384 private:
1385 const sal_uInt16 mnHandoutPageIndex;
1386 const std::vector<sal_uInt16> maPageIndices;
1389 /** The outline information (title, subtitle, outline objects) of the
1390 document. There is no fixed mapping of slides to printer pages.
1392 class OutlinerPrinterPage : public PrinterPage
1394 public:
1395 OutlinerPrinterPage (
1396 std::optional<OutlinerParaObject> pParaObject,
1397 const MapMode& rMapMode,
1398 const OUString& rsPageString,
1399 const Point& rPageStringOffset,
1400 const DrawModeFlags nDrawMode,
1401 const Orientation eOrientation,
1402 const sal_uInt16 nPaperTray)
1403 : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
1404 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
1405 mpParaObject(std::move(pParaObject))
1409 virtual void Print (
1410 Printer& rPrinter,
1411 SdDrawDocument& rDocument,
1412 ViewShell&,
1413 View*,
1414 DrawView&,
1415 const SdrLayerIDSet&,
1416 const SdrLayerIDSet&) const override
1418 // Set up the printer.
1419 rPrinter.SetMapMode(maMap);
1421 // Get and set up the outliner.
1422 const ::tools::Rectangle aOutRect (rPrinter.GetPageOffset(), rPrinter.GetOutputSize());
1423 Outliner* pOutliner = rDocument.GetInternalOutliner();
1424 const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
1425 const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
1426 const Size aSavedPaperSize (pOutliner->GetPaperSize());
1428 pOutliner->Init(OutlinerMode::OutlineView);
1429 pOutliner->SetPaperSize(aOutRect.GetSize());
1430 pOutliner->SetUpdateLayout(true);
1431 pOutliner->Clear();
1432 pOutliner->SetText(*mpParaObject);
1434 pOutliner->Draw(rPrinter, aOutRect);
1436 PrintMessage(
1437 rPrinter,
1438 msPageString,
1439 maPageStringOffset);
1441 // Restore outliner and printer.
1442 pOutliner->Clear();
1443 pOutliner->SetUpdateLayout(bSavedUpdateMode);
1444 pOutliner->SetPaperSize(aSavedPaperSize);
1445 pOutliner->Init(nSavedOutlMode);
1448 private:
1449 std::optional<OutlinerParaObject> mpParaObject;
1453 //===== DocumentRenderer::Implementation ======================================
1455 class DocumentRenderer::Implementation
1456 : public SfxListener,
1457 public vcl::PrinterOptionsHelper
1459 public:
1460 explicit Implementation (ViewShellBase& rBase)
1461 : mxObjectShell(rBase.GetDocShell())
1462 , mrBase(rBase)
1463 , mbIsDisposed(false)
1464 , mpPrinter(nullptr)
1465 , mbHasOrientationWarningBeenShown(false)
1467 DialogCreator aCreator( mrBase, mrBase.GetDocShell()->GetDocumentType() == DocumentType::Impress, GetCurrentPageIndex() );
1468 m_aUIProperties = aCreator.GetDialogControls();
1469 maSlidesPerPage = aCreator.GetSlidesPerPage();
1471 StartListening(mrBase);
1474 virtual ~Implementation() override
1476 EndListening(mrBase);
1479 virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override
1481 if (&rBroadcaster != &static_cast<SfxBroadcaster&>(mrBase))
1482 return;
1484 if (rHint.GetId() == SfxHintId::Dying)
1486 mbIsDisposed = true;
1490 /** Process the sequence of properties given to one of the XRenderable
1491 methods.
1493 void ProcessProperties (const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
1495 OSL_ASSERT(!mbIsDisposed);
1496 if (mbIsDisposed)
1497 return;
1499 bool bIsValueChanged = processProperties( rOptions );
1500 bool bIsPaperChanged = false;
1502 // The RenderDevice property is handled specially: its value is
1503 // stored in mpPrinter instead of being retrieved on demand.
1504 Any aDev( getValue( u"RenderDevice"_ustr ) );
1505 Reference<awt::XDevice> xRenderDevice;
1507 if (aDev >>= xRenderDevice)
1509 VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>(xRenderDevice.get());
1510 VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice()
1511 : VclPtr< OutputDevice >();
1512 mpPrinter = dynamic_cast<Printer*>(pOut.get());
1513 Size aPageSizePixel = mpPrinter ? mpPrinter->GetPaperSizePixel() : Size();
1514 Size aPrintPageSize = mpPrinter ? mpPrinter->GetPrintPageSize() : Size();
1516 lcl_AdjustPageSize(aPageSizePixel, aPrintPageSize);
1518 if (aPageSizePixel != maPrinterPageSizePixel)
1520 bIsPaperChanged = true;
1521 maPrinterPageSizePixel = aPageSizePixel;
1525 if (bIsValueChanged && ! mpOptions )
1526 mpOptions.reset(new PrintOptions(*this, std::vector(maSlidesPerPage)));
1527 if( bIsValueChanged || bIsPaperChanged )
1528 PreparePages();
1531 /** Return the number of pages that are to be printed.
1533 sal_Int32 GetPrintPageCount() const
1535 OSL_ASSERT(!mbIsDisposed);
1536 if (mbIsDisposed)
1537 return 0;
1538 else
1539 return maPrinterPages.size();
1542 /** Return a sequence of properties that can be returned by the
1543 XRenderable::getRenderer() method.
1545 css::uno::Sequence<css::beans::PropertyValue> GetProperties () const
1547 css::uno::Sequence<css::beans::PropertyValue> aProperties{
1548 comphelper::makePropertyValue(u"ExtraPrintUIOptions"_ustr,
1549 comphelper::containerToSequence(m_aUIProperties)),
1550 comphelper::makePropertyValue(u"PageSize"_ustr, maPrintSize),
1551 // FIXME: is this always true ?
1552 comphelper::makePropertyValue(u"PageIncludesNonprintableArea"_ustr, true)
1555 return aProperties;
1558 /** Print one of the prepared pages.
1560 void PrintPage (const sal_Int32 nIndex)
1562 OSL_ASSERT(!mbIsDisposed);
1563 if (mbIsDisposed)
1564 return;
1566 Printer& rPrinter (*mpPrinter);
1568 std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
1569 if ( ! pViewShell)
1570 return;
1572 SdDrawDocument* pDocument = pViewShell->GetDoc();
1573 assert(pDocument!=nullptr);
1575 std::shared_ptr<DrawViewShell> pDrawViewShell(
1576 std::dynamic_pointer_cast<DrawViewShell>(pViewShell));
1578 if (!mpPrintView)
1579 mpPrintView.reset(new DrawView(mrBase.GetDocShell(), &rPrinter, nullptr));
1581 if (nIndex<0 || sal::static_int_cast<sal_uInt32>(nIndex)>=maPrinterPages.size())
1582 return;
1584 const std::shared_ptr<PrinterPage> pPage (maPrinterPages[nIndex]);
1585 OSL_ASSERT(pPage);
1586 if ( ! pPage)
1587 return;
1589 const Orientation eSavedOrientation (rPrinter.GetOrientation());
1590 const DrawModeFlags nSavedDrawMode (rPrinter.GetDrawMode());
1591 const MapMode aSavedMapMode (rPrinter.GetMapMode());
1592 const sal_uInt16 nSavedPaperBin (rPrinter.GetPaperBin());
1594 // Set page orientation.
1595 if ( ! rPrinter.SetOrientation(pPage->GetOrientation()))
1597 if ( ! mbHasOrientationWarningBeenShown
1598 && mpOptions->IsWarningOrientation())
1600 mbHasOrientationWarningBeenShown = true;
1601 // Show warning that the orientation could not be set.
1602 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(
1603 pViewShell->GetFrameWeld(), VclMessageType::Warning, VclButtonsType::OkCancel,
1604 SdResId(STR_WARN_PRINTFORMAT_FAILURE)));
1605 xWarn->set_default_response(RET_CANCEL);
1606 if (xWarn->run() != RET_OK)
1607 return;
1611 // Set the draw mode.
1612 rPrinter.SetDrawMode(pPage->GetDrawMode());
1614 // Set paper tray.
1615 rPrinter.SetPaperBin(pPage->GetPaperTray());
1617 // Print the actual page.
1618 pPage->Print(
1619 rPrinter,
1620 *pDocument,
1621 *pViewShell,
1622 pDrawViewShell ? pDrawViewShell->GetView() : nullptr,
1623 *mpPrintView,
1624 pViewShell->GetFrameView()->GetVisibleLayers(),
1625 pViewShell->GetFrameView()->GetPrintableLayers());
1627 rPrinter.SetOrientation(eSavedOrientation);
1628 rPrinter.SetDrawMode(nSavedDrawMode);
1629 rPrinter.SetMapMode(aSavedMapMode);
1630 rPrinter.SetPaperBin(nSavedPaperBin);
1633 private:
1634 // rhbz#657394: keep the document alive: prevents crash when
1635 SfxObjectShellRef mxObjectShell; // destroying mpPrintView
1636 ViewShellBase& mrBase;
1637 bool mbIsDisposed;
1638 VclPtr<Printer> mpPrinter;
1639 Size maPrinterPageSizePixel;
1640 std::unique_ptr<PrintOptions> mpOptions;
1641 std::vector< std::shared_ptr< ::sd::PrinterPage> > maPrinterPages;
1642 std::unique_ptr<DrawView> mpPrintView;
1643 bool mbHasOrientationWarningBeenShown;
1644 std::vector<sal_Int32> maSlidesPerPage;
1645 awt::Size maPrintSize;
1647 sal_Int32 GetCurrentPageIndex() const
1649 const ViewShell *pShell = mrBase.GetMainViewShell().get();
1650 const SdPage *pCurrentPage = pShell ? pShell->getCurrentPage() : nullptr;
1651 return pCurrentPage ? (pCurrentPage->GetPageNum()-1)/2 : -1;
1654 /** Determine and set the paper orientation.
1656 void SetupPaperOrientation (
1657 const PageKind ePageKind,
1658 PrintInfo& rInfo)
1660 SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
1661 rInfo.meOrientation = Orientation::Portrait;
1663 if( ! mpOptions->IsBooklet())
1665 rInfo.meOrientation = pDocument->GetSdPage(0, ePageKind)->GetOrientation();
1667 else if (rInfo.maPageSize.Width() < rInfo.maPageSize.Height())
1668 rInfo.meOrientation = Orientation::Landscape;
1670 // Draw and Notes should usually abide by their specified paper size
1671 Size aPaperSize;
1672 if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
1674 aPaperSize.setWidth(rInfo.maPageSize.Width());
1675 aPaperSize.setHeight(rInfo.maPageSize.Height());
1677 else
1679 aPaperSize.setWidth(rInfo.mpPrinter->GetPaperSize().Width());
1680 aPaperSize.setHeight(rInfo.mpPrinter->GetPaperSize().Height());
1682 if (!mpOptions->IsBooklet())
1683 lcl_AdjustPageSize(aPaperSize, rInfo.mpPrinter->GetPrintPageSize());
1686 maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
1688 if (mpOptions->IsPrinterPreferred(pDocument->GetDocumentType())
1689 && ePageKind == PageKind::Standard && !mpOptions->IsBooklet())
1691 if( (rInfo.meOrientation == Orientation::Landscape &&
1692 (aPaperSize.Width() < aPaperSize.Height()))
1694 (rInfo.meOrientation == Orientation::Portrait &&
1695 (aPaperSize.Width() > aPaperSize.Height()))
1698 maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
1703 /** Top most method for preparing printer pages. In this and the other
1704 Prepare... methods the various special cases are detected and
1705 handled.
1706 For every page that is to be printed (that may contain several
1707 slides) one PrinterPage object is created and inserted into
1708 maPrinterPages.
1710 void PreparePages()
1712 mpPrintView.reset();
1713 maPrinterPages.clear();
1714 mbHasOrientationWarningBeenShown = false;
1716 ViewShell* pShell = mrBase.GetMainViewShell().get();
1718 PrintInfo aInfo (mpPrinter, mpOptions->IsPrintMarkedOnly());
1720 if (aInfo.mpPrinter==nullptr || pShell==nullptr)
1721 return;
1723 MapMode aMap (aInfo.mpPrinter->GetMapMode());
1724 aMap.SetMapUnit(MapUnit::Map100thMM);
1725 aInfo.maMap = aMap;
1726 mpPrinter->SetMapMode(aMap);
1728 ::Outliner& rOutliner = mrBase.GetDocument()->GetDrawOutliner();
1729 const EEControlBits nSavedControlWord (rOutliner.GetControlWord());
1730 EEControlBits nCntrl = nSavedControlWord;
1731 nCntrl &= ~EEControlBits::MARKFIELDS;
1732 nCntrl &= ~EEControlBits::ONLINESPELLING;
1733 rOutliner.SetControlWord( nCntrl );
1735 // When in outline view then apply all pending changes to the model.
1736 if( auto pOutlineViewShell = dynamic_cast< OutlineViewShell *>( pShell ) )
1737 pOutlineViewShell->PrepareClose (false);
1739 // Collect some frequently used data.
1740 if (mpOptions->IsDate())
1742 aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getDate( Date( Date::SYSTEM ) );
1743 aInfo.msTimeDate += " ";
1746 if (mpOptions->IsTime())
1747 aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getTime( ::tools::Time( ::tools::Time::SYSTEM ), false );
1749 // Draw and Notes should usually use specified paper size when printing
1750 if (!mpOptions->IsPrinterPreferred(mrBase.GetDocShell()->GetDocumentType()))
1752 aInfo.maPrintSize = mrBase.GetDocument()->GetSdPage(0, PageKind::Standard)->GetSize();
1753 maPrintSize = awt::Size(aInfo.maPrintSize.Width(),
1754 aInfo.maPrintSize.Height());
1756 else
1758 aInfo.maPrintSize = aInfo.mpPrinter->GetOutputSize();
1759 maPrintSize = awt::Size(
1760 aInfo.mpPrinter->GetPaperSize().Width(),
1761 aInfo.mpPrinter->GetPaperSize().Height());
1764 switch (mpOptions->GetOutputQuality())
1766 case 1: // Grayscale
1767 aInfo.mnDrawMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill
1768 | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap
1769 | DrawModeFlags::GrayGradient;
1770 break;
1772 case 2: // Black & White
1773 aInfo.mnDrawMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill
1774 | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap
1775 | DrawModeFlags::WhiteGradient;
1776 break;
1778 default:
1779 aInfo.mnDrawMode = DrawModeFlags::Default;
1782 if (mpOptions->IsDraw())
1783 PrepareStdOrNotes(PageKind::Standard, aInfo);
1784 if (mpOptions->IsNotes())
1785 PrepareStdOrNotes(PageKind::Notes, aInfo);
1786 if (mpOptions->IsHandout())
1788 InitHandoutTemplate();
1789 PrepareHandout(aInfo);
1791 if (mpOptions->IsOutline())
1792 PrepareOutline(aInfo);
1794 rOutliner.SetControlWord(nSavedControlWord);
1797 /** Create the page objects of the handout template. When the actual
1798 printing takes place then the page objects are assigned different
1799 sets of slides for each printed page (see HandoutPrinterPage::Print).
1801 void InitHandoutTemplate()
1803 const sal_Int32 nSlidesPerHandout (mpOptions->GetHandoutPageCount());
1804 const bool bHandoutHorizontal (mpOptions->IsHandoutHorizontal());
1806 AutoLayout eLayout = AUTOLAYOUT_HANDOUT6;
1807 switch (nSlidesPerHandout)
1809 case 0: eLayout = AUTOLAYOUT_NONE; break; // AUTOLAYOUT_HANDOUT1; break;
1810 case 1: eLayout = AUTOLAYOUT_HANDOUT1; break;
1811 case 2: eLayout = AUTOLAYOUT_HANDOUT2; break;
1812 case 3: eLayout = AUTOLAYOUT_HANDOUT3; break;
1813 case 4: eLayout = AUTOLAYOUT_HANDOUT4; break;
1814 default:
1815 case 6: eLayout = AUTOLAYOUT_HANDOUT6; break;
1816 case 9: eLayout = AUTOLAYOUT_HANDOUT9; break;
1819 if( !mrBase.GetDocument() )
1820 return;
1822 SdDrawDocument& rModel = *mrBase.GetDocument();
1824 // first, prepare handout page (not handout master)
1826 SdPage* pHandout = rModel.GetSdPage(0, PageKind::Handout);
1827 if( !pHandout )
1828 return;
1830 // delete all previous shapes from handout page
1831 while( pHandout->GetObjCount() )
1832 pHandout->NbcRemoveObject(0);
1834 const bool bDrawLines (eLayout == AUTOLAYOUT_HANDOUT3);
1836 Size aHandoutPageSize = pHandout->GetSize();
1837 lcl_AdjustPageSize(aHandoutPageSize, mpPrinter->GetPrintPageSize());
1838 Orientation eOrient = aHandoutPageSize.Width() > aHandoutPageSize.Height()
1839 ? Orientation::Landscape
1840 : Orientation::Portrait;
1842 std::vector< ::tools::Rectangle > aAreas;
1843 SdPage::CalculateHandoutAreas( rModel, eLayout, bHandoutHorizontal, aAreas, eOrient );
1845 std::vector< ::tools::Rectangle >::iterator iter( aAreas.begin() );
1846 while( iter != aAreas.end() )
1848 pHandout->NbcInsertObject(
1849 new SdrPageObj(
1850 rModel,
1851 (*iter++)));
1853 if( bDrawLines && (iter != aAreas.end()) )
1855 ::tools::Rectangle aRect( *iter++ );
1857 basegfx::B2DPolygon aPoly;
1858 aPoly.insert(0, basegfx::B2DPoint( aRect.Left(), aRect.Top() ) );
1859 aPoly.insert(1, basegfx::B2DPoint( aRect.Right(), aRect.Top() ) );
1861 basegfx::B2DHomMatrix aMatrix;
1862 aMatrix.translate( 0.0, static_cast< double >( aRect.GetHeight() / 7 ) );
1864 basegfx::B2DPolyPolygon aPathPoly;
1865 for( sal_uInt16 nLine = 0; nLine < 7; nLine++ )
1867 aPoly.transform( aMatrix );
1868 aPathPoly.append( aPoly );
1871 rtl::Reference<SdrPathObj> pPathObj = new SdrPathObj(
1872 rModel,
1873 SdrObjKind::PathLine,
1874 std::move(aPathPoly));
1875 pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
1876 pPathObj->SetMergedItem(XLineColorItem(OUString(), COL_BLACK));
1878 pHandout->NbcInsertObject( pPathObj.get() );
1883 /** Detect whether the specified slide is to be printed.
1884 @return
1885 When the slide is not to be printed then <NULL/> is returned.
1886 Otherwise a pointer to the slide is returned.
1888 SdPage* GetFilteredPage (
1889 const sal_Int32 nPageIndex,
1890 const PageKind ePageKind) const
1892 OSL_ASSERT(mrBase.GetDocument() != nullptr);
1893 OSL_ASSERT(nPageIndex>=0);
1894 SdPage* pPage = mrBase.GetDocument()->GetSdPage(
1895 sal::static_int_cast<sal_uInt16>(nPageIndex),
1896 ePageKind);
1897 if (pPage == nullptr)
1898 return nullptr;
1899 if ( ! pPage->IsExcluded() || mpOptions->IsPrintExcluded())
1900 return pPage;
1901 else
1902 return nullptr;
1905 /** Prepare the outline of the document for printing. There is no fixed
1906 number of slides whose outline data is put onto one printer page.
1907 If the current printer page has enough room for the outline of the
1908 current slide then that is added. Otherwise a new printer page is
1909 started.
1911 void PrepareOutline (PrintInfo const & rInfo)
1913 MapMode aMap (rInfo.maMap);
1914 Point aPageOfs (rInfo.mpPrinter->GetPageOffset() );
1915 aMap.SetScaleX(Fraction(1,2));
1916 aMap.SetScaleY(Fraction(1,2));
1917 mpPrinter->SetMapMode(aMap);
1919 ::tools::Rectangle aOutRect(aPageOfs, rInfo.mpPrinter->GetOutputSize());
1920 if( aOutRect.GetWidth() > aOutRect.GetHeight() )
1922 Size aPaperSize( rInfo.mpPrinter->PixelToLogic( rInfo.mpPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) );
1923 maPrintSize.Width = aPaperSize.Height();
1924 maPrintSize.Height = aPaperSize.Width();
1925 const auto nRotatedWidth = aOutRect.GetHeight();
1926 const auto nRotatedHeight = aOutRect.GetWidth();
1927 const auto nRotatedX = aPageOfs.Y();
1928 const auto nRotatedY = aPageOfs.X();
1929 aOutRect = ::tools::Rectangle(Point( nRotatedX, nRotatedY),
1930 Size(nRotatedWidth, nRotatedHeight));
1933 Outliner* pOutliner = mrBase.GetDocument()->GetInternalOutliner();
1934 pOutliner->Init(OutlinerMode::OutlineView);
1935 const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
1936 const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
1937 const Size aSavedPaperSize (pOutliner->GetPaperSize());
1938 const MapMode aSavedMapMode (pOutliner->GetRefMapMode());
1939 pOutliner->SetPaperSize(aOutRect.GetSize());
1940 pOutliner->SetUpdateLayout(true);
1942 ::tools::Long nPageH = aOutRect.GetHeight();
1944 std::vector< sal_Int32 > aPages;
1945 sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
1946 StringRangeEnumerator::getRangesFromString(
1947 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
1948 aPages, 0, nPageCount-1);
1950 for (size_t nIndex = 0, nCount = aPages.size(); nIndex < nCount;)
1952 pOutliner->Clear();
1954 Paragraph* pPara = nullptr;
1955 ::tools::Long nH (0);
1956 while (nH < nPageH && nIndex<nCount)
1958 SdPage* pPage = GetFilteredPage(aPages[nIndex], PageKind::Standard);
1959 ++nIndex;
1960 if (pPage == nullptr)
1961 continue;
1963 SdrTextObj* pTextObj = nullptr;
1965 for (const rtl::Reference<SdrObject>& pObj : *pPage)
1967 if (pObj->GetObjInventor() == SdrInventor::Default
1968 && pObj->GetObjIdentifier() == SdrObjKind::TitleText)
1970 pTextObj = DynCastSdrTextObj(pObj.get());
1971 if (pTextObj)
1972 break;
1976 pPara = pOutliner->GetParagraph(pOutliner->GetParagraphCount() - 1);
1978 if (pTextObj!=nullptr
1979 && !pTextObj->IsEmptyPresObj()
1980 && pTextObj->GetOutlinerParaObject())
1982 pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
1984 else
1985 pOutliner->Insert(OUString());
1987 pTextObj = nullptr;
1989 for (const rtl::Reference<SdrObject>& pObj : *pPage)
1991 if (pObj->GetObjInventor() == SdrInventor::Default
1992 && pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
1994 pTextObj = DynCastSdrTextObj(pObj.get());
1995 if (pTextObj)
1996 break;
2000 bool bSubTitle (false);
2001 if (!pTextObj)
2003 bSubTitle = true;
2004 pTextObj = DynCastSdrTextObj(pPage->GetPresObj(PresObjKind::Text)); // is there a subtitle?
2007 sal_Int32 nParaCount1 = pOutliner->GetParagraphCount();
2009 if (pTextObj!=nullptr
2010 && !pTextObj->IsEmptyPresObj()
2011 && pTextObj->GetOutlinerParaObject())
2013 pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
2016 if (bSubTitle )
2018 const sal_Int32 nParaCount2 (pOutliner->GetParagraphCount());
2019 for (sal_Int32 nPara=nParaCount1; nPara<nParaCount2; ++nPara)
2021 Paragraph* pP = pOutliner->GetParagraph(nPara);
2022 if (pP!=nullptr && pOutliner->GetDepth(nPara) > 0)
2023 pOutliner->SetDepth(pP, 0);
2027 nH = pOutliner->GetTextHeight();
2030 // Remove the last paragraph when that does not fit completely on
2031 // the current page.
2032 if (nH > nPageH && pPara!=nullptr)
2034 sal_Int32 nCnt = pOutliner->GetAbsPos(
2035 pOutliner->GetParagraph( pOutliner->GetParagraphCount() - 1 ) );
2036 sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara );
2037 nCnt -= nParaPos;
2038 pPara = pOutliner->GetParagraph( ++nParaPos );
2039 if ( nCnt && pPara )
2041 pOutliner->Remove(pPara, nCnt);
2042 --nIndex;
2046 if ( CheckForFrontBackPages( nIndex ) )
2048 maPrinterPages.push_back(
2049 std::make_shared<OutlinerPrinterPage>(
2050 pOutliner->CreateParaObject(),
2051 aMap,
2052 rInfo.msTimeDate,
2053 aPageOfs,
2054 rInfo.mnDrawMode,
2055 rInfo.meOrientation,
2056 rInfo.mpPrinter->GetPaperBin()));
2060 pOutliner->SetRefMapMode(aSavedMapMode);
2061 pOutliner->SetUpdateLayout(bSavedUpdateMode);
2062 pOutliner->SetPaperSize(aSavedPaperSize);
2063 pOutliner->Init(nSavedOutlMode);
2066 /** Prepare handout pages for slides that are to be printed.
2068 void PrepareHandout (PrintInfo& rInfo)
2070 SdDrawDocument* pDocument = mrBase.GetDocument();
2071 assert(pDocument != nullptr);
2072 SdPage& rHandoutPage (*pDocument->GetSdPage(0, PageKind::Handout));
2074 const bool bScalePage (mpOptions->IsPageSize());
2076 sal_uInt16 nPaperBin;
2077 if ( ! mpOptions->IsPaperBin())
2078 nPaperBin = rHandoutPage.GetPaperBin();
2079 else
2080 nPaperBin = rInfo.mpPrinter->GetPaperBin();
2082 // Change orientation?
2083 SdPage& rMaster (dynamic_cast<SdPage&>(rHandoutPage.TRG_GetMasterPage()));
2084 rInfo.meOrientation = rMaster.GetOrientation();
2086 Size aPaperSize (rInfo.mpPrinter->GetPaperSize());
2087 lcl_AdjustPageSize(aPaperSize, rInfo.mpPrinter->GetPrintPageSize());
2088 maPrintSize = awt::Size(aPaperSize.Width(),aPaperSize.Height());
2090 MapMode aMap (rInfo.maMap);
2091 const Point aPageOfs (rInfo.mpPrinter->GetPageOffset());
2093 if ( bScalePage )
2095 Size aPageSize (rHandoutPage.GetSize());
2096 Size aPrintSize (rInfo.mpPrinter->GetOutputSize());
2097 lcl_AdjustPageSize(aPageSize, aPrintSize);
2099 const double fHorz = static_cast<double>(aPrintSize.Width()) / aPageSize.Width();
2100 const double fVert = static_cast<double>(aPrintSize.Height()) / aPageSize.Height();
2102 Fraction aFract;
2103 if ( fHorz < fVert )
2104 aFract = Fraction(aPrintSize.Width(), aPageSize.Width());
2105 else
2106 aFract = Fraction(aPrintSize.Height(), aPageSize.Height());
2108 aMap.SetScaleX(aFract);
2109 aMap.SetScaleY(aFract);
2110 aMap.SetOrigin(Point());
2113 std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
2114 pViewShell->WriteFrameViewData();
2116 // Count page shapes.
2117 sal_uInt32 nShapeCount (0);
2118 SdrObjListIter aShapeIter (&rHandoutPage);
2119 while (aShapeIter.IsMore())
2121 SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
2122 if (pPageObj)
2123 ++nShapeCount;
2126 const sal_uInt16 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
2127 const sal_uInt16 nHandoutPageCount = nShapeCount ? (nPageCount + nShapeCount - 1) / nShapeCount : 0;
2128 pViewShell->SetPrintedHandoutPageCount( nHandoutPageCount );
2129 mrBase.GetDocument()->setHandoutPageCount( nHandoutPageCount );
2131 // Distribute pages to handout pages.
2132 StringRangeEnumerator aRangeEnum(
2133 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
2134 0, nPageCount-1);
2135 std::vector<sal_uInt16> aPageIndices;
2136 sal_uInt16 nPrinterPageIndex = 0;
2137 StringRangeEnumerator::Iterator it = aRangeEnum.begin(), itEnd = aRangeEnum.end();
2138 bool bLastLoop = (it == itEnd);
2139 while (!bLastLoop)
2141 sal_Int32 nPageIndex = *it;
2142 ++it;
2143 bLastLoop = (it == itEnd);
2145 if (GetFilteredPage(nPageIndex, PageKind::Standard))
2146 aPageIndices.push_back(nPageIndex);
2147 else if (!bLastLoop)
2148 continue;
2150 // Create a printer page when we have found one page for each
2151 // placeholder or when this is the last (and special) loop.
2152 if ( !aPageIndices.empty() && CheckForFrontBackPages( nPageIndex )
2153 && (aPageIndices.size() == nShapeCount || bLastLoop) )
2155 maPrinterPages.push_back(
2156 std::make_shared<HandoutPrinterPage>(
2157 nPrinterPageIndex++,
2158 std::move(aPageIndices),
2159 aMap,
2160 rInfo.msTimeDate,
2161 aPageOfs,
2162 rInfo.mnDrawMode,
2163 rInfo.meOrientation,
2164 nPaperBin));
2165 aPageIndices.clear();
2170 /** Prepare the notes pages or regular slides.
2172 void PrepareStdOrNotes (
2173 const PageKind ePageKind,
2174 PrintInfo& rInfo)
2176 OSL_ASSERT(rInfo.mpPrinter != nullptr);
2178 // Fill in page kind specific data.
2179 SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
2180 if (pDocument->GetSdPageCount(ePageKind) == 0)
2181 return;
2182 SdPage* pRefPage = pDocument->GetSdPage(0, ePageKind);
2184 if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()) && mpOptions->IsNotes())
2185 rInfo.maPageSize = mpPrinter->GetPrintPageSize();
2186 else
2187 rInfo.maPageSize = pRefPage->GetSize();
2189 SetupPaperOrientation(ePageKind, rInfo);
2191 if (mpOptions->IsBooklet())
2192 PrepareBooklet(ePageKind, rInfo);
2193 else
2194 PrepareRegularPages(ePageKind, rInfo);
2197 /** Prepare slides in a non-booklet way: one slide per one to many
2198 printer pages.
2200 void PrepareRegularPages (
2201 const PageKind ePageKind,
2202 PrintInfo& rInfo)
2204 std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
2205 pViewShell->WriteFrameViewData();
2207 sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
2208 StringRangeEnumerator aRangeEnum(
2209 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
2210 0, nPageCount-1);
2211 for (StringRangeEnumerator::Iterator
2212 it = aRangeEnum.begin(),
2213 itEnd = aRangeEnum.end();
2214 it != itEnd;
2215 ++it)
2217 SdPage* pPage = GetFilteredPage(*it, ePageKind);
2218 if (pPage == nullptr)
2219 continue;
2221 MapMode aMap (rInfo.maMap);
2223 Size aPageSize = pPage->GetSize();
2225 if (mpOptions->IsPageSize())
2227 Size aPrintSize = rInfo.maPrintSize;
2228 lcl_AdjustPageSize(aPageSize, aPrintSize);
2230 const double fHorz(static_cast<double>(aPrintSize.Width()) / aPageSize.Width());
2231 const double fVert(static_cast<double>(aPrintSize.Height()) / aPageSize.Height());
2233 Fraction aFract;
2234 if (fHorz < fVert)
2235 aFract = Fraction(aPrintSize.Width(), aPageSize.Width());
2236 else
2237 aFract = Fraction(aPrintSize.Height(), aPageSize.Height());
2239 aMap.SetScaleX(aFract);
2240 aMap.SetScaleY(aFract);
2241 aMap.SetOrigin(Point());
2244 if (mpOptions->IsPrintPageName())
2246 rInfo.msPageString = pPage->GetName() + " ";
2248 else
2249 rInfo.msPageString.clear();
2250 rInfo.msPageString += rInfo.msTimeDate;
2252 ::tools::Long aPageWidth = aPageSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder();
2253 ::tools::Long aPageHeight = aPageSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder();
2254 // Bugfix for 44530:
2255 // if it was implicitly changed (Landscape/Portrait),
2256 // this is considered for tiling, respectively for the splitting up
2257 // (Poster)
2258 if( ( rInfo.maPrintSize.Width() > rInfo.maPrintSize.Height()
2259 && aPageWidth < aPageHeight )
2260 || ( rInfo.maPrintSize.Width() < rInfo.maPrintSize.Height()
2261 && aPageWidth > aPageHeight ) )
2263 const sal_Int32 nTmp (rInfo.maPrintSize.Width());
2264 rInfo.maPrintSize.setWidth( rInfo.maPrintSize.Height() );
2265 rInfo.maPrintSize.setHeight( nTmp );
2268 if (mpOptions->IsTilePage()
2269 && aPageWidth < rInfo.maPrintSize.Width()
2270 && aPageHeight < rInfo.maPrintSize.Height())
2272 // Put multiple slides on one printer page.
2273 PrepareTiledPage(*it, *pPage, ePageKind, rInfo);
2275 else
2277 rInfo.maMap = std::move(aMap);
2278 PrepareScaledPage(*it, *pPage, ePageKind, rInfo);
2283 /** Put two slides on one printer page.
2285 void PrepareBooklet (
2286 const PageKind ePageKind,
2287 const PrintInfo& rInfo)
2289 MapMode aStdMap (rInfo.maMap);
2290 Point aOffset;
2291 Size aPrintSize_2 (rInfo.maPrintSize);
2292 Size aPageSize_2 (rInfo.maPageSize);
2294 if (rInfo.meOrientation == Orientation::Landscape)
2295 aPrintSize_2.setWidth( aPrintSize_2.Width() >> 1 );
2296 else
2297 aPrintSize_2.setHeight( aPrintSize_2.Height() >> 1 );
2299 const double fPageWH = static_cast<double>(aPageSize_2.Width()) / aPageSize_2.Height();
2300 const double fPrintWH = static_cast<double>(aPrintSize_2.Width()) / aPrintSize_2.Height();
2302 if( fPageWH < fPrintWH )
2304 aPageSize_2.setWidth( static_cast<::tools::Long>( aPrintSize_2.Height() * fPageWH ) );
2305 aPageSize_2.setHeight( aPrintSize_2.Height() );
2307 else
2309 aPageSize_2.setWidth( aPrintSize_2.Width() );
2310 aPageSize_2.setHeight( static_cast<::tools::Long>( aPrintSize_2.Width() / fPageWH ) );
2313 MapMode aMap (rInfo.maMap);
2314 aMap.SetScaleX( Fraction( aPageSize_2.Width(), rInfo.maPageSize.Width() ) );
2315 aMap.SetScaleY( Fraction( aPageSize_2.Height(), rInfo.maPageSize.Height() ) );
2317 // calculate adjusted print size
2318 const Size aAdjustedPrintSize (OutputDevice::LogicToLogic(
2319 rInfo.maPrintSize,
2320 aStdMap,
2321 aMap));
2323 if (rInfo.meOrientation == Orientation::Landscape)
2325 aOffset.setX( ( ( aAdjustedPrintSize.Width() >> 1 ) - rInfo.maPageSize.Width() ) >> 1 );
2326 aOffset.setY( ( aAdjustedPrintSize.Height() - rInfo.maPageSize.Height() ) >> 1 );
2328 else
2330 aOffset.setX( ( aAdjustedPrintSize.Width() - rInfo.maPageSize.Width() ) >> 1 );
2331 aOffset.setY( ( ( aAdjustedPrintSize.Height() >> 1 ) - rInfo.maPageSize.Height() ) >> 1 );
2334 // create vector of pages to print
2335 sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(ePageKind);
2336 StringRangeEnumerator aRangeEnum(
2337 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
2338 0, nPageCount-1);
2339 std::vector< sal_uInt16 > aPageVector;
2340 for (StringRangeEnumerator::Iterator
2341 it = aRangeEnum.begin(),
2342 itEnd = aRangeEnum.end();
2343 it != itEnd;
2344 ++it)
2346 SdPage* pPage = GetFilteredPage(*it, ePageKind);
2347 if (pPage != nullptr)
2348 aPageVector.push_back(*it);
2351 // create pairs of pages to print on each page
2352 std::vector< std::pair< sal_uInt16, sal_uInt16 > > aPairVector;
2353 if ( ! aPageVector.empty())
2355 sal_uInt32 nFirstIndex = 0, nLastIndex = aPageVector.size() - 1;
2357 if( aPageVector.size() & 1 )
2358 aPairVector.emplace_back( sal_uInt16(65535), aPageVector[ nFirstIndex++ ] );
2359 else
2360 aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
2362 while( nFirstIndex < nLastIndex )
2364 if( nFirstIndex & 1 )
2365 aPairVector.emplace_back( aPageVector[ nFirstIndex++ ], aPageVector[ nLastIndex-- ] );
2366 else
2367 aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
2371 for (sal_uInt32
2372 nIndex=0,
2373 nCount=aPairVector.size();
2374 nIndex < nCount;
2375 ++nIndex)
2377 if ( CheckForFrontBackPages( nIndex ) )
2379 const std::pair<sal_uInt16, sal_uInt16> aPair (aPairVector[nIndex]);
2380 Point aSecondOffset (aOffset);
2381 if (rInfo.meOrientation == Orientation::Landscape)
2382 aSecondOffset.AdjustX( aAdjustedPrintSize.Width() / 2 );
2383 else
2384 aSecondOffset.AdjustY( aAdjustedPrintSize.Height() / 2 );
2385 maPrinterPages.push_back(
2386 std::make_shared<BookletPrinterPage>(
2387 aPair.first,
2388 aPair.second,
2389 aOffset,
2390 aSecondOffset,
2391 ePageKind,
2392 aMap,
2393 rInfo.mbPrintMarkedOnly,
2394 rInfo.mnDrawMode,
2395 rInfo.meOrientation,
2396 rInfo.mpPrinter->GetPaperBin()));
2402 /** Print one slide multiple times on one printer page so that the whole
2403 printer page is covered.
2405 void PrepareTiledPage (
2406 const sal_Int32 nPageIndex,
2407 const SdPage& rPage,
2408 const PageKind ePageKind,
2409 const PrintInfo& rInfo)
2411 sal_uInt16 nPaperBin;
2412 if ( ! mpOptions->IsPaperBin())
2413 nPaperBin = rPage.GetPaperBin();
2414 else
2415 nPaperBin = rInfo.mpPrinter->GetPaperBin();
2417 if ( !CheckForFrontBackPages( nPageIndex ) )
2418 return;
2420 maPrinterPages.push_back(
2421 std::make_shared<TiledPrinterPage>(
2422 sal::static_int_cast<sal_uInt16>(nPageIndex),
2423 ePageKind,
2424 rInfo.mbPrintMarkedOnly,
2425 rInfo.msPageString,
2426 rInfo.mpPrinter->GetPageOffset(),
2427 rInfo.mnDrawMode,
2428 rInfo.meOrientation,
2429 nPaperBin));
2432 /** Print one standard slide or notes page on one to many printer
2433 pages. More than on printer page is used when the slide is larger
2434 than the printable area.
2436 void PrepareScaledPage (
2437 const sal_Int32 nPageIndex,
2438 const SdPage& rPage,
2439 const PageKind ePageKind,
2440 const PrintInfo& rInfo)
2442 const Point aPageOffset (rInfo.mpPrinter->GetPageOffset());
2444 sal_uInt16 nPaperBin;
2445 if ( ! mpOptions->IsPaperBin())
2446 nPaperBin = rPage.GetPaperBin();
2447 else
2448 nPaperBin = rInfo.mpPrinter->GetPaperBin();
2450 // For pages larger than the printable area there are three options:
2451 // 1. Scale down to the page to the printable area.
2452 // 2. Print only the upper left part of the page (without the unprintable borders).
2453 // 3. Split the page into parts of the size of the printable area.
2454 const bool bScalePage (mpOptions->IsPageSize());
2455 const bool bCutPage (mpOptions->IsCutPage());
2456 MapMode aMap (rInfo.maMap);
2457 if ( (bScalePage || bCutPage) && CheckForFrontBackPages( nPageIndex ) )
2459 // Handle 1 and 2.
2461 // if CutPage is set then do not move it, otherwise move the
2462 // scaled page to printable area
2463 if (ePageKind == PageKind::Standard)
2465 maPrinterPages.push_back(
2466 std::make_shared<RegularPrinterPage>(
2467 sal::static_int_cast<sal_uInt16>(nPageIndex),
2468 ePageKind,
2469 aMap,
2470 rInfo.mbPrintMarkedOnly,
2471 rInfo.msPageString,
2472 aPageOffset,
2473 rInfo.mnDrawMode,
2474 rInfo.meOrientation,
2475 nPaperBin));
2477 else if (SdPage* pPage = GetFilteredPage(nPageIndex, PageKind::Notes))// Notes
2479 SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
2481 // Clone the current page to create an independent instance.
2482 // This ensures that changes made to pNotesPage do not affect the original page.
2483 rtl::Reference<SdPage> pNotesPage
2484 = static_cast<SdPage*>(pPage->CloneSdrPage(*pDocument).get());
2486 Size aPageSize = bScalePage ? pNotesPage->GetSize() : rInfo.mpPrinter->GetPrintPageSize();
2487 // Adjusts the objects on the notes page to fit the new page size.
2488 ::tools::Rectangle aNewBorderRect(-1, -1, -1, -1);
2489 pNotesPage->ScaleObjects(aPageSize, aNewBorderRect, true);
2491 SdrObject* pNotesObj = pNotesPage->GetPresObj(PresObjKind::Notes);
2492 if (pNotesObj && bCutPage)
2494 // default margins
2495 sal_Int32 nTopMargin = aPageSize.Height() * 0.075;
2496 sal_Int32 nBottomMargin = nTopMargin;
2498 Size nNotesObjSize = pNotesObj->GetLogicRect().GetSize();
2500 Outliner* pOut = pDocument->GetInternalOutliner();
2501 const OutlinerMode nSaveOutlMode(pOut->GetOutlinerMode());
2502 const bool bSavedUpdateMode(pOut->IsUpdateLayout());
2503 pOut->Init(OutlinerMode::OutlineView);
2504 pOut->SetPaperSize(nNotesObjSize);
2505 pOut->SetUpdateLayout(true);
2506 pOut->Clear();
2507 pOut->SetText(*pNotesObj->GetOutlinerParaObject());
2509 sal_Int32 nFirstPageBottomMargin = 0;
2510 ::tools::Long nNotesHeight = nNotesObjSize.Height();
2511 bool bAutoGrow = pNotesObj->GetMergedItem(SDRATTR_TEXT_AUTOGROWHEIGHT).GetValue();
2512 if (bAutoGrow)
2514 nNotesHeight += pNotesObj->GetRelativePos().Y();
2515 nFirstPageBottomMargin = (pNotesPage->GetLowerBorder() != 0)
2516 ? pNotesPage->GetLowerBorder()
2517 : nBottomMargin;
2519 double nOverflowedTextHeight = 0;
2520 ::tools::Long nFirstPageBottom = aPageSize.Height() - nFirstPageBottomMargin;
2521 if (nNotesHeight > nFirstPageBottom)
2523 // Calculate the height of the overflow text
2524 // when the AutoGrowHeight property of the notes object is enabled
2525 // and the height of the object exceeds the page height.
2526 nOverflowedTextHeight = pNotesObj->GetRelativePos().Y()
2527 + pOut->GetTextHeight() - nFirstPageBottom;
2529 else
2530 nOverflowedTextHeight = pOut->GetTextHeight() - nNotesObjSize.Height();
2532 sal_Int32 nNotePageCount = 1;
2533 double nNewPageHeight = aPageSize.Height() - nTopMargin - nBottomMargin;
2534 if (nOverflowedTextHeight > 0)
2536 nNotePageCount += std::ceil(nOverflowedTextHeight / nNewPageHeight);
2539 for (sal_Int32 i = 1; i <= nNotePageCount; i++)
2541 // set page numbers
2542 sal_Int32 nPageNumb = i;
2543 OUString sPageNumb = rInfo.msPageString;
2544 if (!sPageNumb.isEmpty() && nNotePageCount > 1)
2546 OUString sTmp;
2547 if (!rInfo.msTimeDate.isEmpty())
2549 sTmp += " ";
2551 sTmp += SdResId(STR_PAGE_NAME) + " " + OUString::number(i);
2552 sPageNumb += sTmp;
2555 maPrinterPages.push_back(
2556 std::make_shared<NotesPrinterPage>(
2557 sal::static_int_cast<sal_uInt16>(nPageIndex),
2558 nPageNumb,
2559 nNotePageCount,
2560 bScalePage,
2561 PageKind::Notes,
2562 aMap,
2563 rInfo.mbPrintMarkedOnly,
2564 sPageNumb,
2565 aPageOffset,
2566 rInfo.mnDrawMode,
2567 rInfo.meOrientation,
2568 nPaperBin));
2570 pOut->Clear();
2571 pOut->SetUpdateLayout(bSavedUpdateMode);
2572 pOut->Init(nSaveOutlMode);
2574 else // scaled page
2576 maPrinterPages.push_back(
2577 std::make_shared<NotesPrinterPage>(
2578 sal::static_int_cast<sal_uInt16>(nPageIndex),
2579 sal_Int32(0),
2580 sal_Int32(0),
2581 bScalePage,
2582 PageKind::Notes,
2583 aMap,
2584 rInfo.mbPrintMarkedOnly,
2585 rInfo.msPageString,
2586 aPageOffset,
2587 rInfo.mnDrawMode,
2588 rInfo.meOrientation,
2589 nPaperBin));
2593 else
2595 // Handle 3. Print parts of the page in the size of the
2596 // printable area until the whole page is covered.
2598 // keep the page content at its position if it fits, otherwise
2599 // move it to the printable area
2600 const ::tools::Long nPageWidth (
2601 rInfo.maPageSize.Width() - rPage.GetLeftBorder() - rPage.GetRightBorder());
2602 const ::tools::Long nPageHeight (
2603 rInfo.maPageSize.Height() - rPage.GetUpperBorder() - rPage.GetLowerBorder());
2605 Point aOrigin ( 0, 0 );
2607 for (Point aPageOrigin = aOrigin;
2608 -aPageOrigin.Y()<nPageHeight;
2609 aPageOrigin.AdjustY( -rInfo.maPrintSize.Height() ))
2611 for (aPageOrigin.setX(aOrigin.X());
2612 -aPageOrigin.X()<nPageWidth;
2613 aPageOrigin.AdjustX(-rInfo.maPrintSize.Width()))
2615 if ( CheckForFrontBackPages( nPageIndex ) )
2617 aMap.SetOrigin(aPageOrigin);
2618 maPrinterPages.push_back(
2619 std::make_shared<RegularPrinterPage>(
2620 sal::static_int_cast<sal_uInt16>(nPageIndex),
2621 ePageKind,
2622 aMap,
2623 rInfo.mbPrintMarkedOnly,
2624 rInfo.msPageString,
2625 aPageOffset,
2626 rInfo.mnDrawMode,
2627 rInfo.meOrientation,
2628 nPaperBin));
2635 bool CheckForFrontBackPages( sal_Int32 nPage )
2637 const bool bIsIndexOdd(nPage & 1);
2638 if ((!bIsIndexOdd && mpOptions->IsPrintFrontPage())
2639 || (bIsIndexOdd && mpOptions->IsPrintBackPage()))
2641 return true;
2643 else
2644 return false;
2648 //===== DocumentRenderer ======================================================
2650 DocumentRenderer::DocumentRenderer (ViewShellBase& rBase)
2651 : mpImpl(new Implementation(rBase))
2655 DocumentRenderer::~DocumentRenderer()
2659 //----- XRenderable -----------------------------------------------------------
2661 sal_Int32 SAL_CALL DocumentRenderer::getRendererCount (
2662 const css::uno::Any&,
2663 const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
2665 mpImpl->ProcessProperties(rOptions);
2666 return mpImpl->GetPrintPageCount();
2669 Sequence<beans::PropertyValue> SAL_CALL DocumentRenderer::getRenderer (
2670 sal_Int32,
2671 const css::uno::Any&,
2672 const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
2674 mpImpl->ProcessProperties(rOptions);
2675 return mpImpl->GetProperties();
2678 void SAL_CALL DocumentRenderer::render (
2679 sal_Int32 nRenderer,
2680 const css::uno::Any&,
2681 const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
2683 mpImpl->ProcessProperties(rOptions);
2684 mpImpl->PrintPage(nRenderer);
2687 } // end of namespace sd
2689 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */