summaryrefslogtreecommitdiffstats
path: root/sd/source/ui/view/DocumentRenderer.cxx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:06:44 +0000
commited5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch)
tree7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /sd/source/ui/view/DocumentRenderer.cxx
parentInitial commit. (diff)
downloadlibreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz
libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sd/source/ui/view/DocumentRenderer.cxx')
-rw-r--r--sd/source/ui/view/DocumentRenderer.cxx2256
1 files changed, 2256 insertions, 0 deletions
diff --git a/sd/source/ui/view/DocumentRenderer.cxx b/sd/source/ui/view/DocumentRenderer.cxx
new file mode 100644
index 000000000..eee1a759e
--- /dev/null
+++ b/sd/source/ui/view/DocumentRenderer.cxx
@@ -0,0 +1,2256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <DocumentRenderer.hxx>
+#include <DocumentRenderer.hrc>
+#include <ViewShellBase.hxx>
+
+#include <drawdoc.hxx>
+#include <sdpage.hxx>
+#include <sdresid.hxx>
+#include <strings.hrc>
+#include <drawview.hxx>
+#include <DrawViewShell.hxx>
+#include <FrameView.hxx>
+#include <Outliner.hxx>
+#include <OutlineViewShell.hxx>
+#include <SlideSorterViewShell.hxx>
+#include <DrawDocShell.hxx>
+
+#include <tools/multisel.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/sequence.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <editeng/editstat.hxx>
+#include <editeng/outlobj.hxx>
+#include <svx/svdetc.hxx>
+#include <svx/svditer.hxx>
+#include <svx/svdopage.hxx>
+#include <svx/svdopath.hxx>
+#include <svx/svdpagv.hxx>
+#include <svx/xlineit0.hxx>
+#include <svx/xlnclit.hxx>
+#include <toolkit/awt/vclxdevice.hxx>
+#include <unotools/localedatawrapper.hxx>
+#include <vcl/print.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/weld.hxx>
+#include <unotools/moduleoptions.hxx>
+#include <xmloff/autolayout.hxx>
+#include <sfx2/objsh.hxx>
+
+#include <officecfg/Office/Draw.hxx>
+#include <officecfg/Office/Impress.hxx>
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+
+namespace sd {
+
+namespace {
+
+ /** Convenience class to extract values from the sequence of properties
+ given to one of the XRenderable methods.
+ */
+ class PrintOptions
+ {
+ public:
+ PrintOptions (
+ const vcl::PrinterOptionsHelper& rHelper,
+ std::vector<sal_Int32>&& rSlidesPerPage)
+ : mrProperties(rHelper),
+ maSlidesPerPage(std::move(rSlidesPerPage))
+ {
+ }
+
+ bool IsWarningOrientation() const
+ {
+ return GetBoolValue(nullptr, true);
+ }
+
+ bool IsPrintPageName() const
+ {
+ return GetBoolValue("IsPrintName", false);
+ }
+
+ bool IsDate() const
+ {
+ return GetBoolValue("IsPrintDateTime", false);
+ }
+
+ bool IsTime() const
+ {
+ return GetBoolValue("IsPrintDateTime", false);
+ }
+
+ bool IsHiddenPages() const
+ {
+ return GetBoolValue("IsPrintHidden", false);
+ }
+
+ bool IsHandoutHorizontal() const
+ {
+ return GetBoolValue("SlidesPerPageOrder", sal_Int32(0));
+ }
+
+ sal_Int32 GetHandoutPageCount() const
+ {
+ sal_uInt32 nIndex = static_cast<sal_Int32>(mrProperties.getIntValue("SlidesPerPage", sal_Int32(0)));
+ if (nIndex<maSlidesPerPage.size())
+ return maSlidesPerPage[nIndex];
+ else if ( ! maSlidesPerPage.empty())
+ return maSlidesPerPage[0];
+ else
+ return 0;
+ }
+
+ bool IsDraw() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(0));
+ }
+
+ bool IsHandout() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(1));
+ }
+
+ bool IsNotes() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(2));
+ }
+
+ bool IsOutline() const
+ {
+ return GetBoolValue("PageContentType", sal_Int32(3));
+ }
+
+ sal_uLong GetOutputQuality() const
+ {
+ sal_Int32 nQuality = static_cast<sal_Int32>(mrProperties.getIntValue( "Quality", sal_Int32(0) ));
+ return nQuality;
+ }
+
+ bool IsPageSize() const
+ {
+ return GetBoolValue("PageOptions", sal_Int32(1));
+ }
+
+ bool IsTilePage() const
+ {
+ return GetBoolValue("PageOptions", sal_Int32(2)) || GetBoolValue("PageOptions", sal_Int32(3));
+ }
+
+ bool IsCutPage() const
+ {
+ return GetBoolValue("PageOptions", sal_Int32(0));
+ }
+
+ bool IsBooklet() const
+ {
+ return GetBoolValue("PrintProspect", false);
+ }
+
+ bool IsPrinterPreferred(DocumentType eDocType) const
+ {
+ bool bIsDraw = eDocType == DocumentType::Draw;
+ return IsTilePage() || IsPageSize() || IsBooklet() || (!bIsDraw && !IsNotes());
+ }
+
+ bool IsPrintExcluded() const
+ {
+ return (IsNotes() || IsDraw() || IsHandout()) && IsHiddenPages();
+ }
+
+ bool IsPrintFrontPage() const
+ {
+ sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
+ return nInclude != 2;
+ }
+
+ bool IsPrintBackPage() const
+ {
+ sal_Int32 nInclude = static_cast<sal_Int32>(mrProperties.getIntValue( "EvenOdd", 0 ));
+ return nInclude != 1;
+ }
+
+ bool IsPaperBin() const
+ {
+ return GetBoolValue("PrintPaperFromSetup", false);
+ }
+
+ bool IsPrintMarkedOnly() const
+ {
+ return GetBoolValue("PrintContent", sal_Int32(4));
+ }
+
+ OUString GetPrinterSelection (sal_Int32 nPageCount, sal_Int32 nCurrentPageIndex) const
+ {
+ sal_Int32 nContent = static_cast<sal_Int32>(mrProperties.getIntValue( "PrintContent", 0 ));
+ OUString sFullRange = "1-" + OUString::number(nPageCount);
+
+ if (nContent == 0) // all pages/slides
+ {
+ return sFullRange;
+ }
+
+ if (nContent == 1) // range
+ {
+ OUString sValue = mrProperties.getStringValue("PageRange");
+ return sValue.isEmpty() ? sFullRange : sValue;
+ }
+
+ if (nContent == 2 && // selection
+ nCurrentPageIndex >= 0)
+ {
+ return OUString::number(nCurrentPageIndex + 1);
+ }
+
+ return OUString();
+ }
+
+ private:
+ const vcl::PrinterOptionsHelper& mrProperties;
+ const std::vector<sal_Int32> maSlidesPerPage;
+
+ /** When the value of the property with name pName is a boolean then
+ return its value. When the property is unknown then
+ bDefaultValue is returned. Otherwise <FALSE/> is returned.
+ */
+ bool GetBoolValue (
+ const char* pName,
+ const bool bDefaultValue) const
+ {
+ bool bValue = mrProperties.getBoolValue( pName, bDefaultValue );
+ return bValue;
+ }
+
+ /** Return <TRUE/> when the value of the property with name pName is
+ an integer and its value is nTriggerValue. Otherwise <FALSE/> is
+ returned.
+ */
+ bool GetBoolValue (
+ const char* pName,
+ const sal_Int32 nTriggerValue) const
+ {
+ sal_Int32 nValue = static_cast<sal_Int32>(mrProperties.getIntValue( pName, 0 ));
+ return nValue == nTriggerValue;
+ }
+ };
+
+ /** A collection of values that helps to reduce the number of arguments
+ given to some functions. Note that not all values are set at the
+ same time.
+ */
+ class PrintInfo
+ {
+ public:
+ PrintInfo (
+ Printer* pPrinter,
+ const bool bPrintMarkedOnly)
+ : mpPrinter(pPrinter),
+ mnDrawMode(DrawModeFlags::Default),
+ maPrintSize(0,0),
+ maPageSize(0,0),
+ meOrientation(Orientation::Portrait),
+ mbPrintMarkedOnly(bPrintMarkedOnly)
+ {}
+
+ const VclPtr<Printer> mpPrinter;
+ DrawModeFlags mnDrawMode;
+ OUString msTimeDate;
+ OUString msPageString;
+ Size maPrintSize;
+ Size maPageSize;
+ Orientation meOrientation;
+ MapMode maMap;
+ const bool mbPrintMarkedOnly;
+ };
+
+ /** Output one page of the document to the given printer. Note that
+ more than one document page may be output to one printer page.
+ */
+ void PrintPage (
+ Printer& rPrinter,
+ ::sd::View& rPrintView,
+ SdPage& rPage,
+ View const * pView,
+ const bool bPrintMarkedOnly,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers)
+ {
+ rPrintView.ShowSdrPage(&rPage);
+
+ const MapMode aOriginalMapMode (rPrinter.GetMapMode());
+
+ // Set the visible layers
+ SdrPageView* pPageView = rPrintView.GetSdrPageView();
+ OSL_ASSERT(pPageView!=nullptr);
+ pPageView->SetVisibleLayers(rVisibleLayers);
+ pPageView->SetPrintableLayers(rPrintableLayers);
+
+ if (pView!=nullptr && bPrintMarkedOnly)
+ pView->DrawMarkedObj(rPrinter);
+ else
+ rPrintView.CompleteRedraw(&rPrinter,
+ vcl::Region(::tools::Rectangle(Point(0,0), rPage.GetSize())));
+
+ rPrinter.SetMapMode(aOriginalMapMode);
+
+ rPrintView.HideSdrPage();
+ }
+
+ /** Output a string (that typically is not part of a document page) to
+ the given printer.
+ */
+ void PrintMessage (
+ Printer& rPrinter,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset)
+ {
+ const vcl::Font aOriginalFont (rPrinter.OutputDevice::GetFont());
+ rPrinter.SetFont(vcl::Font(FAMILY_SWISS, Size(0, 423)));
+ rPrinter.DrawText(rPageStringOffset, rsPageString);
+ rPrinter.SetFont(aOriginalFont);
+ }
+
+ /** Read the resources and process then into a sequence of properties
+ that can be passed to the printing dialog.
+ */
+ class DialogCreator
+ {
+ public:
+ DialogCreator (ViewShellBase &rBase, bool bImpress, sal_Int32 nCurPage)
+ : mrBase(rBase)
+ , mbImpress(bImpress)
+ , mnCurPage(nCurPage)
+ {
+ ProcessResource();
+ }
+
+ const std::vector< beans::PropertyValue >& GetDialogControls() const
+ {
+ return maProperties;
+ }
+
+ const std::vector<sal_Int32>& GetSlidesPerPage() const
+ {
+ return maSlidesPerPage;
+ }
+
+ private:
+ ViewShellBase &mrBase;
+ std::vector<beans::PropertyValue> maProperties;
+ std::vector<sal_Int32> maSlidesPerPage;
+ bool mbImpress;
+ sal_Int32 mnCurPage;
+
+ void ProcessResource()
+ {
+ // load the writer PrinterOptions into the custom tab
+ beans::PropertyValue aOptionsUIFile;
+ aOptionsUIFile.Name = "OptionsUIFile";
+ if( mbImpress )
+ aOptionsUIFile.Value <<= OUString("modules/simpress/ui/impressprinteroptions.ui");
+ else
+ aOptionsUIFile.Value <<= OUString("modules/sdraw/ui/drawprinteroptions.ui");
+ maProperties.push_back(aOptionsUIFile);
+
+ SvtModuleOptions aOpt;
+ OUString aAppGroupname(SdResId(STR_IMPRESS_PRINT_UI_GROUP_NAME));
+ aAppGroupname = aAppGroupname.replaceFirst("%s", aOpt.GetModuleName(
+ mbImpress ? SvtModuleOptions::EModule::IMPRESS : SvtModuleOptions::EModule::DRAW));
+ AddDialogControl(vcl::PrinterOptionsHelper::setGroupControlOpt("tabcontrol-page2", aAppGroupname, ".HelpID:vcl:PrintDialog:TabPage:AppPage"));
+
+ uno::Sequence< OUString > aHelpIds, aWidgetIds;
+ if( mbImpress )
+ {
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PageContentType:ListBox" };
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "impressdocument",
+ SdResId(STR_IMPRESS_PRINT_UI_CONTENT),
+ aHelpIds,
+ "PageContentType" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_CONTENT_CHOICES)),
+ 0)
+ );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPage:ListBox" };
+ vcl::PrinterOptionsHelper::UIControlOptions aContentOpt( "PageContentType" , 1 );
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "slidesperpage",
+ SdResId(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE),
+ aHelpIds,
+ "SlidesPerPage" ,
+ GetSlidesPerPageSequence(),
+ 0,
+ Sequence< sal_Bool >(),
+ aContentOpt
+ )
+ );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:SlidesPerPageOrder:ListBox" };
+ vcl::PrinterOptionsHelper::UIControlOptions aSlidesPerPageOpt( "SlidesPerPage" , -1, true );
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "slidesperpageorder",
+ SdResId(STR_IMPRESS_PRINT_UI_ORDER),
+ aHelpIds,
+ "SlidesPerPageOrder" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_ORDER_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_ORDER_CHOICES)),
+ 0,
+ Sequence< sal_Bool >(),
+ aSlidesPerPageOpt )
+ );
+ }
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("contents",
+ SdResId(STR_IMPRESS_PRINT_UI_INCLUDE_CONTENT), "" ) );
+
+ if( mbImpress )
+ {
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname",
+ SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_NAME),
+ ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" ,
+ "IsPrintName" ,
+ officecfg::Office::Impress::Print::Other::PageName::get()
+ )
+ );
+ }
+ else
+ {
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printname",
+ SdResId(STR_DRAW_PRINT_UI_IS_PRINT_NAME),
+ ".HelpID:vcl:PrintDialog:IsPrintName:CheckBox" ,
+ "IsPrintName" ,
+ officecfg::Office::Draw::Print::Other::PageName::get()
+ )
+ );
+ }
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printdatetime",
+ SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_DATE),
+ ".HelpID:vcl:PrintDialog:IsPrintDateTime:CheckBox" ,
+ "IsPrintDateTime" ,
+ // Separate settings for time and date in Impress/Draw -> Print page, check that both are set
+ mbImpress ?
+ officecfg::Office::Impress::Print::Other::Date::get() &&
+ officecfg::Office::Impress::Print::Other::Time::get() :
+ officecfg::Office::Draw::Print::Other::Date::get() &&
+ officecfg::Office::Draw::Print::Other::Time::get()
+ )
+ );
+
+ if( mbImpress )
+ {
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printhidden",
+ SdResId(STR_IMPRESS_PRINT_UI_IS_PRINT_HIDDEN),
+ ".HelpID:vcl:PrintDialog:IsPrintHidden:CheckBox" ,
+ "IsPrintHidden" ,
+ officecfg::Office::Impress::Print::Other::HiddenPage::get()
+ )
+ );
+ }
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("color",
+ SdResId(STR_IMPRESS_PRINT_UI_QUALITY), "" ) );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:Quality:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:Quality:RadioButton:1",
+ ".HelpID:vcl:PrintDialog:Quality:RadioButton:2" };
+ aWidgetIds = { "originalcolors", "grayscale", "blackandwhite" };
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
+ aWidgetIds,
+ "",
+ aHelpIds,
+ "Quality" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_QUALITY_CHOICES)),
+ mbImpress ? officecfg::Office::Impress::Print::Other::Quality::get() :
+ officecfg::Office::Draw::Print::Other::Quality::get() )
+
+ );
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesizes",
+ SdResId(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS), "" ) );
+
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:1",
+ ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:2",
+ ".HelpID:vcl:PrintDialog:PageOptions:RadioButton:3" };
+ aWidgetIds = { "originalsize", "fittoprintable", "distributeonmultiple", "tilesheet" };
+
+ // Mutually exclusive page options settings are stored in separate config keys...
+ // TODO: There is no config key to set the distributeonmultiple option as default
+ sal_Int32 nDefaultChoice = 0;
+ if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageSize::get() :
+ officecfg::Office::Draw::Print::Page::PageSize::get() )
+ {
+ nDefaultChoice = 1;
+ }
+ else if ( mbImpress ? officecfg::Office::Impress::Print::Page::PageTile::get() :
+ officecfg::Office::Draw::Print::Page::PageTile::get() )
+ {
+ nDefaultChoice = 3;
+ }
+ vcl::PrinterOptionsHelper::UIControlOptions aPageOptionsOpt("PrintProspect", 0);
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(
+ aWidgetIds,
+ "",
+ aHelpIds,
+ "PageOptions" ,
+ mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES)) :
+ CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_OPTIONS_CHOICES_DRAW)),
+ nDefaultChoice,
+ Sequence< sal_Bool >(),
+ aPageOptionsOpt
+ )
+ );
+
+ vcl::PrinterOptionsHelper::UIControlOptions aBrochureOpt;
+ aBrochureOpt.maGroupHint = "LayoutPage" ;
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("pagesides",
+ SdResId(STR_IMPRESS_PRINT_UI_PAGE_SIDES), "",
+ aBrochureOpt ) );
+
+ // brochure printing
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("brochure",
+ SdResId(STR_IMPRESS_PRINT_UI_BROCHURE),
+ ".HelpID:vcl:PrintDialog:PrintProspect:CheckBox" ,
+ "PrintProspect" ,
+ mbImpress ? officecfg::Office::Impress::Print::Page::Booklet::get() :
+ officecfg::Office::Draw::Print::Page::Booklet::get(),
+ aBrochureOpt
+ )
+ );
+
+ vcl::PrinterOptionsHelper::UIControlOptions
+ aIncludeOpt( "PrintProspect" , -1, false );
+ aIncludeOpt.maGroupHint = "LayoutPage" ;
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PrintProspectInclude:ListBox" };
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt(
+ "brochureinclude",
+ SdResId(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE),
+ aHelpIds,
+ "PrintProspectInclude" ,
+ CreateChoice(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_BROCHURE_INCLUDE_LIST)),
+ 0,
+ Sequence< sal_Bool >(),
+ aIncludeOpt
+ )
+ );
+
+ // paper tray (on options page)
+ vcl::PrinterOptionsHelper::UIControlOptions aPaperTrayOpt;
+ aPaperTrayOpt.maGroupHint = "OptionsPageOptGroup" ;
+ AddDialogControl( vcl::PrinterOptionsHelper::setBoolControlOpt("printpaperfromsetup",
+ SdResId(STR_IMPRESS_PRINT_UI_PAPER_TRAY),
+ ".HelpID:vcl:PrintDialog:PrintPaperFromSetup:CheckBox" ,
+ "PrintPaperFromSetup" ,
+ false,
+ aPaperTrayOpt
+ )
+ );
+ // print range selection
+ vcl::PrinterOptionsHelper::UIControlOptions aPrintRangeOpt;
+ aPrintRangeOpt.mbInternalOnly = true;
+ aPrintRangeOpt.maGroupHint = "PrintRange" ;
+ AddDialogControl( vcl::PrinterOptionsHelper::setSubgroupControlOpt("printrange",
+ mbImpress ? SdResId(STR_IMPRESS_PRINT_UI_SLIDE_RANGE) : SdResId(STR_IMPRESS_PRINT_UI_PAGE_RANGE),
+ "",
+ aPrintRangeOpt )
+ );
+
+ // check if there is a selection of slides
+ OUString aPageRange(OUString::number(mnCurPage + 1));
+ int nPrintRange(0);
+ using sd::slidesorter::SlideSorterViewShell;
+ SlideSorterViewShell* const pSSViewSh(SlideSorterViewShell::GetSlideSorter(mrBase));
+ if (pSSViewSh)
+ {
+ const std::shared_ptr<SlideSorterViewShell::PageSelection> pPageSelection(pSSViewSh->GetPageSelection());
+ if (bool(pPageSelection) && pPageSelection->size() > 1)
+ {
+ OUStringBuffer aBuf;
+ // TODO: this could be improved by writing ranges instead of consecutive page
+ // numbers if appropriate. Do we have a helper function for that somewhere?
+ bool bFirst(true);
+ for (auto pPage: *pPageSelection)
+ {
+ if (bFirst)
+ bFirst = false;
+ else
+ aBuf.append(',');
+ aBuf.append(static_cast<sal_Int32>(pPage->GetPageNum() / 2 + 1));
+ }
+ aPageRange = aBuf.makeStringAndClear();
+ nPrintRange = 1;
+ }
+ }
+/*
+ OUString aPrintRangeName( "PrintContent" );
+ aHelpIds.realloc( 1 );
+ aHelpIds[0] = ".HelpID:vcl:PrintDialog:PageContentType:ListBox";
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceListControlOpt( "printpagesbox", OUString(),
+ aHelpIds, aPrintRangeName,
+ mbImpress ? CreateChoice( STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE ) ) :
+ CreateChoice( STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE ) ),
+ nPrintRange ) );
+*/
+ OUString aPrintRangeName( "PrintContent" );
+ aHelpIds = { ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:0",
+ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:1",
+ ".HelpID:vcl:PrintDialog:PrintContent:RadioButton:2" };
+ aWidgetIds = { "rbAllPages", "rbRangePages", "rbRangeSelection" };
+
+ AddDialogControl( vcl::PrinterOptionsHelper::setChoiceRadiosControlOpt(aWidgetIds, OUString(),
+ aHelpIds, aPrintRangeName,
+ mbImpress ? CreateChoice(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_PAGE_RANGE_CHOICE)) :
+ CreateChoice(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE, SAL_N_ELEMENTS(STR_DRAW_PRINT_UI_PAGE_RANGE_CHOICE)),
+ nPrintRange )
+ );
+ // create an Edit dependent on "Pages" selected
+ vcl::PrinterOptionsHelper::UIControlOptions aPageRangeOpt( aPrintRangeName, 1, true );
+ AddDialogControl(vcl::PrinterOptionsHelper::setEditControlOpt("pagerange", "",
+ ".HelpID:vcl:PrintDialog:PageRange:Edit", "PageRange",
+ aPageRange, aPageRangeOpt));
+ vcl::PrinterOptionsHelper::UIControlOptions aEvenOddOpt(aPrintRangeName, -1, true);
+ AddDialogControl(vcl::PrinterOptionsHelper::setChoiceListControlOpt("evenoddbox", "",
+ uno::Sequence<OUString>(), "EvenOdd", uno::Sequence<OUString>(),
+ 0, uno::Sequence<sal_Bool>(), aEvenOddOpt));
+ }
+
+ void AddDialogControl( const Any& i_rCtrl )
+ {
+ beans::PropertyValue aVal;
+ aVal.Value = i_rCtrl;
+ maProperties.push_back( aVal );
+ }
+
+ static Sequence<OUString> CreateChoice(const TranslateId* pResourceId, size_t nCount)
+ {
+ Sequence<OUString> aChoices (nCount);
+ std::transform(pResourceId, pResourceId + nCount, aChoices.getArray(),
+ [](const auto& id) { return SdResId(id); });
+ return aChoices;
+ }
+
+ Sequence<OUString> GetSlidesPerPageSequence()
+ {
+ const Sequence<OUString> aChoice (
+ CreateChoice(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES, SAL_N_ELEMENTS(STR_IMPRESS_PRINT_UI_SLIDESPERPAGE_CHOICES)));
+ maSlidesPerPage.clear();
+ maSlidesPerPage.push_back(0); // first is using the default
+ std::transform(std::next(aChoice.begin()), aChoice.end(), std::back_inserter(maSlidesPerPage),
+ [](const OUString& rChoice) -> sal_Int32 { return rChoice.toInt32(); });
+ return aChoice;
+ }
+ };
+
+ /** The Prepare... methods of the DocumentRenderer::Implementation class
+ create a set of PrinterPage objects that contain all necessary
+ information to do the actual printing. There is one PrinterPage
+ object per printed page. Derived classes implement the actual, mode
+ specific printing.
+
+ This and all derived classes support the asynchronous printing
+ process by not storing pointers to any data with lifetime shorter
+ than the PrinterPage objects, i.e. slides, shapes, (one of) the
+ outliner (of the document).
+ */
+ class PrinterPage
+ {
+ public:
+ PrinterPage (
+ const PageKind ePageKind,
+ const MapMode& rMapMode,
+ const bool bPrintMarkedOnly,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : mePageKind(ePageKind),
+ maMap(rMapMode),
+ mbPrintMarkedOnly(bPrintMarkedOnly),
+ msPageString(rsPageString),
+ maPageStringOffset(rPageStringOffset),
+ mnDrawMode(nDrawMode),
+ meOrientation(eOrientation),
+ mnPaperTray(nPaperTray)
+ {
+ }
+
+ virtual ~PrinterPage() {}
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell& rViewShell,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const = 0;
+
+ DrawModeFlags GetDrawMode() const { return mnDrawMode; }
+ Orientation GetOrientation() const { return meOrientation; }
+ sal_uInt16 GetPaperTray() const { return mnPaperTray; }
+
+ protected:
+ const PageKind mePageKind;
+ const MapMode maMap;
+ const bool mbPrintMarkedOnly;
+ const OUString msPageString;
+ const Point maPageStringOffset;
+ const DrawModeFlags mnDrawMode;
+ const Orientation meOrientation;
+ const sal_uInt16 mnPaperTray;
+ };
+
+ /** The RegularPrinterPage is used for printing one regular slide (no
+ notes, handout, or outline) to one printer page.
+ */
+ class RegularPrinterPage : public PrinterPage
+ {
+ public:
+ RegularPrinterPage (
+ const sal_uInt16 nPageIndex,
+ const PageKind ePageKind,
+ const MapMode& rMapMode,
+ const bool bPrintMarkedOnly,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mnPageIndex(nPageIndex)
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
+ rPrinter.SetMapMode(maMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+ }
+
+ private:
+ const sal_uInt16 mnPageIndex;
+ };
+
+ /** Print one slide multiple times on a printer page so that the whole
+ printer page is covered.
+ */
+ class TiledPrinterPage : public PrinterPage
+ {
+ public:
+ TiledPrinterPage (
+ const sal_uInt16 nPageIndex,
+ const PageKind ePageKind,
+ const bool bPrintMarkedOnly,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(ePageKind, MapMode(), bPrintMarkedOnly, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mnPageIndex(nPageIndex)
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ SdPage* pPageToPrint = rDocument.GetSdPage(mnPageIndex, mePageKind);
+ if (pPageToPrint==nullptr)
+ return;
+ MapMode aMap (rPrinter.GetMapMode());
+
+ const Size aPageSize (pPageToPrint->GetSize());
+ const Size aPrintSize (rPrinter.GetOutputSize());
+
+ const sal_Int32 nPageWidth (aPageSize.Width() + mnGap
+ - pPageToPrint->GetLeftBorder() - pPageToPrint->GetRightBorder());
+ const sal_Int32 nPageHeight (aPageSize.Height() + mnGap
+ - pPageToPrint->GetUpperBorder() - pPageToPrint->GetLowerBorder());
+ if (nPageWidth<=0 || nPageHeight<=0)
+ return;
+
+ // Print at least two rows and columns. More if the document
+ // page fits completely onto the printer page.
+ const sal_Int32 nColumnCount (std::max(sal_Int32(2),
+ sal_Int32(aPrintSize.Width() / nPageWidth)));
+ const sal_Int32 nRowCount (std::max(sal_Int32(2),
+ sal_Int32(aPrintSize.Height() / nPageHeight)));
+ for (sal_Int32 nRow=0; nRow<nRowCount; ++nRow)
+ for (sal_Int32 nColumn=0; nColumn<nColumnCount; ++nColumn)
+ {
+ aMap.SetOrigin(Point(nColumn*nPageWidth,nRow*nPageHeight));
+ rPrinter.SetMapMode(aMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ }
+
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+ }
+
+ private:
+ const sal_uInt16 mnPageIndex;
+ static const sal_Int32 mnGap = 500;
+ };
+
+ /** Print two slides to one printer page so that the resulting pages
+ form a booklet.
+ */
+ class BookletPrinterPage : public PrinterPage
+ {
+ public:
+ BookletPrinterPage (
+ const sal_uInt16 nFirstPageIndex,
+ const sal_uInt16 nSecondPageIndex,
+ const Point& rFirstOffset,
+ const Point& rSecondOffset,
+ const PageKind ePageKind,
+ const MapMode& rMapMode,
+ const bool bPrintMarkedOnly,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(ePageKind, rMapMode, bPrintMarkedOnly, "",
+ Point(), nDrawMode, eOrientation, nPaperTray),
+ mnFirstPageIndex(nFirstPageIndex),
+ mnSecondPageIndex(nSecondPageIndex),
+ maFirstOffset(rFirstOffset),
+ maSecondOffset(rSecondOffset)
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ MapMode aMap (maMap);
+ SdPage* pPageToPrint = rDocument.GetSdPage(mnFirstPageIndex, mePageKind);
+ if (pPageToPrint)
+ {
+ aMap.SetOrigin(maFirstOffset);
+ rPrinter.SetMapMode(aMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ }
+
+ pPageToPrint = rDocument.GetSdPage(mnSecondPageIndex, mePageKind);
+ if( !pPageToPrint )
+ return;
+
+ aMap.SetOrigin(maSecondOffset);
+ rPrinter.SetMapMode(aMap);
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ *pPageToPrint,
+ pView,
+ mbPrintMarkedOnly,
+ rVisibleLayers,
+ rPrintableLayers);
+ }
+
+ private:
+ const sal_uInt16 mnFirstPageIndex;
+ const sal_uInt16 mnSecondPageIndex;
+ const Point maFirstOffset;
+ const Point maSecondOffset;
+ };
+
+ /** One handout page displays one to nine slides.
+ */
+ class HandoutPrinterPage : public PrinterPage
+ {
+ public:
+ HandoutPrinterPage (
+ const sal_uInt16 nHandoutPageIndex,
+ std::vector<sal_uInt16>&& rPageIndices,
+ const MapMode& rMapMode,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mnHandoutPageIndex(nHandoutPageIndex),
+ maPageIndices(std::move(rPageIndices))
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell& rViewShell,
+ View* pView,
+ DrawView& rPrintView,
+ const SdrLayerIDSet& rVisibleLayers,
+ const SdrLayerIDSet& rPrintableLayers) const override
+ {
+ SdPage& rHandoutPage (*rDocument.GetSdPage(0, PageKind::Handout));
+
+ Reference< css::beans::XPropertySet > xHandoutPage( rHandoutPage.getUnoPage(), UNO_QUERY );
+ static const OUStringLiteral sPageNumber( u"Number" );
+
+ // Collect the page objects of the handout master.
+ std::vector<SdrPageObj*> aHandoutPageObjects;
+ SdrObjListIter aShapeIter (&rHandoutPage);
+ while (aShapeIter.IsMore())
+ {
+ SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
+ if (pPageObj)
+ aHandoutPageObjects.push_back(pPageObj);
+ }
+ if (aHandoutPageObjects.empty())
+ return;
+
+ // Connect page objects with pages.
+ std::vector<SdrPageObj*>::iterator aPageObjIter (aHandoutPageObjects.begin());
+ for (std::vector<sal_uInt16>::const_iterator
+ iPageIndex(maPageIndices.begin()),
+ iEnd(maPageIndices.end());
+ iPageIndex!=iEnd && aPageObjIter!=aHandoutPageObjects.end();
+ ++iPageIndex)
+ {
+ // Check if the page still exists.
+ if (*iPageIndex >= rDocument.GetSdPageCount(PageKind::Standard))
+ continue;
+
+ SdrPageObj* pPageObj = *aPageObjIter++;
+ pPageObj->SetReferencedPage(rDocument.GetSdPage(*iPageIndex, PageKind::Standard));
+ }
+
+ // if there are more page objects than pages left, set the rest to invisible
+ int nHangoverCount = 0;
+ while (aPageObjIter != aHandoutPageObjects.end())
+ {
+ (*aPageObjIter++)->SetReferencedPage(nullptr);
+ nHangoverCount++;
+ }
+
+ // Hide outlines for objects that have pages attached.
+ if (nHangoverCount > 0)
+ {
+ int nSkip = aHandoutPageObjects.size() - nHangoverCount;
+ aShapeIter.Reset();
+ while (aShapeIter.IsMore())
+ {
+ SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
+ if (pPathObj)
+ {
+ if (nSkip > 0)
+ --nSkip;
+ else
+ pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_NONE));
+ }
+ }
+ }
+
+ if( xHandoutPage.is() ) try
+ {
+ xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(mnHandoutPageIndex) ) );
+ }
+ catch( Exception& )
+ {
+ }
+ rViewShell.SetPrintedHandoutPageNum( mnHandoutPageIndex + 1 );
+
+ rPrinter.SetMapMode(maMap);
+
+ PrintPage(
+ rPrinter,
+ rPrintView,
+ rHandoutPage,
+ pView,
+ false,
+ rVisibleLayers,
+ rPrintableLayers);
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+
+ if( xHandoutPage.is() ) try
+ {
+ xHandoutPage->setPropertyValue( sPageNumber, Any( static_cast<sal_Int16>(0) ) );
+ }
+ catch( Exception& )
+ {
+ }
+ rViewShell.SetPrintedHandoutPageNum(1);
+
+ // Restore outlines.
+ if (nHangoverCount > 0)
+ {
+ aShapeIter.Reset();
+ while (aShapeIter.IsMore())
+ {
+ SdrPathObj* pPathObj = dynamic_cast<SdrPathObj*>(aShapeIter.Next());
+ if (pPathObj != nullptr)
+ pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
+ }
+ }
+
+ }
+
+ private:
+ const sal_uInt16 mnHandoutPageIndex;
+ const std::vector<sal_uInt16> maPageIndices;
+ };
+
+ /** The outline information (title, subtitle, outline objects) of the
+ document. There is no fixed mapping of slides to printer pages.
+ */
+ class OutlinerPrinterPage : public PrinterPage
+ {
+ public:
+ OutlinerPrinterPage (
+ std::optional<OutlinerParaObject> pParaObject,
+ const MapMode& rMapMode,
+ const OUString& rsPageString,
+ const Point& rPageStringOffset,
+ const DrawModeFlags nDrawMode,
+ const Orientation eOrientation,
+ const sal_uInt16 nPaperTray)
+ : PrinterPage(PageKind::Handout, rMapMode, false, rsPageString,
+ rPageStringOffset, nDrawMode, eOrientation, nPaperTray),
+ mpParaObject(std::move(pParaObject))
+ {
+ }
+
+ virtual void Print (
+ Printer& rPrinter,
+ SdDrawDocument& rDocument,
+ ViewShell&,
+ View*,
+ DrawView&,
+ const SdrLayerIDSet&,
+ const SdrLayerIDSet&) const override
+ {
+ // Set up the printer.
+ rPrinter.SetMapMode(maMap);
+
+ // Get and set up the outliner.
+ const ::tools::Rectangle aOutRect (rPrinter.GetPageOffset(), rPrinter.GetOutputSize());
+ Outliner* pOutliner = rDocument.GetInternalOutliner();
+ const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
+ const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
+ const Size aSavedPaperSize (pOutliner->GetPaperSize());
+
+ pOutliner->Init(OutlinerMode::OutlineView);
+ pOutliner->SetPaperSize(aOutRect.GetSize());
+ pOutliner->SetUpdateLayout(true);
+ pOutliner->Clear();
+ pOutliner->SetText(*mpParaObject);
+
+ pOutliner->Draw(rPrinter, aOutRect);
+
+ PrintMessage(
+ rPrinter,
+ msPageString,
+ maPageStringOffset);
+
+ // Restore outliner and printer.
+ pOutliner->Clear();
+ pOutliner->SetUpdateLayout(bSavedUpdateMode);
+ pOutliner->SetPaperSize(aSavedPaperSize);
+ pOutliner->Init(nSavedOutlMode);
+ }
+
+ private:
+ std::optional<OutlinerParaObject> mpParaObject;
+ };
+}
+
+//===== DocumentRenderer::Implementation ======================================
+
+class DocumentRenderer::Implementation
+ : public SfxListener,
+ public vcl::PrinterOptionsHelper
+{
+public:
+ explicit Implementation (ViewShellBase& rBase)
+ : mxObjectShell(rBase.GetDocShell())
+ , mrBase(rBase)
+ , mbIsDisposed(false)
+ , mpPrinter(nullptr)
+ , mbHasOrientationWarningBeenShown(false)
+ {
+ DialogCreator aCreator( mrBase, mrBase.GetDocShell()->GetDocumentType() == DocumentType::Impress, GetCurrentPageIndex() );
+ m_aUIProperties = aCreator.GetDialogControls();
+ maSlidesPerPage = aCreator.GetSlidesPerPage();
+
+ StartListening(mrBase);
+ }
+
+ virtual ~Implementation() override
+ {
+ EndListening(mrBase);
+ }
+
+ virtual void Notify (SfxBroadcaster& rBroadcaster, const SfxHint& rHint) override
+ {
+ if (&rBroadcaster != &static_cast<SfxBroadcaster&>(mrBase))
+ return;
+
+ if (rHint.GetId() == SfxHintId::Dying)
+ {
+ mbIsDisposed = true;
+ }
+ }
+
+ /** Process the sequence of properties given to one of the XRenderable
+ methods.
+ */
+ void ProcessProperties (const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
+ {
+ OSL_ASSERT(!mbIsDisposed);
+ if (mbIsDisposed)
+ return;
+
+ bool bIsValueChanged = processProperties( rOptions );
+ bool bIsPaperChanged = false;
+
+ // The RenderDevice property is handled specially: its value is
+ // stored in mpPrinter instead of being retrieved on demand.
+ Any aDev( getValue( "RenderDevice" ) );
+ Reference<awt::XDevice> xRenderDevice;
+
+ if (aDev >>= xRenderDevice)
+ {
+ VCLXDevice* pDevice = comphelper::getFromUnoTunnel<VCLXDevice>(xRenderDevice);
+ VclPtr< OutputDevice > pOut = pDevice ? pDevice->GetOutputDevice()
+ : VclPtr< OutputDevice >();
+ mpPrinter = dynamic_cast<Printer*>(pOut.get());
+ Size aPageSizePixel = mpPrinter ? mpPrinter->GetPaperSizePixel() : Size();
+ if( aPageSizePixel != maPrinterPageSizePixel )
+ {
+ bIsPaperChanged = true;
+ maPrinterPageSizePixel = aPageSizePixel;
+ }
+ }
+
+ if (bIsValueChanged && ! mpOptions )
+ mpOptions.reset(new PrintOptions(*this, std::vector(maSlidesPerPage)));
+ if( bIsValueChanged || bIsPaperChanged )
+ PreparePages();
+ }
+
+ /** Return the number of pages that are to be printed.
+ */
+ sal_Int32 GetPrintPageCount() const
+ {
+ OSL_ASSERT(!mbIsDisposed);
+ if (mbIsDisposed)
+ return 0;
+ else
+ return maPrinterPages.size();
+ }
+
+ /** Return a sequence of properties that can be returned by the
+ XRenderable::getRenderer() method.
+ */
+ css::uno::Sequence<css::beans::PropertyValue> GetProperties () const
+ {
+ css::uno::Sequence<css::beans::PropertyValue> aProperties{
+ comphelper::makePropertyValue("ExtraPrintUIOptions",
+ comphelper::containerToSequence(m_aUIProperties)),
+ comphelper::makePropertyValue("PageSize", maPrintSize),
+ // FIXME: is this always true ?
+ comphelper::makePropertyValue("PageIncludesNonprintableArea", true)
+ };
+
+ return aProperties;
+ }
+
+ /** Print one of the prepared pages.
+ */
+ void PrintPage (const sal_Int32 nIndex)
+ {
+ OSL_ASSERT(!mbIsDisposed);
+ if (mbIsDisposed)
+ return;
+
+ Printer& rPrinter (*mpPrinter);
+
+ std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
+ if ( ! pViewShell)
+ return;
+
+ SdDrawDocument* pDocument = pViewShell->GetDoc();
+ OSL_ASSERT(pDocument!=nullptr);
+
+ std::shared_ptr<DrawViewShell> pDrawViewShell(
+ std::dynamic_pointer_cast<DrawViewShell>(mrBase.GetMainViewShell()));
+
+ if (!mpPrintView)
+ mpPrintView.reset(new DrawView(mrBase.GetDocShell(), &rPrinter, nullptr));
+
+ if (nIndex<0 || sal::static_int_cast<sal_uInt32>(nIndex)>=maPrinterPages.size())
+ return;
+
+ const std::shared_ptr<PrinterPage> pPage (maPrinterPages[nIndex]);
+ OSL_ASSERT(pPage);
+ if ( ! pPage)
+ return;
+
+ const Orientation eSavedOrientation (rPrinter.GetOrientation());
+ const DrawModeFlags nSavedDrawMode (rPrinter.GetDrawMode());
+ const MapMode aSavedMapMode (rPrinter.GetMapMode());
+ const sal_uInt16 nSavedPaperBin (rPrinter.GetPaperBin());
+
+ // Set page orientation.
+ if ( ! rPrinter.SetOrientation(pPage->GetOrientation()))
+ {
+ if ( ! mbHasOrientationWarningBeenShown
+ && mpOptions->IsWarningOrientation())
+ {
+ mbHasOrientationWarningBeenShown = true;
+ // Show warning that the orientation could not be set.
+ std::unique_ptr<weld::MessageDialog> xWarn(Application::CreateMessageDialog(
+ pViewShell->GetFrameWeld(), VclMessageType::Warning, VclButtonsType::OkCancel,
+ SdResId(STR_WARN_PRINTFORMAT_FAILURE)));
+ xWarn->set_default_response(RET_CANCEL);
+ if (xWarn->run() != RET_OK)
+ return;
+ }
+ }
+
+ // Set the draw mode.
+ rPrinter.SetDrawMode(pPage->GetDrawMode());
+
+ // Set paper tray.
+ rPrinter.SetPaperBin(pPage->GetPaperTray());
+
+ // Print the actual page.
+ pPage->Print(
+ rPrinter,
+ *pDocument,
+ *pViewShell,
+ pDrawViewShell ? pDrawViewShell->GetView() : nullptr,
+ *mpPrintView,
+ pViewShell->GetFrameView()->GetVisibleLayers(),
+ pViewShell->GetFrameView()->GetPrintableLayers());
+
+ rPrinter.SetOrientation(eSavedOrientation);
+ rPrinter.SetDrawMode(nSavedDrawMode);
+ rPrinter.SetMapMode(aSavedMapMode);
+ rPrinter.SetPaperBin(nSavedPaperBin);
+ }
+
+private:
+ // rhbz#657394: keep the document alive: prevents crash when
+ SfxObjectShellRef mxObjectShell; // destroying mpPrintView
+ ViewShellBase& mrBase;
+ bool mbIsDisposed;
+ VclPtr<Printer> mpPrinter;
+ Size maPrinterPageSizePixel;
+ std::unique_ptr<PrintOptions> mpOptions;
+ std::vector< std::shared_ptr< ::sd::PrinterPage> > maPrinterPages;
+ std::unique_ptr<DrawView> mpPrintView;
+ bool mbHasOrientationWarningBeenShown;
+ std::vector<sal_Int32> maSlidesPerPage;
+ awt::Size maPrintSize;
+
+ sal_Int32 GetCurrentPageIndex() const
+ {
+ const ViewShell *pShell = mrBase.GetMainViewShell().get();
+ const SdPage *pCurrentPage = pShell ? pShell->getCurrentPage() : nullptr;
+ return pCurrentPage ? (pCurrentPage->GetPageNum()-1)/2 : -1;
+ }
+
+ /** Determine and set the paper orientation.
+ */
+ void SetupPaperOrientation (
+ const PageKind ePageKind,
+ PrintInfo& rInfo)
+ {
+ SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
+ rInfo.meOrientation = Orientation::Portrait;
+
+ if( ! mpOptions->IsBooklet())
+ {
+ rInfo.meOrientation = pDocument->GetSdPage(0, ePageKind)->GetOrientation();
+ }
+ else if (rInfo.maPageSize.Width() < rInfo.maPageSize.Height())
+ rInfo.meOrientation = Orientation::Landscape;
+
+ // Draw and Notes should usually abide by their specified paper size
+ Size aPaperSize;
+ if (!mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
+ {
+ aPaperSize.setWidth(rInfo.maPageSize.Width());
+ aPaperSize.setHeight(rInfo.maPageSize.Height());
+ }
+ else
+ {
+ aPaperSize.setWidth(rInfo.mpPrinter->GetPaperSize().Width());
+ aPaperSize.setHeight(rInfo.mpPrinter->GetPaperSize().Height());
+ }
+
+ maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
+
+ if (mpOptions->IsPrinterPreferred(pDocument->GetDocumentType()))
+ {
+ if( (rInfo.meOrientation == Orientation::Landscape &&
+ (aPaperSize.Width() < aPaperSize.Height()))
+ ||
+ (rInfo.meOrientation == Orientation::Portrait &&
+ (aPaperSize.Width() > aPaperSize.Height()))
+ )
+ {
+ maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
+ }
+ }
+ }
+
+ /** Top most method for preparing printer pages. In this and the other
+ Prepare... methods the various special cases are detected and
+ handled.
+ For every page that is to be printed (that may contain several
+ slides) one PrinterPage object is created and inserted into
+ maPrinterPages.
+ */
+ void PreparePages()
+ {
+ mpPrintView.reset();
+ maPrinterPages.clear();
+ mbHasOrientationWarningBeenShown = false;
+
+ ViewShell* pShell = mrBase.GetMainViewShell().get();
+
+ PrintInfo aInfo (mpPrinter, mpOptions->IsPrintMarkedOnly());
+
+ if (aInfo.mpPrinter==nullptr || pShell==nullptr)
+ return;
+
+ MapMode aMap (aInfo.mpPrinter->GetMapMode());
+ aMap.SetMapUnit(MapUnit::Map100thMM);
+ aInfo.maMap = aMap;
+ mpPrinter->SetMapMode(aMap);
+
+ ::Outliner& rOutliner = mrBase.GetDocument()->GetDrawOutliner();
+ const EEControlBits nSavedControlWord (rOutliner.GetControlWord());
+ EEControlBits nCntrl = nSavedControlWord;
+ nCntrl &= ~EEControlBits::MARKFIELDS;
+ nCntrl &= ~EEControlBits::ONLINESPELLING;
+ rOutliner.SetControlWord( nCntrl );
+
+ // When in outline view then apply all pending changes to the model.
+ if( auto pOutlineViewShell = dynamic_cast< OutlineViewShell *>( pShell ) )
+ pOutlineViewShell->PrepareClose (false);
+
+ // Collect some frequently used data.
+ if (mpOptions->IsDate())
+ {
+ aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData()->getDate( Date( Date::SYSTEM ) );
+ aInfo.msTimeDate += " ";
+ }
+
+ if (mpOptions->IsTime())
+ aInfo.msTimeDate += GetSdrGlobalData().GetLocaleData()->getTime( ::tools::Time( ::tools::Time::SYSTEM ), false );
+
+ // Draw and Notes should usually use specified paper size when printing
+ if (!mpOptions->IsPrinterPreferred(mrBase.GetDocShell()->GetDocumentType()))
+ {
+ aInfo.maPrintSize = mrBase.GetDocument()->GetSdPage(0, PageKind::Standard)->GetSize();
+ maPrintSize = awt::Size(aInfo.maPrintSize.Width(),
+ aInfo.maPrintSize.Height());
+ }
+ else
+ {
+ aInfo.maPrintSize = aInfo.mpPrinter->GetOutputSize();
+ maPrintSize = awt::Size(
+ aInfo.mpPrinter->GetPaperSize().Width(),
+ aInfo.mpPrinter->GetPaperSize().Height());
+ }
+
+ switch (mpOptions->GetOutputQuality())
+ {
+ case 1: // Grayscale
+ aInfo.mnDrawMode = DrawModeFlags::GrayLine | DrawModeFlags::GrayFill
+ | DrawModeFlags::GrayText | DrawModeFlags::GrayBitmap
+ | DrawModeFlags::GrayGradient;
+ break;
+
+ case 2: // Black & White
+ aInfo.mnDrawMode = DrawModeFlags::BlackLine | DrawModeFlags::WhiteFill
+ | DrawModeFlags::BlackText | DrawModeFlags::GrayBitmap
+ | DrawModeFlags::WhiteGradient;
+ break;
+
+ default:
+ aInfo.mnDrawMode = DrawModeFlags::Default;
+ }
+
+ if (mpOptions->IsDraw())
+ PrepareStdOrNotes(PageKind::Standard, aInfo);
+ if (mpOptions->IsNotes())
+ PrepareStdOrNotes(PageKind::Notes, aInfo);
+ if (mpOptions->IsHandout())
+ {
+ InitHandoutTemplate();
+ PrepareHandout(aInfo);
+ }
+ if (mpOptions->IsOutline())
+ PrepareOutline(aInfo);
+
+ rOutliner.SetControlWord(nSavedControlWord);
+ }
+
+ /** Create the page objects of the handout template. When the actual
+ printing takes place then the page objects are assigned different
+ sets of slides for each printed page (see HandoutPrinterPage::Print).
+ */
+ void InitHandoutTemplate()
+ {
+ const sal_Int32 nSlidesPerHandout (mpOptions->GetHandoutPageCount());
+ const bool bHandoutHorizontal (mpOptions->IsHandoutHorizontal());
+
+ AutoLayout eLayout = AUTOLAYOUT_HANDOUT6;
+ switch (nSlidesPerHandout)
+ {
+ case 0: eLayout = AUTOLAYOUT_NONE; break; // AUTOLAYOUT_HANDOUT1; break;
+ case 1: eLayout = AUTOLAYOUT_HANDOUT1; break;
+ case 2: eLayout = AUTOLAYOUT_HANDOUT2; break;
+ case 3: eLayout = AUTOLAYOUT_HANDOUT3; break;
+ case 4: eLayout = AUTOLAYOUT_HANDOUT4; break;
+ default:
+ case 6: eLayout = AUTOLAYOUT_HANDOUT6; break;
+ case 9: eLayout = AUTOLAYOUT_HANDOUT9; break;
+ }
+
+ if( !mrBase.GetDocument() )
+ return;
+
+ SdDrawDocument& rModel = *mrBase.GetDocument();
+
+ // first, prepare handout page (not handout master)
+
+ SdPage* pHandout = rModel.GetSdPage(0, PageKind::Handout);
+ if( !pHandout )
+ return;
+
+ // delete all previous shapes from handout page
+ while( pHandout->GetObjCount() )
+ {
+ SdrObject* pObj = pHandout->NbcRemoveObject(0);
+ if( pObj )
+ SdrObject::Free( pObj );
+ }
+
+ const bool bDrawLines (eLayout == AUTOLAYOUT_HANDOUT3);
+
+ std::vector< ::tools::Rectangle > aAreas;
+ SdPage::CalculateHandoutAreas( rModel, eLayout, bHandoutHorizontal, aAreas );
+
+ std::vector< ::tools::Rectangle >::iterator iter( aAreas.begin() );
+ while( iter != aAreas.end() )
+ {
+ pHandout->NbcInsertObject(
+ new SdrPageObj(
+ rModel,
+ (*iter++)));
+
+ if( bDrawLines && (iter != aAreas.end()) )
+ {
+ ::tools::Rectangle aRect( *iter++ );
+
+ basegfx::B2DPolygon aPoly;
+ aPoly.insert(0, basegfx::B2DPoint( aRect.Left(), aRect.Top() ) );
+ aPoly.insert(1, basegfx::B2DPoint( aRect.Right(), aRect.Top() ) );
+
+ basegfx::B2DHomMatrix aMatrix;
+ aMatrix.translate( 0.0, static_cast< double >( aRect.GetHeight() / 7 ) );
+
+ basegfx::B2DPolyPolygon aPathPoly;
+ for( sal_uInt16 nLine = 0; nLine < 7; nLine++ )
+ {
+ aPoly.transform( aMatrix );
+ aPathPoly.append( aPoly );
+ }
+
+ SdrPathObj* pPathObj = new SdrPathObj(
+ rModel,
+ SdrObjKind::PathLine,
+ aPathPoly);
+ pPathObj->SetMergedItem(XLineStyleItem(drawing::LineStyle_SOLID));
+ pPathObj->SetMergedItem(XLineColorItem(OUString(), COL_BLACK));
+
+ pHandout->NbcInsertObject( pPathObj );
+ }
+ }
+ }
+
+ /** Detect whether the specified slide is to be printed.
+ @return
+ When the slide is not to be printed then <NULL/> is returned.
+ Otherwise a pointer to the slide is returned.
+ */
+ SdPage* GetFilteredPage (
+ const sal_Int32 nPageIndex,
+ const PageKind ePageKind) const
+ {
+ OSL_ASSERT(mrBase.GetDocument() != nullptr);
+ OSL_ASSERT(nPageIndex>=0);
+ SdPage* pPage = mrBase.GetDocument()->GetSdPage(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind);
+ if (pPage == nullptr)
+ return nullptr;
+ if ( ! pPage->IsExcluded() || mpOptions->IsPrintExcluded())
+ return pPage;
+ else
+ return nullptr;
+ }
+
+ /** Prepare the outline of the document for printing. There is no fixed
+ number of slides whose outline data is put onto one printer page.
+ If the current printer page has enough room for the outline of the
+ current slide then that is added. Otherwise a new printer page is
+ started.
+ */
+ void PrepareOutline (PrintInfo const & rInfo)
+ {
+ MapMode aMap (rInfo.maMap);
+ Point aPageOfs (rInfo.mpPrinter->GetPageOffset() );
+ aMap.SetScaleX(Fraction(1,2));
+ aMap.SetScaleY(Fraction(1,2));
+ mpPrinter->SetMapMode(aMap);
+
+ ::tools::Rectangle aOutRect(aPageOfs, rInfo.mpPrinter->GetOutputSize());
+ if( aOutRect.GetWidth() > aOutRect.GetHeight() )
+ {
+ Size aPaperSize( rInfo.mpPrinter->PixelToLogic( rInfo.mpPrinter->GetPaperSizePixel(), MapMode( MapUnit::Map100thMM ) ) );
+ maPrintSize.Width = aPaperSize.Height();
+ maPrintSize.Height = aPaperSize.Width();
+ const auto nRotatedWidth = aOutRect.GetHeight();
+ const auto nRotatedHeight = aOutRect.GetWidth();
+ const auto nRotatedX = aPageOfs.Y();
+ const auto nRotatedY = aPageOfs.X();
+ aOutRect = ::tools::Rectangle(Point( nRotatedX, nRotatedY),
+ Size(nRotatedWidth, nRotatedHeight));
+ }
+
+ Outliner* pOutliner = mrBase.GetDocument()->GetInternalOutliner();
+ pOutliner->Init(OutlinerMode::OutlineView);
+ const OutlinerMode nSavedOutlMode (pOutliner->GetOutlinerMode());
+ const bool bSavedUpdateMode (pOutliner->IsUpdateLayout());
+ const Size aSavedPaperSize (pOutliner->GetPaperSize());
+ const MapMode aSavedMapMode (pOutliner->GetRefMapMode());
+ pOutliner->SetPaperSize(aOutRect.GetSize());
+ pOutliner->SetUpdateLayout(true);
+
+ ::tools::Long nPageH = aOutRect.GetHeight();
+
+ std::vector< sal_Int32 > aPages;
+ sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
+ StringRangeEnumerator::getRangesFromString(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ aPages, 0, nPageCount-1);
+
+ for (size_t nIndex = 0, nCount = aPages.size(); nIndex < nCount;)
+ {
+ pOutliner->Clear();
+
+ Paragraph* pPara = nullptr;
+ ::tools::Long nH (0);
+ while (nH < nPageH && nIndex<nCount)
+ {
+ SdPage* pPage = GetFilteredPage(aPages[nIndex], PageKind::Standard);
+ ++nIndex;
+ if (pPage == nullptr)
+ continue;
+
+ SdrTextObj* pTextObj = nullptr;
+ size_t nObj (0);
+
+ while (pTextObj==nullptr && nObj < pPage->GetObjCount())
+ {
+ SdrObject* pObj = pPage->GetObj(nObj++);
+ if (pObj->GetObjInventor() == SdrInventor::Default
+ && pObj->GetObjIdentifier() == SdrObjKind::TitleText)
+ {
+ pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+ }
+ }
+
+ pPara = pOutliner->GetParagraph(pOutliner->GetParagraphCount() - 1);
+
+ if (pTextObj!=nullptr
+ && !pTextObj->IsEmptyPresObj()
+ && pTextObj->GetOutlinerParaObject())
+ {
+ pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
+ }
+ else
+ pOutliner->Insert(OUString());
+
+ pTextObj = nullptr;
+ nObj = 0;
+
+ while (pTextObj==nullptr && nObj<pPage->GetObjCount())
+ {
+ SdrObject* pObj = pPage->GetObj(nObj++);
+ if (pObj->GetObjInventor() == SdrInventor::Default
+ && pObj->GetObjIdentifier() == SdrObjKind::OutlineText)
+ {
+ pTextObj = dynamic_cast<SdrTextObj*>(pObj);
+ }
+ }
+
+ bool bSubTitle (false);
+ if (!pTextObj)
+ {
+ bSubTitle = true;
+ pTextObj = dynamic_cast<SdrTextObj*>(pPage->GetPresObj(PresObjKind::Text)); // is there a subtitle?
+ }
+
+ sal_Int32 nParaCount1 = pOutliner->GetParagraphCount();
+
+ if (pTextObj!=nullptr
+ && !pTextObj->IsEmptyPresObj()
+ && pTextObj->GetOutlinerParaObject())
+ {
+ pOutliner->AddText(*(pTextObj->GetOutlinerParaObject()));
+ }
+
+ if (bSubTitle )
+ {
+ const sal_Int32 nParaCount2 (pOutliner->GetParagraphCount());
+ for (sal_Int32 nPara=nParaCount1; nPara<nParaCount2; ++nPara)
+ {
+ Paragraph* pP = pOutliner->GetParagraph(nPara);
+ if (pP!=nullptr && pOutliner->GetDepth(nPara) > 0)
+ pOutliner->SetDepth(pP, 0);
+ }
+ }
+
+ nH = pOutliner->GetTextHeight();
+ }
+
+ // Remove the last paragraph when that does not fit completely on
+ // the current page.
+ if (nH > nPageH && pPara!=nullptr)
+ {
+ sal_Int32 nCnt = pOutliner->GetAbsPos(
+ pOutliner->GetParagraph( pOutliner->GetParagraphCount() - 1 ) );
+ sal_Int32 nParaPos = pOutliner->GetAbsPos( pPara );
+ nCnt -= nParaPos;
+ pPara = pOutliner->GetParagraph( ++nParaPos );
+ if ( nCnt && pPara )
+ {
+ pOutliner->Remove(pPara, nCnt);
+ --nIndex;
+ }
+ }
+
+ if ( CheckForFrontBackPages( nIndex ) )
+ {
+ maPrinterPages.push_back(
+ std::make_shared<OutlinerPrinterPage>(
+ pOutliner->CreateParaObject(),
+ aMap,
+ rInfo.msTimeDate,
+ aPageOfs,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ rInfo.mpPrinter->GetPaperBin()));
+ }
+ }
+
+ pOutliner->SetRefMapMode(aSavedMapMode);
+ pOutliner->SetUpdateLayout(bSavedUpdateMode);
+ pOutliner->SetPaperSize(aSavedPaperSize);
+ pOutliner->Init(nSavedOutlMode);
+ }
+
+ /** Prepare handout pages for slides that are to be printed.
+ */
+ void PrepareHandout (PrintInfo& rInfo)
+ {
+ SdDrawDocument* pDocument = mrBase.GetDocument();
+ OSL_ASSERT(pDocument != nullptr);
+ SdPage& rHandoutPage (*pDocument->GetSdPage(0, PageKind::Handout));
+
+ const bool bScalePage (mpOptions->IsPageSize());
+
+ sal_uInt16 nPaperBin;
+ if ( ! mpOptions->IsPaperBin())
+ nPaperBin = rHandoutPage.GetPaperBin();
+ else
+ nPaperBin = rInfo.mpPrinter->GetPaperBin();
+
+ // Change orientation?
+ SdPage& rMaster (dynamic_cast<SdPage&>(rHandoutPage.TRG_GetMasterPage()));
+ rInfo.meOrientation = rMaster.GetOrientation();
+
+ const Size aPaperSize (rInfo.mpPrinter->GetPaperSize());
+ if( (rInfo.meOrientation == Orientation::Landscape &&
+ (aPaperSize.Width() < aPaperSize.Height()))
+ ||
+ (rInfo.meOrientation == Orientation::Portrait &&
+ (aPaperSize.Width() > aPaperSize.Height()))
+ )
+ {
+ maPrintSize = awt::Size(aPaperSize.Height(), aPaperSize.Width());
+ }
+ else
+ {
+ maPrintSize = awt::Size(aPaperSize.Width(), aPaperSize.Height());
+ }
+
+ MapMode aMap (rInfo.maMap);
+ const Point aPageOfs (rInfo.mpPrinter->GetPageOffset());
+
+ if ( bScalePage )
+ {
+ const Size aPageSize (rHandoutPage.GetSize());
+ const Size aPrintSize (rInfo.mpPrinter->GetOutputSize());
+
+ const double fHorz = static_cast<double>(aPrintSize.Width()) / aPageSize.Width();
+ const double fVert = static_cast<double>(aPrintSize.Height()) / aPageSize.Height();
+
+ Fraction aFract;
+ if ( fHorz < fVert )
+ aFract = Fraction(aPrintSize.Width(), aPageSize.Width());
+ else
+ aFract = Fraction(aPrintSize.Height(), aPageSize.Height());
+
+ aMap.SetScaleX(aFract);
+ aMap.SetScaleY(aFract);
+ aMap.SetOrigin(Point());
+ }
+
+ std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
+ pViewShell->WriteFrameViewData();
+
+ // Count page shapes.
+ sal_uInt32 nShapeCount (0);
+ SdrObjListIter aShapeIter (&rHandoutPage);
+ while (aShapeIter.IsMore())
+ {
+ SdrPageObj* pPageObj = dynamic_cast<SdrPageObj*>(aShapeIter.Next());
+ if (pPageObj)
+ ++nShapeCount;
+ }
+
+ const sal_uInt16 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
+ const sal_uInt16 nHandoutPageCount = nShapeCount ? (nPageCount + nShapeCount - 1) / nShapeCount : 0;
+ pViewShell->SetPrintedHandoutPageCount( nHandoutPageCount );
+ mrBase.GetDocument()->setHandoutPageCount( nHandoutPageCount );
+
+ // Distribute pages to handout pages.
+ StringRangeEnumerator aRangeEnum(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ 0, nPageCount-1);
+ std::vector<sal_uInt16> aPageIndices;
+ sal_uInt16 nPrinterPageIndex = 0;
+ StringRangeEnumerator::Iterator it = aRangeEnum.begin(), itEnd = aRangeEnum.end();
+ bool bLastLoop = (it == itEnd);
+ while (!bLastLoop)
+ {
+ sal_Int32 nPageIndex = *it;
+ ++it;
+ bLastLoop = (it == itEnd);
+
+ if (GetFilteredPage(nPageIndex, PageKind::Standard))
+ aPageIndices.push_back(nPageIndex);
+ else if (!bLastLoop)
+ continue;
+
+ // Create a printer page when we have found one page for each
+ // placeholder or when this is the last (and special) loop.
+ if ( !aPageIndices.empty() && CheckForFrontBackPages( nPageIndex )
+ && (aPageIndices.size() == nShapeCount || bLastLoop) )
+ {
+ maPrinterPages.push_back(
+ std::make_shared<HandoutPrinterPage>(
+ nPrinterPageIndex++,
+ std::move(aPageIndices),
+ aMap,
+ rInfo.msTimeDate,
+ aPageOfs,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ aPageIndices.clear();
+ }
+ }
+ }
+
+ /** Prepare the notes pages or regular slides.
+ */
+ void PrepareStdOrNotes (
+ const PageKind ePageKind,
+ PrintInfo& rInfo)
+ {
+ OSL_ASSERT(rInfo.mpPrinter != nullptr);
+
+ // Fill in page kind specific data.
+ SdDrawDocument* pDocument = mrBase.GetMainViewShell()->GetDoc();
+ if (pDocument->GetSdPageCount(ePageKind) == 0)
+ return;
+ SdPage* pRefPage = pDocument->GetSdPage(0, ePageKind);
+ rInfo.maPageSize = pRefPage->GetSize();
+
+ SetupPaperOrientation(ePageKind, rInfo);
+
+ MapMode aMap (rInfo.maMap);
+ rInfo.maMap = aMap;
+
+ if (mpOptions->IsBooklet())
+ PrepareBooklet(ePageKind, rInfo);
+ else
+ PrepareRegularPages(ePageKind, rInfo);
+ }
+
+ /** Prepare slides in a non-booklet way: one slide per one to many
+ printer pages.
+ */
+ void PrepareRegularPages (
+ const PageKind ePageKind,
+ PrintInfo& rInfo)
+ {
+ std::shared_ptr<ViewShell> pViewShell (mrBase.GetMainViewShell());
+ pViewShell->WriteFrameViewData();
+
+ sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(PageKind::Standard);
+ StringRangeEnumerator aRangeEnum(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ 0, nPageCount-1);
+ for (StringRangeEnumerator::Iterator
+ it = aRangeEnum.begin(),
+ itEnd = aRangeEnum.end();
+ it != itEnd;
+ ++it)
+ {
+ SdPage* pPage = GetFilteredPage(*it, ePageKind);
+ if (pPage == nullptr)
+ continue;
+
+ MapMode aMap (rInfo.maMap);
+ // is it possible that the page size changed?
+ const Size aPageSize = pPage->GetSize();
+
+ if (mpOptions->IsPageSize())
+ {
+ const double fHorz (static_cast<double>(rInfo.maPrintSize.Width()) / aPageSize.Width());
+ const double fVert (static_cast<double>(rInfo.maPrintSize.Height()) / aPageSize.Height());
+
+ Fraction aFract;
+ if (fHorz < fVert)
+ aFract = Fraction(rInfo.maPrintSize.Width(), aPageSize.Width());
+ else
+ aFract = Fraction(rInfo.maPrintSize.Height(), aPageSize.Height());
+
+ aMap.SetScaleX(aFract);
+ aMap.SetScaleY(aFract);
+ aMap.SetOrigin(Point());
+ }
+
+ if (mpOptions->IsPrintPageName())
+ {
+ rInfo.msPageString = pPage->GetName() + " ";
+ }
+ else
+ rInfo.msPageString.clear();
+ rInfo.msPageString += rInfo.msTimeDate;
+
+ ::tools::Long aPageWidth = aPageSize.Width() - pPage->GetLeftBorder() - pPage->GetRightBorder();
+ ::tools::Long aPageHeight = aPageSize.Height() - pPage->GetUpperBorder() - pPage->GetLowerBorder();
+ // Bugfix for 44530:
+ // if it was implicitly changed (Landscape/Portrait),
+ // this is considered for tiling, respectively for the splitting up
+ // (Poster)
+ if( ( rInfo.maPrintSize.Width() > rInfo.maPrintSize.Height()
+ && aPageWidth < aPageHeight )
+ || ( rInfo.maPrintSize.Width() < rInfo.maPrintSize.Height()
+ && aPageWidth > aPageHeight ) )
+ {
+ const sal_Int32 nTmp (rInfo.maPrintSize.Width());
+ rInfo.maPrintSize.setWidth( rInfo.maPrintSize.Height() );
+ rInfo.maPrintSize.setHeight( nTmp );
+ }
+
+ if (mpOptions->IsTilePage()
+ && aPageWidth < rInfo.maPrintSize.Width()
+ && aPageHeight < rInfo.maPrintSize.Height())
+ {
+ // Put multiple slides on one printer page.
+ PrepareTiledPage(*it, *pPage, ePageKind, rInfo);
+ }
+ else
+ {
+ rInfo.maMap = aMap;
+ PrepareScaledPage(*it, *pPage, ePageKind, rInfo);
+ }
+ }
+ }
+
+ /** Put two slides on one printer page.
+ */
+ void PrepareBooklet (
+ const PageKind ePageKind,
+ const PrintInfo& rInfo)
+ {
+ MapMode aStdMap (rInfo.maMap);
+ Point aOffset;
+ Size aPrintSize_2 (rInfo.maPrintSize);
+ Size aPageSize_2 (rInfo.maPageSize);
+
+ if (rInfo.meOrientation == Orientation::Landscape)
+ aPrintSize_2.setWidth( aPrintSize_2.Width() >> 1 );
+ else
+ aPrintSize_2.setHeight( aPrintSize_2.Height() >> 1 );
+
+ const double fPageWH = static_cast<double>(aPageSize_2.Width()) / aPageSize_2.Height();
+ const double fPrintWH = static_cast<double>(aPrintSize_2.Width()) / aPrintSize_2.Height();
+
+ if( fPageWH < fPrintWH )
+ {
+ aPageSize_2.setWidth( static_cast<::tools::Long>( aPrintSize_2.Height() * fPageWH ) );
+ aPageSize_2.setHeight( aPrintSize_2.Height() );
+ }
+ else
+ {
+ aPageSize_2.setWidth( aPrintSize_2.Width() );
+ aPageSize_2.setHeight( static_cast<::tools::Long>( aPrintSize_2.Width() / fPageWH ) );
+ }
+
+ MapMode aMap (rInfo.maMap);
+ aMap.SetScaleX( Fraction( aPageSize_2.Width(), rInfo.maPageSize.Width() ) );
+ aMap.SetScaleY( Fraction( aPageSize_2.Height(), rInfo.maPageSize.Height() ) );
+
+ // calculate adjusted print size
+ const Size aAdjustedPrintSize (OutputDevice::LogicToLogic(
+ rInfo.maPrintSize,
+ aStdMap,
+ aMap));
+
+ if (rInfo.meOrientation == Orientation::Landscape)
+ {
+ aOffset.setX( ( ( aAdjustedPrintSize.Width() >> 1 ) - rInfo.maPageSize.Width() ) >> 1 );
+ aOffset.setY( ( aAdjustedPrintSize.Height() - rInfo.maPageSize.Height() ) >> 1 );
+ }
+ else
+ {
+ aOffset.setX( ( aAdjustedPrintSize.Width() - rInfo.maPageSize.Width() ) >> 1 );
+ aOffset.setY( ( ( aAdjustedPrintSize.Height() >> 1 ) - rInfo.maPageSize.Height() ) >> 1 );
+ }
+
+ // create vector of pages to print
+ sal_Int32 nPageCount = mrBase.GetDocument()->GetSdPageCount(ePageKind);
+ StringRangeEnumerator aRangeEnum(
+ mpOptions->GetPrinterSelection(nPageCount, GetCurrentPageIndex()),
+ 0, nPageCount-1);
+ std::vector< sal_uInt16 > aPageVector;
+ for (StringRangeEnumerator::Iterator
+ it = aRangeEnum.begin(),
+ itEnd = aRangeEnum.end();
+ it != itEnd;
+ ++it)
+ {
+ SdPage* pPage = GetFilteredPage(*it, ePageKind);
+ if (pPage != nullptr)
+ aPageVector.push_back(*it);
+ }
+
+ // create pairs of pages to print on each page
+ std::vector< std::pair< sal_uInt16, sal_uInt16 > > aPairVector;
+ if ( ! aPageVector.empty())
+ {
+ sal_uInt32 nFirstIndex = 0, nLastIndex = aPageVector.size() - 1;
+
+ if( aPageVector.size() & 1 )
+ aPairVector.emplace_back( sal_uInt16(65535), aPageVector[ nFirstIndex++ ] );
+ else
+ aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
+
+ while( nFirstIndex < nLastIndex )
+ {
+ if( nFirstIndex & 1 )
+ aPairVector.emplace_back( aPageVector[ nFirstIndex++ ], aPageVector[ nLastIndex-- ] );
+ else
+ aPairVector.emplace_back( aPageVector[ nLastIndex-- ], aPageVector[ nFirstIndex++ ] );
+ }
+ }
+
+ for (sal_uInt32
+ nIndex=0,
+ nCount=aPairVector.size();
+ nIndex < nCount;
+ ++nIndex)
+ {
+ if ( CheckForFrontBackPages( nIndex ) )
+ {
+ const std::pair<sal_uInt16, sal_uInt16> aPair (aPairVector[nIndex]);
+ Point aSecondOffset (aOffset);
+ if (rInfo.meOrientation == Orientation::Landscape)
+ aSecondOffset.AdjustX( aAdjustedPrintSize.Width() / 2 );
+ else
+ aSecondOffset.AdjustY( aAdjustedPrintSize.Height() / 2 );
+ maPrinterPages.push_back(
+ std::make_shared<BookletPrinterPage>(
+ aPair.first,
+ aPair.second,
+ aOffset,
+ aSecondOffset,
+ ePageKind,
+ aMap,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ rInfo.mpPrinter->GetPaperBin()));
+
+ }
+ }
+ }
+
+ /** Print one slide multiple times on one printer page so that the whole
+ printer page is covered.
+ */
+ void PrepareTiledPage (
+ const sal_Int32 nPageIndex,
+ const SdPage& rPage,
+ const PageKind ePageKind,
+ const PrintInfo& rInfo)
+ {
+ sal_uInt16 nPaperBin;
+ if ( ! mpOptions->IsPaperBin())
+ nPaperBin = rPage.GetPaperBin();
+ else
+ nPaperBin = rInfo.mpPrinter->GetPaperBin();
+
+ if ( !CheckForFrontBackPages( nPageIndex ) )
+ return;
+
+ maPrinterPages.push_back(
+ std::make_shared<TiledPrinterPage>(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.msPageString,
+ rInfo.mpPrinter->GetPageOffset(),
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ }
+
+ /** Print one standard slide or notes page on one to many printer
+ pages. More than on printer page is used when the slide is larger
+ than the printable area.
+ */
+ void PrepareScaledPage (
+ const sal_Int32 nPageIndex,
+ const SdPage& rPage,
+ const PageKind ePageKind,
+ const PrintInfo& rInfo)
+ {
+ const Point aPageOffset (rInfo.mpPrinter->GetPageOffset());
+
+ sal_uInt16 nPaperBin;
+ if ( ! mpOptions->IsPaperBin())
+ nPaperBin = rPage.GetPaperBin();
+ else
+ nPaperBin = rInfo.mpPrinter->GetPaperBin();
+
+ // For pages larger then the printable area there
+ // are three options:
+ // 1. Scale down to the page to the printable area.
+ // 2. Print only the upper left part of the page
+ // (without the unprintable borders).
+ // 3. Split the page into parts of the size of the
+ // printable area.
+ const bool bScalePage (mpOptions->IsPageSize());
+ const bool bCutPage (mpOptions->IsCutPage());
+ MapMode aMap (rInfo.maMap);
+ if ( (bScalePage || bCutPage) && CheckForFrontBackPages( nPageIndex ) )
+ {
+ // Handle 1 and 2.
+
+ // if CutPage is set then do not move it, otherwise move the
+ // scaled page to printable area
+ maPrinterPages.push_back(
+ std::make_shared<RegularPrinterPage>(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind,
+ aMap,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.msPageString,
+ aPageOffset,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ }
+ else
+ {
+ // Handle 3. Print parts of the page in the size of the
+ // printable area until the whole page is covered.
+
+ // keep the page content at its position if it fits, otherwise
+ // move it to the printable area
+ const ::tools::Long nPageWidth (
+ rInfo.maPageSize.Width() - rPage.GetLeftBorder() - rPage.GetRightBorder());
+ const ::tools::Long nPageHeight (
+ rInfo.maPageSize.Height() - rPage.GetUpperBorder() - rPage.GetLowerBorder());
+
+ Point aOrigin ( 0, 0 );
+
+ for (Point aPageOrigin = aOrigin;
+ -aPageOrigin.Y()<nPageHeight;
+ aPageOrigin.AdjustY( -rInfo.maPrintSize.Height() ))
+ {
+ for (aPageOrigin.setX(aOrigin.X());
+ -aPageOrigin.X()<nPageWidth;
+ aPageOrigin.AdjustX(-rInfo.maPrintSize.Width()))
+ {
+ if ( CheckForFrontBackPages( nPageIndex ) )
+ {
+ aMap.SetOrigin(aPageOrigin);
+ maPrinterPages.push_back(
+ std::make_shared<RegularPrinterPage>(
+ sal::static_int_cast<sal_uInt16>(nPageIndex),
+ ePageKind,
+ aMap,
+ rInfo.mbPrintMarkedOnly,
+ rInfo.msPageString,
+ aPageOffset,
+ rInfo.mnDrawMode,
+ rInfo.meOrientation,
+ nPaperBin));
+ }
+ }
+ }
+ }
+ }
+
+bool CheckForFrontBackPages( sal_Int32 nPage )
+{
+ const bool bIsIndexOdd(nPage & 1);
+ if ((!bIsIndexOdd && mpOptions->IsPrintFrontPage())
+ || (bIsIndexOdd && mpOptions->IsPrintBackPage()))
+ {
+ return true;
+ }
+ else
+ return false;
+}
+};
+
+//===== DocumentRenderer ======================================================
+
+DocumentRenderer::DocumentRenderer (ViewShellBase& rBase)
+ : mpImpl(new Implementation(rBase))
+{
+}
+
+DocumentRenderer::~DocumentRenderer()
+{
+}
+
+//----- XRenderable -----------------------------------------------------------
+
+sal_Int32 SAL_CALL DocumentRenderer::getRendererCount (
+ const css::uno::Any&,
+ const css::uno::Sequence<css::beans::PropertyValue >& rOptions)
+{
+ mpImpl->ProcessProperties(rOptions);
+ return mpImpl->GetPrintPageCount();
+}
+
+Sequence<beans::PropertyValue> SAL_CALL DocumentRenderer::getRenderer (
+ sal_Int32,
+ const css::uno::Any&,
+ const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
+{
+ mpImpl->ProcessProperties(rOptions);
+ return mpImpl->GetProperties();
+}
+
+void SAL_CALL DocumentRenderer::render (
+ sal_Int32 nRenderer,
+ const css::uno::Any&,
+ const css::uno::Sequence<css::beans::PropertyValue>& rOptions)
+{
+ mpImpl->ProcessProperties(rOptions);
+ mpImpl->PrintPage(nRenderer);
+}
+
+} // end of namespace sd
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */