android: Update app-specific/MIME type icons
[LibreOffice.git] / sd / source / ui / view / DocumentRenderer.cxx
blob7ca62d9daa1b832431cb608a5094963e6b110e08
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/outlobj.hxx>
47 #include <svx/svdetc.hxx>
48 #include <svx/svditer.hxx>
49 #include <svx/svdopage.hxx>
50 #include <svx/svdopath.hxx>
51 #include <svx/svdpagv.hxx>
52 #include <svx/xlineit0.hxx>
53 #include <svx/xlnclit.hxx>
54 #include <toolkit/awt/vclxdevice.hxx>
55 #include <unotools/localedatawrapper.hxx>
56 #include <utility>
57 #include <vcl/print.hxx>
58 #include <vcl/svapp.hxx>
59 #include <vcl/weld.hxx>
60 #include <unotools/moduleoptions.hxx>
61 #include <xmloff/autolayout.hxx>
62 #include <sfx2/objsh.hxx>
64 #include <officecfg/Office/Draw.hxx>
65 #include <officecfg/Office/Impress.hxx>
67 #include <algorithm>
68 #include <memory>
69 #include <vector>
71 using namespace ::com::sun::star;
72 using namespace ::com::sun::star::uno;
74 namespace sd {
76 namespace {
78 /** Convenience class to extract values from the sequence of properties
79 given to one of the XRenderable methods.
81 class PrintOptions
83 public:
84 PrintOptions (
85 const vcl::PrinterOptionsHelper& rHelper,
86 std::vector<sal_Int32>&& rSlidesPerPage)
87 : mrProperties(rHelper),
88 maSlidesPerPage(std::move(rSlidesPerPage))
92 bool IsWarningOrientation() const
94 return GetBoolValue(nullptr, true);
97 bool IsPrintPageName() const
99 return GetBoolValue("IsPrintName", false);
102 bool IsDate() const
104 return GetBoolValue("IsPrintDateTime", false);
107 bool IsTime() const
109 return GetBoolValue("IsPrintDateTime", false);
112 bool IsHiddenPages() const
114 return GetBoolValue("IsPrintHidden", false);
117 bool IsHandoutHorizontal() const
119 return GetBoolValue("SlidesPerPageOrder", sal_Int32(0));
122 sal_Int32 GetHandoutPageCount() const
124 sal_uInt32 nIndex = static_cast<sal_Int32>(mrProperties.getIntValue("SlidesPerPage", sal_Int32(0)));
125 if (nIndex<maSlidesPerPage.size())
126 return maSlidesPerPage[nIndex];
127 else if ( ! maSlidesPerPage.empty())
128 return maSlidesPerPage[0];
129 else
130 return 0;
133 bool IsDraw() const
135 return GetBoolValue("PageContentType", sal_Int32(0));
138 bool IsHandout() const
140 return GetBoolValue("PageContentType", sal_Int32(1));
143 bool IsNotes() const
145 return GetBoolValue("PageContentType", sal_Int32(2));
148 bool IsOutline() const
150 return GetBoolValue("PageContentType", sal_Int32(3));
153 sal_uLong GetOutputQuality() const
155 sal_Int32 nQuality = static_cast<sal_Int32>(mrProperties.getIntValue( "Quality", sal_Int32(0) ));
156 return nQuality;
159 bool IsPageSize() const
161 return GetBoolValue("PageOptions", sal_Int32(1));
164 bool IsTilePage() const
166 return GetBoolValue("PageOptions", sal_Int32(2)) || GetBoolValue("PageOptions", sal_Int32(3));
169 bool IsCutPage() const
171 return GetBoolValue("PageOptions", sal_Int32(0));
174 bool IsBooklet() const
176 return GetBoolValue("PrintProspect", false);
179 bool IsPrinterPreferred(DocumentType eDocType) const
181 bool bIsDraw = eDocType == DocumentType::Draw;
182 return IsTilePage() || IsPageSize() || IsBooklet() || (!bIsDraw && !IsNotes());
185 bool IsPrintExcluded() const
187 return (IsNotes() || IsDraw() || IsHandout()) && IsHiddenPages();
190 bool IsPrintFrontPage() const
192 sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
193 return nInclude != 2;
196 bool IsPrintBackPage() const
198 sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
199 return nInclude != 1;
202 bool IsPaperBin() const
204 return GetBoolValue("PrintPaperFromSetup", false);
207 bool IsPrintMarkedOnly() const
209 return GetBoolValue("PrintContent", sal_Int32(4));
212 OUString GetPrinterSelection (sal_Int32 nPageCount, sal_Int32 nCurrentPageIndex) const
214 sal_Int32 nContent = static_cast<sal_Int32>(mrProperties.getIntValue( "PrintContent", 0 ));
215 OUString sFullRange = "1-" + OUString::number(nPageCount);
217 if (nContent == 0) // all pages/slides
219 return sFullRange;
222 if (nContent == 1) // range
224 OUString sValue = mrProperties.getStringValue("PageRange");
225 return sValue.isEmpty() ? sFullRange : sValue;
228 if (nContent == 2 && // selection
229 nCurrentPageIndex >= 0)
231 return OUString::number(nCurrentPageIndex + 1);
234 return OUString();
237 private:
238 const vcl::PrinterOptionsHelper& mrProperties;
239 const std::vector<sal_Int32> maSlidesPerPage;
241 /** When the value of the property with name pName is a boolean then
242 return its value. When the property is unknown then
243 bDefaultValue is returned. Otherwise <FALSE/> is returned.
245 bool GetBoolValue (
246 const char* pName,
247 const bool bDefaultValue) const
249 bool bValue = mrProperties.getBoolValue( pName, bDefaultValue );
250 return bValue;
253 /** Return <TRUE/> when the value of the property with name pName is
254 an integer and its value is nTriggerValue. Otherwise <FALSE/> is
255 returned.
257 bool GetBoolValue (
258 const char* pName,
259 const sal_Int32 nTriggerValue) const
261 sal_Int32 nValue = static_cast<sal_Int32>(mrProperties.getIntValue( pName, 0 ));
262 return nValue == nTriggerValue;
266 /** A collection of values that helps to reduce the number of arguments
267 given to some functions. Note that not all values are set at the
268 same time.
270 class PrintInfo
272 public:
273 PrintInfo (
274 Printer* pPrinter,
275 const bool bPrintMarkedOnly)
276 : mpPrinter(pPrinter),
277 mnDrawMode(DrawModeFlags::Default),
278 maPrintSize(0,0),
279 maPageSize(0,0),
280 meOrientation(Orientation::Portrait),
281 mbPrintMarkedOnly(bPrintMarkedOnly)
284 const VclPtr<Printer> mpPrinter;
285 DrawModeFlags mnDrawMode;
286 OUString msTimeDate;
287 OUString msPageString;
288 Size maPrintSize;
289 Size maPageSize;
290 Orientation meOrientation;
291 MapMode maMap;
292 const bool mbPrintMarkedOnly;
295 /** Output one page of the document to the given printer. Note that
296 more than one document page may be output to one printer page.
298 void PrintPage (
299 Printer& rPrinter,
300 ::sd::View& rPrintView,
301 SdPage& rPage,
302 View const * pView,
303 const bool bPrintMarkedOnly,
304 const SdrLayerIDSet& rVisibleLayers,
305 const SdrLayerIDSet& rPrintableLayers)
307 rPrintView.ShowSdrPage(&rPage);
309 const MapMode aOriginalMapMode (rPrinter.GetMapMode());
311 // Set the visible layers
312 SdrPageView* pPageView = rPrintView.GetSdrPageView();
313 OSL_ASSERT(pPageView!=nullptr);
314 pPageView->SetVisibleLayers(rVisibleLayers);
315 pPageView->SetPrintableLayers(rPrintableLayers);
317 if (pView!=nullptr && bPrintMarkedOnly)
318 pView->DrawMarkedObj(rPrinter);
319 else
320 rPrintView.CompleteRedraw(&rPrinter,
321 vcl::Region(::tools::Rectangle(Point(0,0), rPage.GetSize())));
323 rPrinter.SetMapMode(aOriginalMapMode);
325 rPrintView.HideSdrPage();
328 /** Output a string (that typically is not part of a document page) to
329 the given printer.
331 void PrintMessage (
332 Printer& rPrinter,
333 const OUString& rsPageString,
334 const Point& rPageStringOffset)
336 const vcl::Font aOriginalFont (rPrinter.OutputDevice::GetFont());
337 rPrinter.SetFont(vcl::Font(FAMILY_SWISS, Size(0, 423)));
338 rPrinter.DrawText(rPageStringOffset, rsPageString);
339 rPrinter.SetFont(aOriginalFont);
342 /** Read the resources and process then into a sequence of properties
343 that can be passed to the printing dialog.
345 class DialogCreator
347 public:
348 DialogCreator (ViewShellBase &rBase, bool bImpress, sal_Int32 nCurPage)
349 : mrBase(rBase)
350 , mbImpress(bImpress)
351 , mnCurPage(nCurPage)
353 ProcessResource();
356 const std::vector< beans::PropertyValue >& GetDialogControls() const
358 return maProperties;
361 const std::vector<sal_Int32>& GetSlidesPerPage() const
363 return maSlidesPerPage;
366 private:
367 ViewShellBase &mrBase;
368 std::vector<beans::PropertyValue> maProperties;
369 std::vector<sal_Int32> maSlidesPerPage;
370 bool mbImpress;
371 sal_Int32 mnCurPage;
373 void ProcessResource()
375 // load the writer PrinterOptions into the custom tab
376 beans::PropertyValue aOptionsUIFile;
377 aOptionsUIFile.Name = "OptionsUIFile";
378 if( mbImpress )
379 aOptionsUIFile.Value <<= OUString("modules/simpress/ui/impressprinteroptions.ui");
380 else
381 aOptionsUIFile.Value <<= OUString("modules/sdraw/ui/drawprinteroptions.ui");
382 maProperties.push_back(aOptionsUIFile);
384 SvtModuleOptions aOpt;
385 OUString aAppGroupname(SdResId(STR_IMPRESS_PRINT_UI_GROUP_NAME));
386 aAppGroupname = aAppGroupname.replaceFirst("%s", aOpt.GetModuleName(
387 mbImpress ? SvtModuleOptions::EModule::IMPRESS : SvtModuleOptions::EModule::DRAW));
388 AddDialogControl(vcl::PrinterOptionsHelper::setGroupControlOpt("tabcontrol-page2", aAppGroupname, ".HelpID:vcl:PrintDialog:TabPage:AppPage"));
390 uno::Sequence< OUString > aHelpIds, aWidgetIds;
391 if( mbImpress )
393 aHelpIds = { ".HelpID:vcl:PrintDialog:PageContentType:ListBox" };
394 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
395 "impressdocument",
396 SdResId(STR_IMPRESS_PRINT_UI_CONTENT),
397 aHelpIds,
398 "PageContentType" ,
399 CreateChoice(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES)),
403 aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPage:ListBox" };
404 vcl::PrinterOptionsHelper::UIControlOptions aContentOpt( "PageContentType" , 1 );
405 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
406 "slidesperpage",
407 SdResId(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE),
408 aHelpIds,
409 "SlidesPerPage" ,
410 GetSlidesPerPageSequence(),
412 Sequence< sal_Bool >(),
413 aContentOpt
417 aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPageOrder:ListBox" };
418 vcl::PrinterOptionsHelper::UIControlOptions aSlidesPerPageOpt( "SlidesPerPage" , -1, true );
419 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
420 "slidesperpageorder",
421 SdResId(STR_IMPRESS_PRINT_UI_ORDER),
422 aHelpIds,
423 "SlidesPerPageOrder" ,
424 CreateChoice(STR_IMPRESS_PRINT_UI_ORDER_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_ORDER_CHOICES)),
426 Sequence< sal_Bool >(),
427 aSlidesPerPageOpt )
431 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("contents",
432 SdResId(STR_IMPRESS_PRINT_UI_INCLUDE_CONTENT), "" ) );
434 if( mbImpress )
436 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname",
437 SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_NAME),
438 ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" ,
439 "IsPrintName" ,
440 officecfg::Office::Impress::Print::Other::PageName::get()
444 else
446 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname",
447 SdResId(STR_DRAW_PRINT_UI_IS_PRINT_NAME),
448 ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" ,
449 "IsPrintName" ,
450 officecfg::Office::Draw::Print::Other::PageName::get()
455 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printdatetime",
456 SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_DATE),
457 ".HelpID:vcl:PrintDialog:IsPrintDateTime:CheckBox" ,
458 "IsPrintDateTime" ,
459 // Separate settings for time and date in Impress/Draw -> Print page, check that both are set
460 mbImpress ?
461 officecfg::Office::Impress::Print::Other::Date::get() &&
462 officecfg::Office::Impress::Print::Other::Time::get() :
463 officecfg::Office::Draw::Print::Other::Date::get() &&
464 officecfg::Office::Draw::Print::Other::Time::get()
468 if( mbImpress )
470 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printhidden",
471 SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_HIDDEN),
472 ".HelpID:vcl:PrintDialog:IsPrintHidden:CheckBox" ,
473 "IsPrintHidden" ,
474 officecfg::Office::Impress::Print::Other::HiddenPage::get()
479 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("color",
480 SdResId(STR_IMPRESS_PRINT_UI_QUALITY), "" ) );
482 aHelpIds = { ".HelpID:vcl:PrintDialog:Quality:RadioButton:0",
483 ".HelpID:vcl:PrintDialog:Quality:RadioButton:1",
484 ".HelpID:vcl:PrintDialog:Quality:RadioButton:2" };
485 aWidgetIds = { "originalcolors", "grayscale", "blackandwhite" };
486 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
487 aWidgetIds,
489 aHelpIds,
490 "Quality" ,
491 CreateChoice(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES)),
492 mbImpress ? officecfg::Office::Impress::Print::Other::Quality::get() :
493 officecfg::Office::Draw::Print::Other::Quality::get() )
497 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesizes",
498 SdResId(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS), "" ) );
500 aHelpIds = { ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:0",
501 ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:1",
502 ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:2",
503 ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:3" };
504 aWidgetIds = { "originalsize", "fittoprintable", "distributeonmultiple", "tilesheet" };
506 // Mutually exclusive page options settings are stored in separate config keys...
507 // TODO: There is no config key to set the distributeonmultiple option as default
508 sal_Int32 nDefaultChoice = 0;
509 if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageSize::get() :
510 officecfg::Office::Draw::Print::Page::PageSize::get() )
512 nDefaultChoice = 1;
514 else if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageTile::get() :
515 officecfg::Office::Draw::Print::Page::PageTile::get() )
517 nDefaultChoice = 3;
519 vcl::PrinterOptionsHelper::UIControlOptions aPageOptionsOpt("PrintProspect", 0);
520 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
521 aWidgetIds,
523 aHelpIds,
524 "PageOptions" ,
525 mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES)) :
526 CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW)),
527 nDefaultChoice,
528 Sequence< sal_Bool >(),
529 aPageOptionsOpt
533 vcl::PrinterOptionsHelper::UIControlOptions aBrochureOpt;
534 aBrochureOpt.maGroupHint = "LayoutPage" ;
535 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesides",
536 SdResId(STR_IMPRESS_PRINT_UI_PAGE_SIDES), "",
537 aBrochureOpt ) );
539 // brochure printing
540 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("brochure",
541 SdResId(STR_IMPRESS_PRINT_UI_BROCHURE),
542 ".HelpID:vcl:PrintDialog:PrintProspect:CheckBox" ,
543 "PrintProspect" ,
544 mbImpress ? officecfg::Office::Impress::Print::Page::Booklet::get() :
545 officecfg::Office::Draw::Print::Page::Booklet::get(),
546 aBrochureOpt
550 vcl::PrinterOptionsHelper::UIControlOptions
551 aIncludeOpt( "PrintProspect" , -1, false );
552 aIncludeOpt.maGroupHint = "LayoutPage" ;
553 aHelpIds = { ".HelpID:vcl:PrintDialog:PrintProspectInclude:ListBox" };
554 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
555 "brochureinclude",
556 SdResId(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE),
557 aHelpIds,
558 "PrintProspectInclude" ,
559 CreateChoice(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST)),
561 Sequence< sal_Bool >(),
562 aIncludeOpt
566 // paper tray (on options page)
567 vcl::PrinterOptionsHelper::UIControlOptions aPaperTrayOpt;
568 aPaperTrayOpt.maGroupHint = "OptionsPageOptGroup" ;
569 AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printpaperfromsetup",
570 SdResId(STR_IMPRESS_PRINT_UI_PAPER_TRAY),
571 ".HelpID:vcl:PrintDialog:PrintPaperFromSetup:CheckBox" ,
572 "PrintPaperFromSetup" ,
573 false,
574 aPaperTrayOpt
577 // print range selection
578 vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
579 aPrintRangeOpt.mbInternalOnly = true;
580 aPrintRangeOpt.maGroupHint = "PrintRange" ;
581 AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("printrange",
582 mbImpress ? SdResId(STR_IMPRESS_PRINT_UI_SLIDE_RANGE) : SdResId(STR_IMPRESS_PRINT_UI_PAGE_RANGE),
584 aPrintRangeOpt )
587 // check if there is a selection of slides
588 OUString aPageRange(OUString::number(mnCurPage + 1));
589 int nPrintRange(0);
590 using sd::slidesorter::SlideSorterViewShell;
591 SlideSorterViewShell* const pSSViewSh(SlideSorterViewShell::GetSlideSorter(mrBase));
592 if (pSSViewSh)
594 const std::shared_ptr<SlideSorterViewShell::PageSelection> pPageSelection(pSSViewSh->GetPageSelection());
595 if (bool(pPageSelection) && pPageSelection->size() > 1)
597 OUStringBuffer aBuf;
598 // TODO: this could be improved by writing ranges instead of consecutive page
599 // numbers if appropriate. Do we have a helper function for that somewhere?
600 bool bFirst(true);
601 for (auto pPage: *pPageSelection)
603 if (bFirst)
604 bFirst = false;
605 else
606 aBuf.append(',');
607 aBuf.append(static_cast<sal_Int32>(pPage->GetPageNum() / 2 + 1));
609 aPageRange = aBuf.makeStringAndClear();
610 nPrintRange = 1;
614 OUString aPrintRangeName( "PrintContent" );
615 aHelpIds.realloc( 1 );
616 aHelpIds[0] = ".HelpID:vcl:PrintDialog:PageContentType:ListBox";
617 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( "printpagesbox", OUString(),
618 aHelpIds, aPrintRangeName,
619 mbImpress ? CreateChoice( STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE ) ) :
620 CreateChoice( STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE ) ),
621 nPrintRange ) );
623 OUString aPrintRangeName( "PrintContent" );
624 aHelpIds = { ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0",
625 ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1",
626 ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:2" };
627 aWidgetIds = { "rbAllPages", "rbRangePages", "rbRangeSelection" };
629 AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(aWidgetIds, OUString(),
630 aHelpIds, aPrintRangeName,
631 mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE)) :
632 CreateChoice(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE)),
633 nPrintRange )
635 // create an Edit dependent on "Pages" selected
636 vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
637 AddDialogControl(vcl::PrinterOptionsHelper::setEditControlOpt("pagerange", "",
638 ".HelpID:vcl:PrintDialog:PageRange:Edit", "PageRange",
639 aPageRange, aPageRangeOpt));
640 vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, -1, true);
641 AddDialogControl(vcl::PrinterOptionsHelper::setChoiceListControlOpt("evenoddbox", "",
642 uno::Sequence<OUString>(), "EvenOdd", uno::Sequence<OUString>(),
643 0, uno::Sequence<sal_Bool>(), aEvenOddOpt));
646 void AddDialogControl( const Any& i_rCtrl )
648 beans::PropertyValue aVal;
649 aVal.Value = i_rCtrl;
650 maProperties.push_back( aVal );
653 static Sequence<OUString> CreateChoice(const TranslateId* pResourceId, size_t nCount)
655 Sequence<OUString> aChoices (nCount);
656 std::transform(pResourceId, pResourceId + nCount, aChoices.getArray(),
657 [](const auto& id) { return SdResId(id); });
658 return aChoices;
661 Sequence<OUString> GetSlidesPerPageSequence()
663 const Sequence<OUString> aChoice (
664 CreateChoice(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES)));
665 maSlidesPerPage.clear();
666 maSlidesPerPage.push_back(0); // first is using the default
667 std::transform(std::next(aChoice.begin()), aChoice.end(), std::back_inserter(maSlidesPerPage),
668 [](const OUString& rChoice) -> sal_Int32 { return rChoice.toInt32(); });
669 return aChoice;
673 /** The Prepare... methods of the DocumentRenderer::Implementation class
674 create a set of PrinterPage objects that contain all necessary
675 information to do the actual printing. There is one PrinterPage
676 object per printed page. Derived classes implement the actual, mode
677 specific printing.
679 This and all derived classes support the asynchronous printing
680 process by not storing pointers to any data with lifetime shorter
681 than the PrinterPage objects, i.e. slides, shapes, (one of) the
682 outliner (of the document).
684 class PrinterPage
686 public:
687 PrinterPage (
688 const PageKind ePageKind,
689 const MapMode& rMapMode,
690 const bool bPrintMarkedOnly,
691 OUString sPageString,
692 const Point& rPageStringOffset,
693 const DrawModeFlags nDrawMode,
694 const Orientation eOrientation,
695 const sal_uInt16 nPaperTray)
696 : mePageKind(ePageKind),
697 maMap(rMapMode),
698 mbPrintMarkedOnly(bPrintMarkedOnly),
699 msPageString(std::move(sPageString)),
700 maPageStringOffset(rPageStringOffset),
701 mnDrawMode(nDrawMode),
702 meOrientation(eOrientation),
703 mnPaperTray(nPaperTray)
707 virtual ~PrinterPage() {}
709 virtual void Print (
710 Printer& rPrinter,
711 SdDrawDocument& rDocument,
712 ViewShell& rViewShell,
713 View* pView,
714 DrawView& rPrintView,
715 const SdrLayerIDSet& rVisibleLayers,
716 const SdrLayerIDSet& rPrintableLayers) const = 0;
718 DrawModeFlags GetDrawMode() const { return mnDrawMode; }
719 Orientation GetOrientation() const { return meOrientation; }
720 sal_uInt16 GetPaperTray() const { return mnPaperTray; }
722 protected:
723 const PageKind mePageKind;
724 const MapMode maMap;
725 const bool mbPrintMarkedOnly;
726 const OUString msPageString;
727 const Point maPageStringOffset;
728 const DrawModeFlags mnDrawMode;
729 const Orientation meOrientation;
730 const sal_uInt16 mnPaperTray;
733 /** The RegularPrinterPage is used for printing one regular slide (no
734 notes, handout, or outline) to one printer page.
736 class RegularPrinterPage : public PrinterPage
738 public:
739 RegularPrinterPage (
740 const sal_uInt16 nPageIndex,
741 const PageKind ePageKind,
742 const MapMode& rMapMode,
743 const bool bPrintMarkedOnly,
744 const OUString& rsPageString,
745 const Point& rPageStringOffset,
746 const DrawModeFlags nDrawMode,
747 const Orientation eOrientation,
748 const sal_uInt16 nPaperTray)
749 : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString,
750 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
751 mnPageIndex(nPageIndex)
755 virtual void Print (
756 Printer& rPrinter,
757 SdDrawDocument& rDocument,
758 ViewShell&,
759 View* pView,
760 DrawView& rPrintView,
761 const SdrLayerIDSet& rVisibleLayers,
762 const SdrLayerIDSet& rPrintableLayers) const override
764 SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
765 rPrinter.SetMapMode(maMap);
766 PrintPage(
767 rPrinter,
768 rPrintView,
769 *pPageToPrint,
770 pView,
771 mbPrintMarkedOnly,
772 rVisibleLayers,
773 rPrintableLayers);
774 PrintMessage(
775 rPrinter,
776 msPageString,
777 maPageStringOffset);
780 private:
781 const sal_uInt16 mnPageIndex;
784 /** Print one slide multiple times on a printer page so that the whole
785 printer page is covered.
787 class TiledPrinterPage : public PrinterPage
789 public:
790 TiledPrinterPage (
791 const sal_uInt16 nPageIndex,
792 const PageKind ePageKind,
793 const bool bPrintMarkedOnly,
794 const OUString& rsPageString,
795 const Point& rPageStringOffset,
796 const DrawModeFlags nDrawMode,
797 const Orientation eOrientation,
798 const sal_uInt16 nPaperTray)
799 : PrinterPage(ePageKind, MapMode(), bPrintMarkedOnly, rsPageString,
800 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
801 mnPageIndex(nPageIndex)
805 virtual void Print (
806 Printer& rPrinter,
807 SdDrawDocument& rDocument,
808 ViewShell&,
809 View* pView,
810 DrawView& rPrintView,
811 const SdrLayerIDSet& rVisibleLayers,
812 const SdrLayerIDSet& rPrintableLayers) const override
814 SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
815 if (pPageToPrint==nullptr)
816 return;
817 MapMode aMap (rPrinter.GetMapMode());
819 const Size aPageSize (pPageToPrint->GetSize());
820 const Size aPrintSize (rPrinter.GetOutputSize());
822 const sal_Int32 nPageWidth (aPageSize.Width() + mnGap
823 - pPageToPrint->GetLeftBorder() - pPageToPrint->GetRightBorder());
824 const sal_Int32 nPageHeight (aPageSize.Height() + mnGap
825 - pPageToPrint->GetUpperBorder() - pPageToPrint->GetLowerBorder());
826 if (nPageWidth<=0 || nPageHeight<=0)
827 return;
829 // Print at least two rows and columns. More if the document
830 // page fits completely onto the printer page.
831 const sal_Int32 nColumnCount (std::max(sal_Int32(2),
832 sal_Int32(aPrintSize.Width() / nPageWidth)));
833 const sal_Int32 nRowCount (std::max(sal_Int32(2),
834 sal_Int32(aPrintSize.Height() / nPageHeight)));
835 for (sal_Int32 nRow=0; nRow<nRowCount; ++nRow)
836 for (sal_Int32 nColumn=0; nColumn<nColumnCount; ++nColumn)
838 aMap.SetOrigin(Point(nColumn*nPageWidth,nRow*nPageHeight));
839 rPrinter.SetMapMode(aMap);
840 PrintPage(
841 rPrinter,
842 rPrintView,
843 *pPageToPrint,
844 pView,
845 mbPrintMarkedOnly,
846 rVisibleLayers,
847 rPrintableLayers);
850 PrintMessage(
851 rPrinter,
852 msPageString,
853 maPageStringOffset);
856 private:
857 const sal_uInt16 mnPageIndex;
858 static const sal_Int32 mnGap = 500;
861 /** Print two slides to one printer page so that the resulting pages
862 form a booklet.
864 class BookletPrinterPage : public PrinterPage
866 public:
867 BookletPrinterPage (
868 const sal_uInt16 nFirstPageIndex,
869 const sal_uInt16 nSecondPageIndex,
870 const Point& rFirstOffset,
871 const Point& rSecondOffset,
872 const PageKind ePageKind,
873 const MapMode& rMapMode,
874 const bool bPrintMarkedOnly,
875 const DrawModeFlags nDrawMode,
876 const Orientation eOrientation,
877 const sal_uInt16 nPaperTray)
878 : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, "",
879 Point(), nDrawMode, eOrientation, nPaperTray),
880 mnFirstPageIndex(nFirstPageIndex),
881 mnSecondPageIndex(nSecondPageIndex),
882 maFirstOffset(rFirstOffset),
883 maSecondOffset(rSecondOffset)
887 virtual void Print (
888 Printer& rPrinter,
889 SdDrawDocument& rDocument,
890 ViewShell&,
891 View* pView,
892 DrawView& rPrintView,
893 const SdrLayerIDSet& rVisibleLayers,
894 const SdrLayerIDSet& rPrintableLayers) const override
896 MapMode aMap (maMap);
897 SdPage* pPageToPrint = rDocument.GetSdPage(mnFirstPageIndex, mePageKind);
898 if (pPageToPrint)
900 aMap.SetOrigin(maFirstOffset);
901 rPrinter.SetMapMode(aMap);
902 PrintPage(
903 rPrinter,
904 rPrintView,
905 *pPageToPrint,
906 pView,
907 mbPrintMarkedOnly,
908 rVisibleLayers,
909 rPrintableLayers);
912 pPageToPrint = rDocument.GetSdPage(mnSecondPageIndex, mePageKind);
913 if( !pPageToPrint )
914 return;
916 aMap.SetOrigin(maSecondOffset);
917 rPrinter.SetMapMode(aMap);
918 PrintPage(
919 rPrinter,
920 rPrintView,
921 *pPageToPrint,
922 pView,
923 mbPrintMarkedOnly,
924 rVisibleLayers,
925 rPrintableLayers);
928 private:
929 const sal_uInt16 mnFirstPageIndex;
930 const sal_uInt16 mnSecondPageIndex;
931 const Point maFirstOffset;
932 const Point maSecondOffset;
935 /** One handout page displays one to nine slides.
937 class HandoutPrinterPage : public PrinterPage
939 public:
940 HandoutPrinterPage (
941 const sal_uInt16 nHandoutPageIndex,
942 std::vector<sal_uInt16>&& rPageIndices,
943 const MapMode& rMapMode,
944 const OUString& rsPageString,
945 const Point& rPageStringOffset,
946 const DrawModeFlags nDrawMode,
947 const Orientation eOrientation,
948 const sal_uInt16 nPaperTray)
949 : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
950 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
951 mnHandoutPageIndex(nHandoutPageIndex),
952 maPageIndices(std::move(rPageIndices))
956 virtual void Print (
957 Printer& rPrinter,
958 SdDrawDocument& rDocument,
959 ViewShell& rViewShell,
960 View* pView,
961 DrawView& rPrintView,
962 const SdrLayerIDSet& rVisibleLayers,
963 const SdrLayerIDSet& rPrintableLayers) const override
965 SdPage& rHandoutPage (*rDocument.GetSdPage(0, PageKind::Handout));
967 Reference< css::beans::XPropertySet > xHandoutPage( rHandoutPage.getUnoPage(), UNO_QUERY );
968 static const OUStringLiteral sPageNumber( u"Number" );
970 // Collect the page objects of the handout master.
971 std::vector<SdrPageObj*> aHandoutPageObjects;
972 SdrObjListIter aShapeIter (&rHandoutPage);
973 while (aShapeIter.IsMore())
975 SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
976 if (pPageObj)
977 aHandoutPageObjects.push_back(pPageObj);
979 if (aHandoutPageObjects.empty())
980 return;
982 // Connect page objects with pages.
983 std::vector<SdrPageObj*>::iterator aPageObjIter (aHandoutPageObjects.begin());
984 for (std::vector<sal_uInt16>::const_iterator
985 iPageIndex(maPageIndices.begin()),
986 iEnd(maPageIndices.end());
987 iPageIndex!=iEnd && aPageObjIter!=aHandoutPageObjects.end();
988 ++iPageIndex)
990 // Check if the page still exists.
991 if (*iPageIndex >= rDocument.GetSdPageCount(PageKind::Standard))
992 continue;
994 SdrPageObj* pPageObj = *aPageObjIter++;
995 pPageObj->SetReferencedPage(rDocument.GetSdPage(*iPageIndex, PageKind::Standard));
998 // if there are more page objects than pages left, set the rest to invisible
999 int nHangoverCount = 0;
1000 while (aPageObjIter != aHandoutPageObjects.end())
1002 (*aPageObjIter++)->SetReferencedPage(nullptr);
1003 nHangoverCount++;
1006 // Hide outlines for objects that have pages attached.
1007 if (nHangoverCount > 0)
1009 int nSkip = aHandoutPageObjects.size() - nHangoverCount;
1010 aShapeIter.Reset();
1011 while (aShapeIter.IsMore())
1013 SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
1014 if (pPathObj)
1016 if (nSkip > 0)
1017 --nSkip;
1018 else
1019 pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
1024 if( xHandoutPage.is() ) try
1026 xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(mnHandoutPageIndex) ) );
1028 catch( Exception& )
1031 rViewShell.SetPrintedHandoutPageNum( mnHandoutPageIndex + 1 );
1033 rPrinter.SetMapMode(maMap);
1035 PrintPage(
1036 rPrinter,
1037 rPrintView,
1038 rHandoutPage,
1039 pView,
1040 false,
1041 rVisibleLayers,
1042 rPrintableLayers);
1043 PrintMessage(
1044 rPrinter,
1045 msPageString,
1046 maPageStringOffset);
1048 if( xHandoutPage.is() ) try
1050 xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(0) ) );
1052 catch( Exception& )
1055 rViewShell.SetPrintedHandoutPageNum(1);
1057 // Restore outlines.
1058 if (nHangoverCount > 0)
1060 aShapeIter.Reset();
1061 while (aShapeIter.IsMore())
1063 SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
1064 if (pPathObj != nullptr)
1065 pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
1071 private:
1072 const sal_uInt16 mnHandoutPageIndex;
1073 const std::vector<sal_uInt16> maPageIndices;
1076 /** The outline information (title, subtitle, outline objects) of the
1077 document. There is no fixed mapping of slides to printer pages.
1079 class OutlinerPrinterPage : public PrinterPage
1081 public:
1082 OutlinerPrinterPage (
1083 std::optional<OutlinerParaObject> pParaObject,
1084 const MapMode& rMapMode,
1085 const OUString& rsPageString,
1086 const Point& rPageStringOffset,
1087 const DrawModeFlags nDrawMode,
1088 const Orientation eOrientation,
1089 const sal_uInt16 nPaperTray)
1090 : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
1091 rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
1092 mpParaObject(std::move(pParaObject))
1096 virtual void Print (
1097 Printer& rPrinter,
1098 SdDrawDocument& rDocument,
1099 ViewShell&,
1100 View*,
1101 DrawView&,
1102 const SdrLayerIDSet&,
1103 const SdrLayerIDSet&) const override
1105 // Set up the printer.
1106 rPrinter.SetMapMode(maMap);
1108 // Get and set up the outliner.
1109 const ::tools::Rectangle aOutRect (rPrinter.GetPageOffset(), rPrinter.GetOutputSize());
1110 Outliner* pOutliner = rDocument.GetInternalOutliner();
1111 const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
1112 const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
1113 const Size aSavedPaperSize (pOutliner->GetPaperSize());
1115 pOutliner->Init(OutlinerMode::OutlineView);
1116 pOutliner->SetPaperSize(aOutRect.GetSize());
1117 pOutliner->SetUpdateLayout(true);
1118 pOutliner->Clear();
1119 pOutliner->SetText(*mpParaObject);
1121 pOutliner->Draw(rPrinter, aOutRect);
1123 PrintMessage(
1124 rPrinter,
1125 msPageString,
1126 maPageStringOffset);
1128 // Restore outliner and printer.
1129 pOutliner->Clear();
1130 pOutliner->SetUpdateLayout(bSavedUpdateMode);
1131 pOutliner->SetPaperSize(aSavedPaperSize);
1132 pOutliner->Init(nSavedOutlMode);
1135 private:
1136 std::optional<OutlinerParaObject> mpParaObject;
1140 //===== DocumentRenderer::Implementation ======================================
1142 class DocumentRenderer::Implementation
1143 : public SfxListener,
1144 public vcl::PrinterOptionsHelper
1146 public:
1147 explicit Implementation (ViewShellBase& rBase)
1148 : mxObjectShell(rBase.GetDocShell())
1149 , mrBase(rBase)
1150 , mbIsDisposed(false)
1151 , mpPrinter(nullptr)
1152 , mbHasOrientationWarningBeenShown(false)
1154 DialogCreator aCreator( mrBase, mrBase.GetDocShell()->GetDocumentType() == DocumentType::Impress, GetCurrentPageIndex() );
1155 m_aUIProperties = aCreator.GetDialogControls();
1156 maSlidesPerPage = aCreator.GetSlidesPerPage();
1158 StartListening(mrBase);
1161 virtual ~Implementation() override
1163 EndListening(mrBase);
1166 virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override
1168 if (&rBroadcaster != &static_cast<SfxBroadcaster&>(mrBase))
1169 return;
1171 if (rHint.GetId() == SfxHintId::Dying)
1173 mbIsDisposed = true;
1177 /** Process the sequence of properties given to one of the XRenderable
1178 methods.
1180 void ProcessProperties (const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
1182 OSL_ASSERT(!mbIsDisposed);
1183 if (mbIsDisposed)
1184 return;
1186 bool bIsValueChanged = processProperties( rOptions );
1187 bool bIsPaperChanged = false;
1189 // The RenderDevice property is handled specially: its value is
1190 // stored in mpPrinter instead of being retrieved on demand.
1191 Any aDev( getValue( "RenderDevice" ) );
1192 Reference<awt::XDevice> xRenderDevice;
1194 if (aDev >>= xRenderDevice)
1196 VCLXDevice* pDevice = dynamic_cast<VCLXDevice*>(xRenderDevice.get());
1197 VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice()
1198 : VclPtr< OutputDevice >();
1199 mpPrinter = dynamic_cast<Printer*>(pOut.get());
1200 Size aPageSizePixel = mpPrinter ? mpPrinter->GetPaperSizePixel() : Size();
1201 if( aPageSizePixel != maPrinterPageSizePixel )
1203 bIsPaperChanged = true;
1204 maPrinterPageSizePixel = aPageSizePixel;
1208 if (bIsValueChanged && ! mpOptions )
1209 mpOptions.reset(new PrintOptions(*this, std::vector(maSlidesPerPage)));
1210 if( bIsValueChanged || bIsPaperChanged )
1211 PreparePages();
1214 /** Return the number of pages that are to be printed.
1216 sal_Int32 GetPrintPageCount() const
1218 OSL_ASSERT(!mbIsDisposed);
1219 if (mbIsDisposed)
1220 return 0;
1221 else
1222 return maPrinterPages.size();
1225 /** Return a sequence of properties that can be returned by the
1226 XRenderable::getRenderer() method.
1228 css::uno::Sequence<css::beans::PropertyValue> GetProperties () const
1230 css::uno::Sequence<css::beans::PropertyValue> aProperties{
1231 comphelper::makePropertyValue("ExtraPrintUIOptions",
1232 comphelper::containerToSequence(m_aUIProperties)),
1233 comphelper::makePropertyValue("PageSize", maPrintSize),
1234 // FIXME: is this always true ?
1235 comphelper::makePropertyValue("PageIncludesNonprintableArea", true)
1238 return aProperties;
1241 /** Print one of the prepared pages.
1243 void PrintPage (const sal_Int32 nIndex)
1245 OSL_ASSERT(!mbIsDisposed);
1246 if (mbIsDisposed)
1247 return;
1249 Printer& rPrinter (*mpPrinter);
1251 std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
1252 if ( ! pViewShell)
1253 return;
1255 SdDrawDocument* pDocument = pViewShell->GetDoc();
1256 OSL_ASSERT(pDocument!=nullptr);
1258 std::shared_ptr<DrawViewShell> pDrawViewShell(
1259 std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
1261 if (!mpPrintView)
1262 mpPrintView.reset(new DrawView(mrBase.GetDocShell(), &rPrinter, nullptr));
1264 if (nIndex<0 || sal::static_int_cast<sal_uInt32>(nIndex)>=maPrinterPages.size())
1265 return;
1267 const std::shared_ptr<PrinterPage> pPage (maPrinterPages[nIndex]);
1268 OSL_ASSERT(pPage);
1269 if ( ! pPage)
1270 return;
1272 const Orientation eSavedOrientation (rPrinter.GetOrientation());
1273 const DrawModeFlags nSavedDrawMode (rPrinter.GetDrawMode());
1274 const MapMode aSavedMapMode (rPrinter.GetMapMode());
1275 const sal_uInt16 nSavedPaperBin (rPrinter.GetPaperBin());
1277 // Set page orientation.
1278 if ( ! rPrinter.SetOrientation(pPage->GetOrientation()))
1280 if ( ! mbHasOrientationWarningBeenShown
1281 && mpOptions->IsWarningOrientation())
1283 mbHasOrientationWarningBeenShown = true;
1284 // Show warning that the orientation could not be set.
1285 std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(
1286 pViewShell->GetFrameWeld(), VclMessageType::Warning, VclButtonsType::OkCancel,
1287 SdResId(STR_WARN_PRINTFORMAT_FAILURE)));
1288 xWarn->set_default_response(RET_CANCEL);
1289 if (xWarn->run() != RET_OK)
1290 return;
1294 // Set the draw mode.
1295 rPrinter.SetDrawMode(pPage->GetDrawMode());
1297 // Set paper tray.
1298 rPrinter.SetPaperBin(pPage->GetPaperTray());
1300 // Print the actual page.
1301 pPage->Print(
1302 rPrinter,
1303 *pDocument,
1304 *pViewShell,
1305 pDrawViewShell ? pDrawViewShell->GetView() : nullptr,
1306 *mpPrintView,
1307 pViewShell->GetFrameView()->GetVisibleLayers(),
1308 pViewShell->GetFrameView()->GetPrintableLayers());
1310 rPrinter.SetOrientation(eSavedOrientation);
1311 rPrinter.SetDrawMode(nSavedDrawMode);
1312 rPrinter.SetMapMode(aSavedMapMode);
1313 rPrinter.SetPaperBin(nSavedPaperBin);
1316 private:
1317 // rhbz#657394: keep the document alive: prevents crash when
1318 SfxObjectShellRef mxObjectShell; // destroying mpPrintView
1319 ViewShellBase& mrBase;
1320 bool mbIsDisposed;
1321 VclPtr<Printer> mpPrinter;
1322 Size maPrinterPageSizePixel;
1323 std::unique_ptr<PrintOptions> mpOptions;
1324 std::vector< std::shared_ptr< ::sd::PrinterPage> > maPrinterPages;
1325 std::unique_ptr<DrawView> mpPrintView;
1326 bool mbHasOrientationWarningBeenShown;
1327 std::vector<sal_Int32> maSlidesPerPage;
1328 awt::Size maPrintSize;
1330 sal_Int32 GetCurrentPageIndex() const
1332 const ViewShell *pShell = mrBase.GetMainViewShell().get();
1333 const SdPage *pCurrentPage = pShell ? pShell->getCurrentPage() : nullptr;
1334 return pCurrentPage ? (pCurrentPage->GetPageNum()-1)/2 : -1;
1337 /** Determine and set the paper orientation.
1339 void SetupPaperOrientation (
1340 const PageKind ePageKind,
1341 PrintInfo& rInfo)
1343 SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
1344 rInfo.meOrientation = Orientation::Portrait;
1346 if( ! mpOptions->IsBooklet())
1348 rInfo.meOrientation = pDocument->GetSdPage(0, ePageKind)->GetOrientation();
1350 else if (rInfo.maPageSize.Width() < rInfo.maPageSize.Height())
1351 rInfo.meOrientation = Orientation::Landscape;
1353 // Draw and Notes should usually abide by their specified paper size
1354 Size aPaperSize;
1355 if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
1357 aPaperSize.setWidth(rInfo.maPageSize.Width());
1358 aPaperSize.setHeight(rInfo.maPageSize.Height());
1360 else
1362 aPaperSize.setWidth(rInfo.mpPrinter->GetPaperSize().Width());
1363 aPaperSize.setHeight(rInfo.mpPrinter->GetPaperSize().Height());
1366 maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
1368 if (mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
1370 if( (rInfo.meOrientation == Orientation::Landscape &&
1371 (aPaperSize.Width() < aPaperSize.Height()))
1373 (rInfo.meOrientation == Orientation::Portrait &&
1374 (aPaperSize.Width() > aPaperSize.Height()))
1377 maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
1382 /** Top most method for preparing printer pages. In this and the other
1383 Prepare... methods the various special cases are detected and
1384 handled.
1385 For every page that is to be printed (that may contain several
1386 slides) one PrinterPage object is created and inserted into
1387 maPrinterPages.
1389 void PreparePages()
1391 mpPrintView.reset();
1392 maPrinterPages.clear();
1393 mbHasOrientationWarningBeenShown = false;
1395 ViewShell* pShell = mrBase.GetMainViewShell().get();
1397 PrintInfo aInfo (mpPrinter, mpOptions->IsPrintMarkedOnly());
1399 if (aInfo.mpPrinter==nullptr || pShell==nullptr)
1400 return;
1402 MapMode aMap (aInfo.mpPrinter->GetMapMode());
1403 aMap.SetMapUnit(MapUnit::Map100thMM);
1404 aInfo.maMap = aMap;
1405 mpPrinter->SetMapMode(aMap);
1407 ::Outliner& rOutliner = mrBase.GetDocument()->GetDrawOutliner();
1408 const EEControlBits nSavedControlWord (rOutliner.GetControlWord());
1409 EEControlBits nCntrl = nSavedControlWord;
1410 nCntrl &= ~EEControlBits::MARKFIELDS;
1411 nCntrl &= ~EEControlBits::ONLINESPELLING;
1412 rOutliner.SetControlWord( nCntrl );
1414 // When in outline view then apply all pending changes to the model.
1415 if( auto pOutlineViewShell = dynamic_cast< OutlineViewShell *>( pShell ) )
1416 pOutlineViewShell->PrepareClose (false);
1418 // Collect some frequently used data.
1419 if (mpOptions->IsDate())
1421 aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getDate( Date( Date::SYSTEM ) );
1422 aInfo.msTimeDate += " ";
1425 if (mpOptions->IsTime())
1426 aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData().getTime( ::tools::Time( ::tools::Time::SYSTEM ), false );
1428 // Draw and Notes should usually use specified paper size when printing
1429 if (!mpOptions->IsPrinterPreferred(mrBase.GetDocShell()->GetDocumentType()))
1431 aInfo.maPrintSize = mrBase.GetDocument()->GetSdPage(0, PageKind::Standard)->GetSize();
1432 maPrintSize = awt::Size(aInfo.maPrintSize.Width(),
1433 aInfo.maPrintSize.Height());
1435 else
1437 aInfo.maPrintSize = aInfo.mpPrinter->GetOutputSize();
1438 maPrintSize = awt::Size(
1439 aInfo.mpPrinter->GetPaperSize().Width(),
1440 aInfo.mpPrinter->GetPaperSize().Height());
1443 switch (mpOptions->GetOutputQuality())
1445 case 1: // Grayscale
1446 aInfo.mnDrawMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill
1447 | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap
1448 | DrawModeFlags::GrayGradient;
1449 break;
1451 case 2: // Black & White
1452 aInfo.mnDrawMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill
1453 | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap
1454 | DrawModeFlags::WhiteGradient;
1455 break;
1457 default:
1458 aInfo.mnDrawMode = DrawModeFlags::Default;
1461 if (mpOptions->IsDraw())
1462 PrepareStdOrNotes(PageKind::Standard, aInfo);
1463 if (mpOptions->IsNotes())
1464 PrepareStdOrNotes(PageKind::Notes, aInfo);
1465 if (mpOptions->IsHandout())
1467 InitHandoutTemplate();
1468 PrepareHandout(aInfo);
1470 if (mpOptions->IsOutline())
1471 PrepareOutline(aInfo);
1473 rOutliner.SetControlWord(nSavedControlWord);
1476 /** Create the page objects of the handout template. When the actual
1477 printing takes place then the page objects are assigned different
1478 sets of slides for each printed page (see HandoutPrinterPage::Print).
1480 void InitHandoutTemplate()
1482 const sal_Int32 nSlidesPerHandout (mpOptions->GetHandoutPageCount());
1483 const bool bHandoutHorizontal (mpOptions->IsHandoutHorizontal());
1485 AutoLayout eLayout = AUTOLAYOUT_HANDOUT6;
1486 switch (nSlidesPerHandout)
1488 case 0: eLayout = AUTOLAYOUT_NONE; break; // AUTOLAYOUT_HANDOUT1; break;
1489 case 1: eLayout = AUTOLAYOUT_HANDOUT1; break;
1490 case 2: eLayout = AUTOLAYOUT_HANDOUT2; break;
1491 case 3: eLayout = AUTOLAYOUT_HANDOUT3; break;
1492 case 4: eLayout = AUTOLAYOUT_HANDOUT4; break;
1493 default:
1494 case 6: eLayout = AUTOLAYOUT_HANDOUT6; break;
1495 case 9: eLayout = AUTOLAYOUT_HANDOUT9; break;
1498 if( !mrBase.GetDocument() )
1499 return;
1501 SdDrawDocument& rModel = *mrBase.GetDocument();
1503 // first, prepare handout page (not handout master)
1505 SdPage* pHandout = rModel.GetSdPage(0, PageKind::Handout);
1506 if( !pHandout )
1507 return;
1509 // delete all previous shapes from handout page
1510 while( pHandout->GetObjCount() )
1511 pHandout->NbcRemoveObject(0);
1513 const bool bDrawLines (eLayout == AUTOLAYOUT_HANDOUT3);
1515 std::vector< ::tools::Rectangle > aAreas;
1516 SdPage::CalculateHandoutAreas( rModel, eLayout, bHandoutHorizontal, aAreas );
1518 std::vector< ::tools::Rectangle >::iterator iter( aAreas.begin() );
1519 while( iter != aAreas.end() )
1521 pHandout->NbcInsertObject(
1522 new SdrPageObj(
1523 rModel,
1524 (*iter++)));
1526 if( bDrawLines && (iter != aAreas.end()) )
1528 ::tools::Rectangle aRect( *iter++ );
1530 basegfx::B2DPolygon aPoly;
1531 aPoly.insert(0, basegfx::B2DPoint( aRect.Left(), aRect.Top() ) );
1532 aPoly.insert(1, basegfx::B2DPoint( aRect.Right(), aRect.Top() ) );
1534 basegfx::B2DHomMatrix aMatrix;
1535 aMatrix.translate( 0.0, static_cast< double >( aRect.GetHeight() / 7 ) );
1537 basegfx::B2DPolyPolygon aPathPoly;
1538 for( sal_uInt16 nLine = 0; nLine < 7; nLine++ )
1540 aPoly.transform( aMatrix );
1541 aPathPoly.append( aPoly );
1544 rtl::Reference<SdrPathObj> pPathObj = new SdrPathObj(
1545 rModel,
1546 SdrObjKind::PathLine,
1547 std::move(aPathPoly));
1548 pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
1549 pPathObj->SetMergedItem(XLineColorItem(OUString(), COL_BLACK));
1551 pHandout->NbcInsertObject( pPathObj.get() );
1556 /** Detect whether the specified slide is to be printed.
1557 @return
1558 When the slide is not to be printed then <NULL/> is returned.
1559 Otherwise a pointer to the slide is returned.
1561 SdPage* GetFilteredPage (
1562 const sal_Int32 nPageIndex,
1563 const PageKind ePageKind) const
1565 OSL_ASSERT(mrBase.GetDocument() != nullptr);
1566 OSL_ASSERT(nPageIndex>=0);
1567 SdPage* pPage = mrBase.GetDocument()->GetSdPage(
1568 sal::static_int_cast<sal_uInt16>(nPageIndex),
1569 ePageKind);
1570 if (pPage == nullptr)
1571 return nullptr;
1572 if ( ! pPage->IsExcluded() || mpOptions->IsPrintExcluded())
1573 return pPage;
1574 else
1575 return nullptr;
1578 /** Prepare the outline of the document for printing. There is no fixed
1579 number of slides whose outline data is put onto one printer page.
1580 If the current printer page has enough room for the outline of the
1581 current slide then that is added. Otherwise a new printer page is
1582 started.
1584 void PrepareOutline (PrintInfo const & rInfo)
1586 MapMode aMap (rInfo.maMap);
1587 Point aPageOfs (rInfo.mpPrinter->GetPageOffset() );
1588 aMap.SetScaleX(Fraction(1,2));
1589 aMap.SetScaleY(Fraction(1,2));
1590 mpPrinter->SetMapMode(aMap);
1592 ::tools::Rectangle aOutRect(aPageOfs, rInfo.mpPrinter->GetOutputSize());
1593 if( aOutRect.GetWidth() > aOutRect.GetHeight() )
1595 Size aPaperSize( rInfo.mpPrinter->PixelToLogic( rInfo.mpPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) );
1596 maPrintSize.Width = aPaperSize.Height();
1597 maPrintSize.Height = aPaperSize.Width();
1598 const auto nRotatedWidth = aOutRect.GetHeight();
1599 const auto nRotatedHeight = aOutRect.GetWidth();
1600 const auto nRotatedX = aPageOfs.Y();
1601 const auto nRotatedY = aPageOfs.X();
1602 aOutRect = ::tools::Rectangle(Point( nRotatedX, nRotatedY),
1603 Size(nRotatedWidth, nRotatedHeight));
1606 Outliner* pOutliner = mrBase.GetDocument()->GetInternalOutliner();
1607 pOutliner->Init(OutlinerMode::OutlineView);
1608 const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
1609 const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
1610 const Size aSavedPaperSize (pOutliner->GetPaperSize());
1611 const MapMode aSavedMapMode (pOutliner->GetRefMapMode());
1612 pOutliner->SetPaperSize(aOutRect.GetSize());
1613 pOutliner->SetUpdateLayout(true);
1615 ::tools::Long nPageH = aOutRect.GetHeight();
1617 std::vector< sal_Int32 > aPages;
1618 sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
1619 StringRangeEnumerator::getRangesFromString(
1620 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
1621 aPages, 0, nPageCount-1);
1623 for (size_t nIndex = 0, nCount = aPages.size(); nIndex < nCount;)
1625 pOutliner->Clear();
1627 Paragraph* pPara = nullptr;
1628 ::tools::Long nH (0);
1629 while (nH < nPageH && nIndex<nCount)
1631 SdPage* pPage = GetFilteredPage(aPages[nIndex], PageKind::Standard);
1632 ++nIndex;
1633 if (pPage == nullptr)
1634 continue;
1636 SdrTextObj* pTextObj = nullptr;
1637 size_t nObj (0);
1639 while (pTextObj==nullptr && nObj < pPage->GetObjCount())
1641 SdrObject* pObj = pPage->GetObj(nObj++);
1642 if (pObj->GetObjInventor() == SdrInventor::Default
1643 && pObj->GetObjIdentifier() == SdrObjKind::TitleText)
1645 pTextObj = DynCastSdrTextObj(pObj);
1649 pPara = pOutliner->GetParagraph(pOutliner->GetParagraphCount() - 1);
1651 if (pTextObj!=nullptr
1652 && !pTextObj->IsEmptyPresObj()
1653 && pTextObj->GetOutlinerParaObject())
1655 pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
1657 else
1658 pOutliner->Insert(OUString());
1660 pTextObj = nullptr;
1661 nObj = 0;
1663 while (pTextObj==nullptr && nObj<pPage->GetObjCount())
1665 SdrObject* pObj = pPage->GetObj(nObj++);
1666 if (pObj->GetObjInventor() == SdrInventor::Default
1667 && pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
1669 pTextObj = DynCastSdrTextObj(pObj);
1673 bool bSubTitle (false);
1674 if (!pTextObj)
1676 bSubTitle = true;
1677 pTextObj = DynCastSdrTextObj(pPage->GetPresObj(PresObjKind::Text)); // is there a subtitle?
1680 sal_Int32 nParaCount1 = pOutliner->GetParagraphCount();
1682 if (pTextObj!=nullptr
1683 && !pTextObj->IsEmptyPresObj()
1684 && pTextObj->GetOutlinerParaObject())
1686 pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
1689 if (bSubTitle )
1691 const sal_Int32 nParaCount2 (pOutliner->GetParagraphCount());
1692 for (sal_Int32 nPara=nParaCount1; nPara<nParaCount2; ++nPara)
1694 Paragraph* pP = pOutliner->GetParagraph(nPara);
1695 if (pP!=nullptr && pOutliner->GetDepth(nPara) > 0)
1696 pOutliner->SetDepth(pP, 0);
1700 nH = pOutliner->GetTextHeight();
1703 // Remove the last paragraph when that does not fit completely on
1704 // the current page.
1705 if (nH > nPageH && pPara!=nullptr)
1707 sal_Int32 nCnt = pOutliner->GetAbsPos(
1708 pOutliner->GetParagraph( pOutliner->GetParagraphCount() - 1 ) );
1709 sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara );
1710 nCnt -= nParaPos;
1711 pPara = pOutliner->GetParagraph( ++nParaPos );
1712 if ( nCnt && pPara )
1714 pOutliner->Remove(pPara, nCnt);
1715 --nIndex;
1719 if ( CheckForFrontBackPages( nIndex ) )
1721 maPrinterPages.push_back(
1722 std::make_shared<OutlinerPrinterPage>(
1723 pOutliner->CreateParaObject(),
1724 aMap,
1725 rInfo.msTimeDate,
1726 aPageOfs,
1727 rInfo.mnDrawMode,
1728 rInfo.meOrientation,
1729 rInfo.mpPrinter->GetPaperBin()));
1733 pOutliner->SetRefMapMode(aSavedMapMode);
1734 pOutliner->SetUpdateLayout(bSavedUpdateMode);
1735 pOutliner->SetPaperSize(aSavedPaperSize);
1736 pOutliner->Init(nSavedOutlMode);
1739 /** Prepare handout pages for slides that are to be printed.
1741 void PrepareHandout (PrintInfo& rInfo)
1743 SdDrawDocument* pDocument = mrBase.GetDocument();
1744 OSL_ASSERT(pDocument != nullptr);
1745 SdPage& rHandoutPage (*pDocument->GetSdPage(0, PageKind::Handout));
1747 const bool bScalePage (mpOptions->IsPageSize());
1749 sal_uInt16 nPaperBin;
1750 if ( ! mpOptions->IsPaperBin())
1751 nPaperBin = rHandoutPage.GetPaperBin();
1752 else
1753 nPaperBin = rInfo.mpPrinter->GetPaperBin();
1755 // Change orientation?
1756 SdPage& rMaster (dynamic_cast<SdPage&>(rHandoutPage.TRG_GetMasterPage()));
1757 rInfo.meOrientation = rMaster.GetOrientation();
1759 const Size aPaperSize (rInfo.mpPrinter->GetPaperSize());
1760 if( (rInfo.meOrientation == Orientation::Landscape &&
1761 (aPaperSize.Width() < aPaperSize.Height()))
1763 (rInfo.meOrientation == Orientation::Portrait &&
1764 (aPaperSize.Width() > aPaperSize.Height()))
1767 maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
1769 else
1771 maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
1774 MapMode aMap (rInfo.maMap);
1775 const Point aPageOfs (rInfo.mpPrinter->GetPageOffset());
1777 if ( bScalePage )
1779 const Size aPageSize (rHandoutPage.GetSize());
1780 const Size aPrintSize (rInfo.mpPrinter->GetOutputSize());
1782 const double fHorz = static_cast<double>(aPrintSize.Width()) / aPageSize.Width();
1783 const double fVert = static_cast<double>(aPrintSize.Height()) / aPageSize.Height();
1785 Fraction aFract;
1786 if ( fHorz < fVert )
1787 aFract = Fraction(aPrintSize.Width(), aPageSize.Width());
1788 else
1789 aFract = Fraction(aPrintSize.Height(), aPageSize.Height());
1791 aMap.SetScaleX(aFract);
1792 aMap.SetScaleY(aFract);
1793 aMap.SetOrigin(Point());
1796 std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
1797 pViewShell->WriteFrameViewData();
1799 // Count page shapes.
1800 sal_uInt32 nShapeCount (0);
1801 SdrObjListIter aShapeIter (&rHandoutPage);
1802 while (aShapeIter.IsMore())
1804 SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
1805 if (pPageObj)
1806 ++nShapeCount;
1809 const sal_uInt16 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
1810 const sal_uInt16 nHandoutPageCount = nShapeCount ? (nPageCount + nShapeCount - 1) / nShapeCount : 0;
1811 pViewShell->SetPrintedHandoutPageCount( nHandoutPageCount );
1812 mrBase.GetDocument()->setHandoutPageCount( nHandoutPageCount );
1814 // Distribute pages to handout pages.
1815 StringRangeEnumerator aRangeEnum(
1816 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
1817 0, nPageCount-1);
1818 std::vector<sal_uInt16> aPageIndices;
1819 sal_uInt16 nPrinterPageIndex = 0;
1820 StringRangeEnumerator::Iterator it = aRangeEnum.begin(), itEnd = aRangeEnum.end();
1821 bool bLastLoop = (it == itEnd);
1822 while (!bLastLoop)
1824 sal_Int32 nPageIndex = *it;
1825 ++it;
1826 bLastLoop = (it == itEnd);
1828 if (GetFilteredPage(nPageIndex, PageKind::Standard))
1829 aPageIndices.push_back(nPageIndex);
1830 else if (!bLastLoop)
1831 continue;
1833 // Create a printer page when we have found one page for each
1834 // placeholder or when this is the last (and special) loop.
1835 if ( !aPageIndices.empty() && CheckForFrontBackPages( nPageIndex )
1836 && (aPageIndices.size() == nShapeCount || bLastLoop) )
1838 maPrinterPages.push_back(
1839 std::make_shared<HandoutPrinterPage>(
1840 nPrinterPageIndex++,
1841 std::move(aPageIndices),
1842 aMap,
1843 rInfo.msTimeDate,
1844 aPageOfs,
1845 rInfo.mnDrawMode,
1846 rInfo.meOrientation,
1847 nPaperBin));
1848 aPageIndices.clear();
1853 /** Prepare the notes pages or regular slides.
1855 void PrepareStdOrNotes (
1856 const PageKind ePageKind,
1857 PrintInfo& rInfo)
1859 OSL_ASSERT(rInfo.mpPrinter != nullptr);
1861 // Fill in page kind specific data.
1862 SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
1863 if (pDocument->GetSdPageCount(ePageKind) == 0)
1864 return;
1865 SdPage* pRefPage = pDocument->GetSdPage(0, ePageKind);
1866 rInfo.maPageSize = pRefPage->GetSize();
1868 SetupPaperOrientation(ePageKind, rInfo);
1870 MapMode aMap (rInfo.maMap);
1871 rInfo.maMap = aMap;
1873 if (mpOptions->IsBooklet())
1874 PrepareBooklet(ePageKind, rInfo);
1875 else
1876 PrepareRegularPages(ePageKind, rInfo);
1879 /** Prepare slides in a non-booklet way: one slide per one to many
1880 printer pages.
1882 void PrepareRegularPages (
1883 const PageKind ePageKind,
1884 PrintInfo& rInfo)
1886 std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
1887 pViewShell->WriteFrameViewData();
1889 sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
1890 StringRangeEnumerator aRangeEnum(
1891 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
1892 0, nPageCount-1);
1893 for (StringRangeEnumerator::Iterator
1894 it = aRangeEnum.begin(),
1895 itEnd = aRangeEnum.end();
1896 it != itEnd;
1897 ++it)
1899 SdPage* pPage = GetFilteredPage(*it, ePageKind);
1900 if (pPage == nullptr)
1901 continue;
1903 MapMode aMap (rInfo.maMap);
1904 // is it possible that the page size changed?
1905 const Size aPageSize = pPage->GetSize();
1907 if (mpOptions->IsPageSize())
1909 const double fHorz (static_cast<double>(rInfo.maPrintSize.Width()) / aPageSize.Width());
1910 const double fVert (static_cast<double>(rInfo.maPrintSize.Height()) / aPageSize.Height());
1912 Fraction aFract;
1913 if (fHorz < fVert)
1914 aFract = Fraction(rInfo.maPrintSize.Width(), aPageSize.Width());
1915 else
1916 aFract = Fraction(rInfo.maPrintSize.Height(), aPageSize.Height());
1918 aMap.SetScaleX(aFract);
1919 aMap.SetScaleY(aFract);
1920 aMap.SetOrigin(Point());
1923 if (mpOptions->IsPrintPageName())
1925 rInfo.msPageString = pPage->GetName() + " ";
1927 else
1928 rInfo.msPageString.clear();
1929 rInfo.msPageString += rInfo.msTimeDate;
1931 ::tools::Long aPageWidth = aPageSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder();
1932 ::tools::Long aPageHeight = aPageSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder();
1933 // Bugfix for 44530:
1934 // if it was implicitly changed (Landscape/Portrait),
1935 // this is considered for tiling, respectively for the splitting up
1936 // (Poster)
1937 if( ( rInfo.maPrintSize.Width() > rInfo.maPrintSize.Height()
1938 && aPageWidth < aPageHeight )
1939 || ( rInfo.maPrintSize.Width() < rInfo.maPrintSize.Height()
1940 && aPageWidth > aPageHeight ) )
1942 const sal_Int32 nTmp (rInfo.maPrintSize.Width());
1943 rInfo.maPrintSize.setWidth( rInfo.maPrintSize.Height() );
1944 rInfo.maPrintSize.setHeight( nTmp );
1947 if (mpOptions->IsTilePage()
1948 && aPageWidth < rInfo.maPrintSize.Width()
1949 && aPageHeight < rInfo.maPrintSize.Height())
1951 // Put multiple slides on one printer page.
1952 PrepareTiledPage(*it, *pPage, ePageKind, rInfo);
1954 else
1956 rInfo.maMap = aMap;
1957 PrepareScaledPage(*it, *pPage, ePageKind, rInfo);
1962 /** Put two slides on one printer page.
1964 void PrepareBooklet (
1965 const PageKind ePageKind,
1966 const PrintInfo& rInfo)
1968 MapMode aStdMap (rInfo.maMap);
1969 Point aOffset;
1970 Size aPrintSize_2 (rInfo.maPrintSize);
1971 Size aPageSize_2 (rInfo.maPageSize);
1973 if (rInfo.meOrientation == Orientation::Landscape)
1974 aPrintSize_2.setWidth( aPrintSize_2.Width() >> 1 );
1975 else
1976 aPrintSize_2.setHeight( aPrintSize_2.Height() >> 1 );
1978 const double fPageWH = static_cast<double>(aPageSize_2.Width()) / aPageSize_2.Height();
1979 const double fPrintWH = static_cast<double>(aPrintSize_2.Width()) / aPrintSize_2.Height();
1981 if( fPageWH < fPrintWH )
1983 aPageSize_2.setWidth( static_cast<::tools::Long>( aPrintSize_2.Height() * fPageWH ) );
1984 aPageSize_2.setHeight( aPrintSize_2.Height() );
1986 else
1988 aPageSize_2.setWidth( aPrintSize_2.Width() );
1989 aPageSize_2.setHeight( static_cast<::tools::Long>( aPrintSize_2.Width() / fPageWH ) );
1992 MapMode aMap (rInfo.maMap);
1993 aMap.SetScaleX( Fraction( aPageSize_2.Width(), rInfo.maPageSize.Width() ) );
1994 aMap.SetScaleY( Fraction( aPageSize_2.Height(), rInfo.maPageSize.Height() ) );
1996 // calculate adjusted print size
1997 const Size aAdjustedPrintSize (OutputDevice::LogicToLogic(
1998 rInfo.maPrintSize,
1999 aStdMap,
2000 aMap));
2002 if (rInfo.meOrientation == Orientation::Landscape)
2004 aOffset.setX( ( ( aAdjustedPrintSize.Width() >> 1 ) - rInfo.maPageSize.Width() ) >> 1 );
2005 aOffset.setY( ( aAdjustedPrintSize.Height() - rInfo.maPageSize.Height() ) >> 1 );
2007 else
2009 aOffset.setX( ( aAdjustedPrintSize.Width() - rInfo.maPageSize.Width() ) >> 1 );
2010 aOffset.setY( ( ( aAdjustedPrintSize.Height() >> 1 ) - rInfo.maPageSize.Height() ) >> 1 );
2013 // create vector of pages to print
2014 sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(ePageKind);
2015 StringRangeEnumerator aRangeEnum(
2016 mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
2017 0, nPageCount-1);
2018 std::vector< sal_uInt16 > aPageVector;
2019 for (StringRangeEnumerator::Iterator
2020 it = aRangeEnum.begin(),
2021 itEnd = aRangeEnum.end();
2022 it != itEnd;
2023 ++it)
2025 SdPage* pPage = GetFilteredPage(*it, ePageKind);
2026 if (pPage != nullptr)
2027 aPageVector.push_back(*it);
2030 // create pairs of pages to print on each page
2031 std::vector< std::pair< sal_uInt16, sal_uInt16 > > aPairVector;
2032 if ( ! aPageVector.empty())
2034 sal_uInt32 nFirstIndex = 0, nLastIndex = aPageVector.size() - 1;
2036 if( aPageVector.size() & 1 )
2037 aPairVector.emplace_back( sal_uInt16(65535), aPageVector[ nFirstIndex++ ] );
2038 else
2039 aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
2041 while( nFirstIndex < nLastIndex )
2043 if( nFirstIndex & 1 )
2044 aPairVector.emplace_back( aPageVector[ nFirstIndex++ ], aPageVector[ nLastIndex-- ] );
2045 else
2046 aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
2050 for (sal_uInt32
2051 nIndex=0,
2052 nCount=aPairVector.size();
2053 nIndex < nCount;
2054 ++nIndex)
2056 if ( CheckForFrontBackPages( nIndex ) )
2058 const std::pair<sal_uInt16, sal_uInt16> aPair (aPairVector[nIndex]);
2059 Point aSecondOffset (aOffset);
2060 if (rInfo.meOrientation == Orientation::Landscape)
2061 aSecondOffset.AdjustX( aAdjustedPrintSize.Width() / 2 );
2062 else
2063 aSecondOffset.AdjustY( aAdjustedPrintSize.Height() / 2 );
2064 maPrinterPages.push_back(
2065 std::make_shared<BookletPrinterPage>(
2066 aPair.first,
2067 aPair.second,
2068 aOffset,
2069 aSecondOffset,
2070 ePageKind,
2071 aMap,
2072 rInfo.mbPrintMarkedOnly,
2073 rInfo.mnDrawMode,
2074 rInfo.meOrientation,
2075 rInfo.mpPrinter->GetPaperBin()));
2081 /** Print one slide multiple times on one printer page so that the whole
2082 printer page is covered.
2084 void PrepareTiledPage (
2085 const sal_Int32 nPageIndex,
2086 const SdPage& rPage,
2087 const PageKind ePageKind,
2088 const PrintInfo& rInfo)
2090 sal_uInt16 nPaperBin;
2091 if ( ! mpOptions->IsPaperBin())
2092 nPaperBin = rPage.GetPaperBin();
2093 else
2094 nPaperBin = rInfo.mpPrinter->GetPaperBin();
2096 if ( !CheckForFrontBackPages( nPageIndex ) )
2097 return;
2099 maPrinterPages.push_back(
2100 std::make_shared<TiledPrinterPage>(
2101 sal::static_int_cast<sal_uInt16>(nPageIndex),
2102 ePageKind,
2103 rInfo.mbPrintMarkedOnly,
2104 rInfo.msPageString,
2105 rInfo.mpPrinter->GetPageOffset(),
2106 rInfo.mnDrawMode,
2107 rInfo.meOrientation,
2108 nPaperBin));
2111 /** Print one standard slide or notes page on one to many printer
2112 pages. More than on printer page is used when the slide is larger
2113 than the printable area.
2115 void PrepareScaledPage (
2116 const sal_Int32 nPageIndex,
2117 const SdPage& rPage,
2118 const PageKind ePageKind,
2119 const PrintInfo& rInfo)
2121 const Point aPageOffset (rInfo.mpPrinter->GetPageOffset());
2123 sal_uInt16 nPaperBin;
2124 if ( ! mpOptions->IsPaperBin())
2125 nPaperBin = rPage.GetPaperBin();
2126 else
2127 nPaperBin = rInfo.mpPrinter->GetPaperBin();
2129 // For pages larger then the printable area there
2130 // are three options:
2131 // 1. Scale down to the page to the printable area.
2132 // 2. Print only the upper left part of the page
2133 // (without the unprintable borders).
2134 // 3. Split the page into parts of the size of the
2135 // printable area.
2136 const bool bScalePage (mpOptions->IsPageSize());
2137 const bool bCutPage (mpOptions->IsCutPage());
2138 MapMode aMap (rInfo.maMap);
2139 if ( (bScalePage || bCutPage) && CheckForFrontBackPages( nPageIndex ) )
2141 // Handle 1 and 2.
2143 // if CutPage is set then do not move it, otherwise move the
2144 // scaled page to printable area
2145 maPrinterPages.push_back(
2146 std::make_shared<RegularPrinterPage>(
2147 sal::static_int_cast<sal_uInt16>(nPageIndex),
2148 ePageKind,
2149 aMap,
2150 rInfo.mbPrintMarkedOnly,
2151 rInfo.msPageString,
2152 aPageOffset,
2153 rInfo.mnDrawMode,
2154 rInfo.meOrientation,
2155 nPaperBin));
2157 else
2159 // Handle 3. Print parts of the page in the size of the
2160 // printable area until the whole page is covered.
2162 // keep the page content at its position if it fits, otherwise
2163 // move it to the printable area
2164 const ::tools::Long nPageWidth (
2165 rInfo.maPageSize.Width() - rPage.GetLeftBorder() - rPage.GetRightBorder());
2166 const ::tools::Long nPageHeight (
2167 rInfo.maPageSize.Height() - rPage.GetUpperBorder() - rPage.GetLowerBorder());
2169 Point aOrigin ( 0, 0 );
2171 for (Point aPageOrigin = aOrigin;
2172 -aPageOrigin.Y()<nPageHeight;
2173 aPageOrigin.AdjustY( -rInfo.maPrintSize.Height() ))
2175 for (aPageOrigin.setX(aOrigin.X());
2176 -aPageOrigin.X()<nPageWidth;
2177 aPageOrigin.AdjustX(-rInfo.maPrintSize.Width()))
2179 if ( CheckForFrontBackPages( nPageIndex ) )
2181 aMap.SetOrigin(aPageOrigin);
2182 maPrinterPages.push_back(
2183 std::make_shared<RegularPrinterPage>(
2184 sal::static_int_cast<sal_uInt16>(nPageIndex),
2185 ePageKind,
2186 aMap,
2187 rInfo.mbPrintMarkedOnly,
2188 rInfo.msPageString,
2189 aPageOffset,
2190 rInfo.mnDrawMode,
2191 rInfo.meOrientation,
2192 nPaperBin));
2199 bool CheckForFrontBackPages( sal_Int32 nPage )
2201 const bool bIsIndexOdd(nPage & 1);
2202 if ((!bIsIndexOdd && mpOptions->IsPrintFrontPage())
2203 || (bIsIndexOdd && mpOptions->IsPrintBackPage()))
2205 return true;
2207 else
2208 return false;
2212 //===== DocumentRenderer ======================================================
2214 DocumentRenderer::DocumentRenderer (ViewShellBase& rBase)
2215 : mpImpl(new Implementation(rBase))
2219 DocumentRenderer::~DocumentRenderer()
2223 //----- XRenderable -----------------------------------------------------------
2225 sal_Int32 SAL_CALL DocumentRenderer::getRendererCount (
2226 const css::uno::Any&,
2227 const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
2229 mpImpl->ProcessProperties(rOptions);
2230 return mpImpl->GetPrintPageCount();
2233 Sequence<beans::PropertyValue> SAL_CALL DocumentRenderer::getRenderer (
2234 sal_Int32,
2235 const css::uno::Any&,
2236 const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
2238 mpImpl->ProcessProperties(rOptions);
2239 return mpImpl->GetProperties();
2242 void SAL_CALL DocumentRenderer::render (
2243 sal_Int32 nRenderer,
2244 const css::uno::Any&,
2245 const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
2247 mpImpl->ProcessProperties(rOptions);
2248 mpImpl->PrintPage(nRenderer);
2251 } // end of namespace sd
2253 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */