diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /filter/source/pdf | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.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 'filter/source/pdf')
-rw-r--r-- | filter/source/pdf/impdialog.cxx | 1638 | ||||
-rw-r--r-- | filter/source/pdf/impdialog.hxx | 419 | ||||
-rw-r--r-- | filter/source/pdf/pdfdecomposer.cxx | 123 | ||||
-rw-r--r-- | filter/source/pdf/pdfdialog.cxx | 139 | ||||
-rw-r--r-- | filter/source/pdf/pdfdialog.hxx | 72 | ||||
-rw-r--r-- | filter/source/pdf/pdfexport.cxx | 1374 | ||||
-rw-r--r-- | filter/source/pdf/pdfexport.hxx | 145 | ||||
-rw-r--r-- | filter/source/pdf/pdffilter.component | 38 | ||||
-rw-r--r-- | filter/source/pdf/pdffilter.cxx | 295 | ||||
-rw-r--r-- | filter/source/pdf/pdffilter.hxx | 70 | ||||
-rw-r--r-- | filter/source/pdf/pdfinteract.cxx | 97 | ||||
-rw-r--r-- | filter/source/pdf/pdfinteract.hxx | 61 |
12 files changed, 4471 insertions, 0 deletions
diff --git a/filter/source/pdf/impdialog.cxx b/filter/source/pdf/impdialog.cxx new file mode 100644 index 000000000..bd8db8369 --- /dev/null +++ b/filter/source/pdf/impdialog.cxx @@ -0,0 +1,1638 @@ +/* -*- 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 "impdialog.hxx" +#include <strings.hrc> +#include <officecfg/Office/Common.hxx> +#include <vcl/errinf.hxx> +#include <vcl/svapp.hxx> +#include <vcl/weld.hxx> +#include <sfx2/passwd.hxx> +#include <unotools/resmgr.hxx> +#include <tools/diagnose_ex.h> +#include <sfx2/objsh.hxx> +#include <svx/AccessibilityCheckDialog.hxx> + +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/storagehelper.hxx> + +#include <com/sun/star/text/XTextRange.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/container/XIndexAccess.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> +#include <com/sun/star/security/DocumentDigitalSignatures.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +static OUString PDFFilterResId(TranslateId aId) +{ + return Translate::get(aId, Translate::Create("flt")); +} + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; + +/** Tabbed PDF dialog implementation + Please note: the default used here are the same as per specification, + They should be the same in PDFFilter::implExport and in PDFExport::PDFExport + */ +ImpPDFTabDialog::ImpPDFTabDialog(weld::Window* pParent, const Sequence< PropertyValue >& rFilterData, + const Reference< XComponent >& rxDoc) + : SfxTabDialogController(pParent, "filter/ui/pdfoptionsdialog.ui", "PdfOptionsDialog"), + mrDoc(rxDoc), + mpParent(pParent), + maConfigItem( u"Office.Common/Filter/PDF/Export/", &rFilterData ), + maConfigI18N( u"Office.Common/I18N/CTL/" ), + mbIsPresentation( false ), + mbIsSpreadsheet( false ), + mbIsWriter( false ), + + mbSelectionPresent( false ), + mbUseCTLFont( false ), + mbUseLosslessCompression( true ), + mnQuality( 90 ), + mbReduceImageResolution( false ), + mnMaxImageResolution( 300 ), + mbUseTaggedPDF( false ), + mbUseTaggedPDFUserSelection( false ), + mbExportNotes( true ), + mbViewPDF( false ), + mbUseReferenceXObject( false ), + mbExportNotesPages( false ), + mbExportOnlyNotesPages( false ), + mbUseTransitionEffects( false ), + mbIsSkipEmptyPages( true ), + mbIsExportPlaceholders( false ), + mbAddStream( false ), + mnFormsType( 0 ), + mbExportFormFields( true ), + mbAllowDuplicateFieldNames( false ), + mbExportBookmarks( true ), + mbExportHiddenSlides ( false ), + mbSinglePageSheets ( false ), + mnOpenBookmarkLevels( -1 ), + + mbHideViewerToolbar( false ), + mbHideViewerMenubar( false ), + mbHideViewerWindowControls( false ), + mbResizeWinToInit( false ), + mbCenterWindow( false ), + mbOpenInFullScreenMode( false ), + mbDisplayPDFDocumentTitle( false ), + mnMagnification( 0 ), + mnInitialView( 0 ), + mnZoom( 0 ), + mnInitialPage( 1 ), + mnPageLayout( 0 ), + mbFirstPageLeft( false ), + + mbEncrypt( false ), + mbRestrictPermissions( false ), + mnPrint( 0 ), + mnChangesAllowed( 0 ), + mbCanCopyOrExtract( false ), + mbCanExtractForAccessibility( true ), + + mbIsRangeChecked( false ), + msPageRange( ' ' ), + + mbSelectionIsChecked( false ), + mbExportRelativeFsysLinks( false ), + mnViewPDFMode( 0 ), + mbConvertOOoTargets( false ), + mbExportBmkToPDFDestination( false ), + + mbSignPDF( false ) +{ + // check for selection + try + { + Reference< frame::XController > xController( Reference< frame::XModel >( rxDoc, UNO_QUERY_THROW )->getCurrentController() ); + if( xController.is() ) + { + Reference< view::XSelectionSupplier > xView( xController, UNO_QUERY ); + if( xView.is() ) + maSelection = xView->getSelection(); + } + } + catch(const RuntimeException &) + { + } + mbSelectionPresent = maSelection.hasValue(); + if ( mbSelectionPresent ) + { + Reference< drawing::XShapes > xShapes; + if ( !( maSelection >>= xShapes ) ) // XShapes is always a selection + { + // even if nothing is selected in writer the selection is not empty + Reference< container::XIndexAccess > xIndexAccess; + if ( maSelection >>= xIndexAccess ) + { + sal_Int32 nLen = xIndexAccess->getCount(); + if ( !nLen ) + mbSelectionPresent = false; + else if ( nLen == 1 ) + { + Reference< text::XTextRange > xTextRange( xIndexAccess->getByIndex( 0 ), UNO_QUERY ); + if ( xTextRange.is() && ( xTextRange->getString().isEmpty() ) ) + mbSelectionPresent = false; + } + } + } + } + + // check if source document is a presentation or a spreadsheet or a textdocument + try + { + Reference< XServiceInfo > xInfo( rxDoc, UNO_QUERY ); + if ( xInfo.is() ) + { + if ( xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) ) + mbIsPresentation = true; + if ( xInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) + mbIsSpreadsheet = true; + if ( xInfo->supportsService( "com.sun.star.text.GenericTextDocument" ) ) + mbIsWriter = true; + } + } + catch(const RuntimeException &) + { + } + + // get the CTL (Complex Text Layout) from general options, returns sal_True if we have a CTL font on our hands. + mbUseCTLFont = maConfigI18N.ReadBool( "CTLFont", false ); + + mbUseLosslessCompression = maConfigItem.ReadBool( "UseLosslessCompression", false ); + mnQuality = maConfigItem.ReadInt32( "Quality", 90 ); + mbReduceImageResolution = maConfigItem.ReadBool( "ReduceImageResolution", false ); + mnMaxImageResolution = maConfigItem.ReadInt32( "MaxImageResolution", 300 ); + + // this is always the user selection, independent from the PDF/A forced selection + mbUseTaggedPDF = maConfigItem.ReadBool( "UseTaggedPDF", false ); + mbUseTaggedPDFUserSelection = mbUseTaggedPDF; + + mnPDFTypeSelection = maConfigItem.ReadInt32( "SelectPdfVersion", 0 ); + mbPDFUACompliance = maConfigItem.ReadBool("PDFUACompliance", false); + + if ( mbIsPresentation ) + { + mbExportNotesPages = maConfigItem.ReadBool( "ExportNotesPages", false ); + mbExportOnlyNotesPages = maConfigItem.ReadBool( "ExportOnlyNotesPages", false ); + } + mbExportNotes = maConfigItem.ReadBool( "ExportNotes", false ); + mbViewPDF = maConfigItem.ReadBool( "ViewPDFAfterExport", false ); + + mbExportBookmarks = maConfigItem.ReadBool( "ExportBookmarks", true ); + if ( mbIsPresentation ) + mbExportHiddenSlides = maConfigItem.ReadBool( "ExportHiddenSlides", false ); + if ( mbIsSpreadsheet ) + mbSinglePageSheets = maConfigItem.ReadBool( "SinglePageSheets", false ); + mnOpenBookmarkLevels = maConfigItem.ReadInt32( "OpenBookmarkLevels", -1 ); + mbUseTransitionEffects = maConfigItem.ReadBool( "UseTransitionEffects", true ); + mbIsSkipEmptyPages = maConfigItem.ReadBool( "IsSkipEmptyPages", false ); + mbIsExportPlaceholders = maConfigItem.ReadBool( "ExportPlaceholders", false ); + mbAddStream = maConfigItem.ReadBool( "IsAddStream", false ); + + mbExportFormFields = maConfigItem.ReadBool( "ExportFormFields", true ); + mnFormsType = maConfigItem.ReadInt32( "FormsType", 0 ); + if ( ( mnFormsType < 0 ) || ( mnFormsType > 3 ) ) + mnFormsType = 0; + mbAllowDuplicateFieldNames = maConfigItem.ReadBool( "AllowDuplicateFieldNames", false ); + + // prepare values for the Viewer tab page + mbHideViewerToolbar = maConfigItem.ReadBool( "HideViewerToolbar", false ); + mbHideViewerMenubar = maConfigItem.ReadBool( "HideViewerMenubar", false ); + mbHideViewerWindowControls = maConfigItem.ReadBool( "HideViewerWindowControls", false ); + mbResizeWinToInit = maConfigItem.ReadBool( "ResizeWindowToInitialPage", false ); + mbCenterWindow = maConfigItem.ReadBool( "CenterWindow", false ); + mbOpenInFullScreenMode = maConfigItem.ReadBool( "OpenInFullScreenMode", false ); + mbDisplayPDFDocumentTitle = maConfigItem.ReadBool( "DisplayPDFDocumentTitle", true ); + + mnInitialView = maConfigItem.ReadInt32( "InitialView", 0 ); + mnMagnification = maConfigItem.ReadInt32( "Magnification", 0 ); + mnZoom = maConfigItem.ReadInt32( "Zoom", 100 ); + mnPageLayout = maConfigItem.ReadInt32( "PageLayout", 0 ); + mbFirstPageLeft = maConfigItem.ReadBool( "FirstPageOnLeft", false ); + mnInitialPage = maConfigItem.ReadInt32( "InitialPage", 1 ); + if( mnInitialPage < 1 ) + mnInitialPage = 1; + + // prepare values for the security tab page + mnPrint = maConfigItem.ReadInt32( "Printing", 2 ); + mnChangesAllowed = maConfigItem.ReadInt32( "Changes", 4 ); + mbCanCopyOrExtract = maConfigItem.ReadBool( "EnableCopyingOfContent", true ); + mbCanExtractForAccessibility = maConfigItem.ReadBool( "EnableTextAccessForAccessibilityTools", true ); + + // prepare values for relative links + mbExportRelativeFsysLinks = maConfigItem.ReadBool( "ExportLinksRelativeFsys", false ); + + mnViewPDFMode = maConfigItem.ReadInt32( "PDFViewSelection", 0 ); + + mbConvertOOoTargets = maConfigItem.ReadBool( "ConvertOOoTargetToPDFTarget", false ); + mbExportBmkToPDFDestination = maConfigItem.ReadBool( "ExportBookmarksToPDFDestination", false ); + + // prepare values for digital signatures + mbSignPDF = maConfigItem.ReadBool( "SignPDF", false ); + + // queue the tab pages for later creation (created when first shown) + AddTabPage("general", ImpPDFTabGeneralPage::Create, nullptr ); + AddTabPage("digitalsignatures", ImpPDFTabSigningPage::Create, nullptr); + AddTabPage("security", ImpPDFTabSecurityPage::Create, nullptr); + AddTabPage("links", ImpPDFTabLinksPage::Create, nullptr); + AddTabPage("userinterface", ImpPDFTabViewerPage::Create, nullptr); + AddTabPage("initialview", ImpPDFTabOpnFtrPage::Create, nullptr); + + SetCurPageId("general"); + + // get the string property value (from sfx2/source/dialog/mailmodel.cxx) to overwrite the text for the Ok button + OUString sOkButtonText = maConfigItem.ReadString( "_OkButtonString", OUString() ); + + // change text on the Ok button: get the relevant string from resources, update it on the button + // according to the exported pdf file destination: send as e-mail or write to file? + if (!sOkButtonText.isEmpty()) + GetOKButton().set_label(sOkButtonText); + + GetCancelButton().connect_clicked(LINK(this, ImpPDFTabDialog, CancelHdl)); + GetOKButton().connect_clicked(LINK(this, ImpPDFTabDialog, OkHdl)); + + // remove the reset button, not needed in this tabbed dialog + RemoveResetButton(); +} + +ImpPDFTabSecurityPage* ImpPDFTabDialog::getSecurityPage() const +{ + SfxTabPage* pSecurityPage = GetTabPage("security"); + if (pSecurityPage) + { + return static_cast<ImpPDFTabSecurityPage*>(pSecurityPage); + } + return nullptr; +} + + +ImpPDFTabLinksPage* ImpPDFTabDialog::getLinksPage() const +{ + SfxTabPage* pLinksPage = GetTabPage("links"); + if (pLinksPage) + { + return static_cast<ImpPDFTabLinksPage*>(pLinksPage); + } + return nullptr; +} + + +ImpPDFTabGeneralPage* ImpPDFTabDialog::getGeneralPage() const +{ + SfxTabPage* pGeneralPage = GetTabPage("general"); + if (pGeneralPage) + { + return static_cast<ImpPDFTabGeneralPage*>(pGeneralPage); + } + return nullptr; +} + +IMPL_LINK_NOARG(ImpPDFTabDialog, CancelHdl, weld::Button&, void) +{ + m_xDialog->response(RET_CANCEL); +} + +IMPL_LINK_NOARG(ImpPDFTabDialog, OkHdl, weld::Button&, void) +{ + if (getGeneralPage()->IsPdfUaSelected()) + { + SfxObjectShell* pShell = SfxObjectShell::GetShellFromComponent(mrDoc); + if (pShell) + { + sfx::AccessibilityIssueCollection aCollection = pShell->runAccessibilityCheck(); + if (!aCollection.getIssues().empty()) + { + mpAccessibilityCheckDialog = std::make_shared<svx::AccessibilityCheckDialog>(mpParent, aCollection); + weld::DialogController::runAsync(mpAccessibilityCheckDialog, [this](sal_Int32 retValue){ + m_xDialog->response(retValue); + }); + } + else + { + m_xDialog->response(RET_OK); + } + } + else + { + m_xDialog->response(RET_OK); + } + } + else + { + m_xDialog->response(RET_OK); + } +} + +ImpPDFTabDialog::~ImpPDFTabDialog() +{ + maConfigItem.WriteModifiedConfig(); + maConfigI18N.WriteModifiedConfig(); + if (mpAccessibilityCheckDialog) + { + mpAccessibilityCheckDialog->response(RET_CANCEL); + } +} + +void ImpPDFTabDialog::PageCreated(const OString& rId, SfxTabPage& rPage) +{ + if (rId == "general") + static_cast<ImpPDFTabGeneralPage&>(rPage).SetFilterConfigItem(this); + else if (rId == "userinterface") + { + static_cast<ImpPDFTabViewerPage&>(rPage).SetFilterConfigItem(this); + } + else if (rId == "initialview") + { + static_cast<ImpPDFTabOpnFtrPage&>(rPage).SetFilterConfigItem(this); + } + else if (rId == "links") + { + static_cast<ImpPDFTabLinksPage&>(rPage).SetFilterConfigItem(this); + } + else if (rId == "security") + { + static_cast<ImpPDFTabSecurityPage&>(rPage).SetFilterConfigItem(this); + } + else if (rId == "digitalsignatures") + { + static_cast<ImpPDFTabSigningPage&>(rPage).SetFilterConfigItem(this); + } +} + + +Sequence< PropertyValue > ImpPDFTabDialog::GetFilterData() +{ + // updating the FilterData sequence and storing FilterData to configuration + if (ImpPDFTabGeneralPage* pPage = static_cast<ImpPDFTabGeneralPage*>(GetTabPage("general"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabViewerPage* pPage = static_cast<ImpPDFTabViewerPage*>(GetTabPage("userinterface"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabOpnFtrPage* pPage = static_cast<ImpPDFTabOpnFtrPage*>(GetTabPage("initialview"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabLinksPage* pPage = static_cast<ImpPDFTabLinksPage*>(GetTabPage("links"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabSecurityPage* pPage = static_cast<ImpPDFTabSecurityPage*>( GetTabPage("security"))) + pPage->GetFilterConfigItem(this); + if (ImpPDFTabSigningPage* pPage = static_cast<ImpPDFTabSigningPage*>(GetTabPage("digitalsignatures"))) + pPage->GetFilterConfigItem(this); + + // prepare the items to be returned + maConfigItem.WriteBool( "UseLosslessCompression", mbUseLosslessCompression ); + maConfigItem.WriteInt32("Quality", mnQuality ); + maConfigItem.WriteBool( "ReduceImageResolution", mbReduceImageResolution ); + maConfigItem.WriteInt32("MaxImageResolution", mnMaxImageResolution ); + + // always write the user selection, never the overridden value + const bool bIsPDFUA = mbPDFUACompliance; + const bool bIsPDFA = (1 == mnPDFTypeSelection) || (2 == mnPDFTypeSelection) || (3 == mnPDFTypeSelection); + const bool bUserSelectionTags = bIsPDFA || bIsPDFUA; + maConfigItem.WriteBool("UseTaggedPDF", bUserSelectionTags ? mbUseTaggedPDFUserSelection : mbUseTaggedPDF); + maConfigItem.WriteInt32("SelectPdfVersion", mnPDFTypeSelection ); + maConfigItem.WriteBool("PDFUACompliance", mbPDFUACompliance); + + if ( mbIsPresentation ) + { + maConfigItem.WriteBool( "ExportNotesPages", mbExportNotesPages ); + maConfigItem.WriteBool( "ExportOnlyNotesPages", mbExportOnlyNotesPages ); + } + maConfigItem.WriteBool( "ExportNotes", mbExportNotes ); + maConfigItem.WriteBool( "ViewPDFAfterExport", mbViewPDF ); + + maConfigItem.WriteBool( "ExportBookmarks", mbExportBookmarks ); + if ( mbIsPresentation ) + maConfigItem.WriteBool( "ExportHiddenSlides", mbExportHiddenSlides ); + if ( mbIsSpreadsheet ) + maConfigItem.WriteBool( "SinglePageSheets", mbSinglePageSheets ); + maConfigItem.WriteBool( "UseTransitionEffects", mbUseTransitionEffects ); + maConfigItem.WriteBool( "IsSkipEmptyPages", mbIsSkipEmptyPages ); + maConfigItem.WriteBool( "ExportPlaceholders", mbIsExportPlaceholders ); + maConfigItem.WriteBool( "IsAddStream", mbAddStream ); + + /* + * FIXME: the entries are only implicitly defined by the resource file. Should there + * ever be an additional form submit format this could get invalid. + */ + maConfigItem.WriteInt32( "FormsType", mnFormsType ); + maConfigItem.WriteBool( "ExportFormFields", mbExportFormFields ); + maConfigItem.WriteBool( "AllowDuplicateFieldNames", mbAllowDuplicateFieldNames ); + + maConfigItem.WriteBool( "HideViewerToolbar", mbHideViewerToolbar ); + maConfigItem.WriteBool( "HideViewerMenubar", mbHideViewerMenubar ); + maConfigItem.WriteBool( "HideViewerWindowControls", mbHideViewerWindowControls ); + maConfigItem.WriteBool( "ResizeWindowToInitialPage", mbResizeWinToInit ); + maConfigItem.WriteBool( "CenterWindow", mbCenterWindow ); + maConfigItem.WriteBool( "OpenInFullScreenMode", mbOpenInFullScreenMode ); + maConfigItem.WriteBool( "DisplayPDFDocumentTitle", mbDisplayPDFDocumentTitle ); + maConfigItem.WriteInt32( "InitialView", mnInitialView ); + maConfigItem.WriteInt32( "Magnification", mnMagnification); + maConfigItem.WriteInt32( "Zoom", mnZoom ); + maConfigItem.WriteInt32( "InitialPage", mnInitialPage ); + maConfigItem.WriteInt32( "PageLayout", mnPageLayout ); + maConfigItem.WriteBool( "FirstPageOnLeft", mbFirstPageLeft ); + maConfigItem.WriteInt32( "OpenBookmarkLevels", mnOpenBookmarkLevels ); + + maConfigItem.WriteBool( "ExportLinksRelativeFsys", mbExportRelativeFsysLinks ); + maConfigItem.WriteInt32("PDFViewSelection", mnViewPDFMode ); + maConfigItem.WriteBool( "ConvertOOoTargetToPDFTarget", mbConvertOOoTargets ); + maConfigItem.WriteBool( "ExportBookmarksToPDFDestination", mbExportBmkToPDFDestination ); + + maConfigItem.WriteBool( "SignPDF", mbSignPDF ); + + maConfigItem.WriteInt32( "Printing", mnPrint ); + maConfigItem.WriteInt32( "Changes", mnChangesAllowed ); + maConfigItem.WriteBool( "EnableCopyingOfContent", mbCanCopyOrExtract ); + maConfigItem.WriteBool( "EnableTextAccessForAccessibilityTools", mbCanExtractForAccessibility ); + + std::vector<beans::PropertyValue> aRet + { + comphelper::makePropertyValue("Watermark", maWatermarkText), + comphelper::makePropertyValue("EncryptFile", mbEncrypt), + comphelper::makePropertyValue("PreparedPasswords", mxPreparedPasswords), + comphelper::makePropertyValue("RestrictPermissions", mbRestrictPermissions), + comphelper::makePropertyValue("PreparedPermissionPassword", maPreparedOwnerPassword) + }; + if( mbIsRangeChecked ) + aRet.push_back(comphelper::makePropertyValue("PageRange", msPageRange)); + else if( mbSelectionIsChecked ) + aRet.push_back(comphelper::makePropertyValue("Selection", maSelection)); + + aRet.push_back(comphelper::makePropertyValue("SignatureLocation", msSignLocation)); + aRet.push_back(comphelper::makePropertyValue("SignatureReason", msSignReason)); + aRet.push_back(comphelper::makePropertyValue("SignatureContactInfo", msSignContact)); + aRet.push_back(comphelper::makePropertyValue("SignaturePassword", msSignPassword)); + aRet.push_back(comphelper::makePropertyValue("SignatureCertificate", maSignCertificate)); + aRet.push_back(comphelper::makePropertyValue("SignatureTSA", msSignTSA)); + aRet.push_back(comphelper::makePropertyValue("UseReferenceXObject", mbUseReferenceXObject)); + + return comphelper::concatSequences(maConfigItem.GetFilterData(), comphelper::containerToSequence(aRet)); +} + + +ImpPDFTabGeneralPage::ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfgeneralpage.ui", "PdfGeneralPage", &rCoreSet) + , mbUseTaggedPDFUserSelection(false) + , mbIsPresentation(false) + , mbIsSpreadsheet(false) + , mbIsWriter(false) + , mpParent(nullptr) + , mxRbAll(m_xBuilder->weld_radio_button("all")) + , mxRbRange(m_xBuilder->weld_radio_button("range")) + , mxRbSelection(m_xBuilder->weld_radio_button("selection")) + , mxEdPages(m_xBuilder->weld_entry("pages")) + , mxSelectedSheets(m_xBuilder->weld_label("selectedsheets")) + , mxRbLosslessCompression(m_xBuilder->weld_radio_button("losslesscompress")) + , mxRbJPEGCompression(m_xBuilder->weld_radio_button("jpegcompress")) + , mxQualityFrame(m_xBuilder->weld_widget("qualityframe")) + , mxNfQuality(m_xBuilder->weld_metric_spin_button("quality", FieldUnit::PERCENT)) + , mxCbReduceImageResolution(m_xBuilder->weld_check_button("reduceresolution")) + , mxCoReduceImageResolution(m_xBuilder->weld_combo_box("resolution")) + , mxCbPDFA(m_xBuilder->weld_check_button("pdfa")) + , mxCbPDFUA(m_xBuilder->weld_check_button("pdfua")) + , mxRbPDFAVersion(m_xBuilder->weld_combo_box("pdfaversion")) + , mxCbTaggedPDF(m_xBuilder->weld_check_button("tagged")) + , mxCbExportFormFields(m_xBuilder->weld_check_button("forms")) + , mxFormsFrame(m_xBuilder->weld_widget("formsframe")) + , mxLbFormsFormat(m_xBuilder->weld_combo_box("format")) + , mxCbAllowDuplicateFieldNames(m_xBuilder->weld_check_button("allowdups")) + , mxCbExportBookmarks(m_xBuilder->weld_check_button("bookmarks")) + , mxCbExportHiddenSlides(m_xBuilder->weld_check_button("hiddenpages")) + , mxCbSinglePageSheets(m_xBuilder->weld_check_button("singlepagesheets")) + , mxCbExportNotes(m_xBuilder->weld_check_button("comments")) + , mxCbViewPDF(m_xBuilder->weld_check_button("viewpdf")) + , mxCbUseReferenceXObject(m_xBuilder->weld_check_button("usereferencexobject")) + , mxCbExportNotesPages(m_xBuilder->weld_check_button("notes")) + , mxCbExportOnlyNotesPages(m_xBuilder->weld_check_button("onlynotes")) + , mxCbExportEmptyPages(m_xBuilder->weld_check_button("emptypages")) + , mxCbExportPlaceholders(m_xBuilder->weld_check_button("exportplaceholders")) + , mxCbAddStream(m_xBuilder->weld_check_button("embed")) + , mxCbWatermark(m_xBuilder->weld_check_button("watermark")) + , mxFtWatermark(m_xBuilder->weld_label("watermarklabel")) + , mxEdWatermark(m_xBuilder->weld_entry("watermarkentry")) + , mxSlidesFt(m_xBuilder->weld_label("slides")) + , mxSheetsFt(m_xBuilder->weld_label("selectedsheets")) +{ +} + +ImpPDFTabGeneralPage::~ImpPDFTabGeneralPage() +{ +} + +void ImpPDFTabGeneralPage::SetFilterConfigItem(ImpPDFTabDialog* pParent) +{ + mpParent = pParent; + + // init this class data + mxRbRange->connect_toggled( LINK( this, ImpPDFTabGeneralPage, TogglePagesHdl ) ); + + mxRbAll->set_active(true); + mxRbAll->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleAllHdl ) ); + TogglePagesHdl(); + + const bool bSelectionPresent = pParent->mbSelectionPresent; + mxRbSelection->set_sensitive( bSelectionPresent ); + if ( bSelectionPresent ) + mxRbSelection->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleSelectionHdl ) ); + mbIsPresentation = pParent->mbIsPresentation; + mbIsWriter = pParent->mbIsWriter; + mbIsSpreadsheet = pParent->mbIsSpreadsheet; + + mxCbExportEmptyPages->set_sensitive( mbIsWriter ); + mxCbExportPlaceholders->set_sensitive( mbIsWriter ); + + mxRbLosslessCompression->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleCompressionHdl ) ); + const bool bUseLosslessCompression = pParent->mbUseLosslessCompression; + if ( bUseLosslessCompression ) + mxRbLosslessCompression->set_active(true); + else + mxRbJPEGCompression->set_active(true); + + mxNfQuality->set_value( pParent->mnQuality, FieldUnit::PERCENT ); + mxQualityFrame->set_sensitive(!bUseLosslessCompression); + + mxCbReduceImageResolution->connect_toggled(LINK(this, ImpPDFTabGeneralPage, ToggleReduceImageResolutionHdl)); + const bool bReduceImageResolution = pParent->mbReduceImageResolution; + mxCbReduceImageResolution->set_active( bReduceImageResolution ); + OUString aStrRes = OUString::number( pParent->mnMaxImageResolution ) + " DPI"; + mxCoReduceImageResolution->set_entry_text(aStrRes); + mxCoReduceImageResolution->set_sensitive( bReduceImageResolution ); + mxCbWatermark->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleWatermarkHdl ) ); + mxFtWatermark->set_sensitive(false ); + mxEdWatermark->set_sensitive( false ); + mxCbPDFA->connect_toggled(LINK(this, ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle)); + + const bool bIsPDFA = (pParent->mnPDFTypeSelection>=1) && (pParent->mnPDFTypeSelection <= 3); + mxCbPDFA->set_active(bIsPDFA); + switch( pParent->mnPDFTypeSelection ) + { + case 1: // PDF/A-1 + mxRbPDFAVersion->set_active_id("1"); + break; + case 2: // PDF/A-2 + mxRbPDFAVersion->set_active_id("2"); + break; + case 3: // PDF/A-3 + default: // PDF 1.x + mxRbPDFAVersion->set_active_id("3"); + break; + } + + const bool bIsPDFUA = pParent->mbPDFUACompliance; + mxCbPDFUA->set_active(bIsPDFUA); + mxCbPDFUA->connect_toggled(LINK(this, ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle)); + + // the TogglePDFVersionOrUniversalAccessibilityHandle handler will read or write the *UserSelection based + // on the mxCbPDFA (= bIsPDFA) state, so we have to prepare the correct input state. + if (bIsPDFA || bIsPDFUA) + mxCbTaggedPDF->set_active(pParent->mbUseTaggedPDFUserSelection); + else + mbUseTaggedPDFUserSelection = pParent->mbUseTaggedPDFUserSelection; + TogglePDFVersionOrUniversalAccessibilityHandle(*mxCbPDFA); + + mxCbExportFormFields->set_active(pParent->mbExportFormFields); + mxCbExportFormFields->connect_toggled( LINK( this, ImpPDFTabGeneralPage, ToggleExportFormFieldsHdl ) ); + + mxLbFormsFormat->set_active(static_cast<sal_uInt16>(pParent->mnFormsType)); + mxCbAllowDuplicateFieldNames->set_active( pParent->mbAllowDuplicateFieldNames ); + mxFormsFrame->set_sensitive(pParent->mbExportFormFields); + + mxCbExportBookmarks->set_active( pParent->mbExportBookmarks ); + + mxCbExportNotes->set_active( pParent->mbExportNotes ); + mxCbViewPDF->set_active( pParent->mbViewPDF); + + if ( mbIsPresentation ) + { + mxRbRange->set_label(mxSlidesFt->get_label()); + mxCbExportNotesPages->show(); + mxCbExportNotesPages->set_active(pParent->mbExportNotesPages); + mxCbExportNotesPages->connect_toggled( LINK(this, ImpPDFTabGeneralPage, ToggleExportNotesPagesHdl ) ); + mxCbExportOnlyNotesPages->show(); + mxCbExportOnlyNotesPages->set_active(pParent->mbExportOnlyNotesPages); + // tdf#116473 Initially enable Export only note pages option depending on the checked state of Export notes pages option + mxCbExportOnlyNotesPages->set_sensitive(mxCbExportNotesPages->get_active()); + mxCbExportHiddenSlides->show(); + mxCbExportHiddenSlides->set_active(pParent->mbExportHiddenSlides); + } + else + { + mxCbExportNotesPages->hide(); + mxCbExportNotesPages->set_active(false); + mxCbExportOnlyNotesPages->hide(); + mxCbExportOnlyNotesPages->set_active(false); + mxCbExportHiddenSlides->hide(); + mxCbExportHiddenSlides->set_active(false); + } + + if( mbIsSpreadsheet ) + { + mxRbSelection->set_label(mxSheetsFt->get_label()); + // tdf#105965 Make Selection/Selected sheets the default PDF export range setting for spreadsheets + mxRbSelection->set_active(true); + + mxCbSinglePageSheets->show(); + mxCbSinglePageSheets->set_active(pParent->mbSinglePageSheets); + } + else + { + mxCbSinglePageSheets->hide(); + mxCbSinglePageSheets->set_active(false); + } + + mxCbExportPlaceholders->set_visible(mbIsWriter); + if( mbIsWriter ) + { + // tdf#54908 Make selection active if there is a selection in Writer's version + mxRbSelection->set_active( bSelectionPresent ); + } + else + { + mxCbExportPlaceholders->set_active(false); + } + mxCbExportEmptyPages->set_active(!pParent->mbIsSkipEmptyPages); + mxCbExportPlaceholders->set_active(pParent->mbIsExportPlaceholders); + + mxCbAddStream->show(); + mxCbAddStream->set_active(pParent->mbAddStream); + + mxCbAddStream->connect_toggled(LINK(this, ImpPDFTabGeneralPage, ToggleAddStreamHdl)); + ToggleAddStreamHdl(*mxCbAddStream); // init addstream dependencies +} + +void ImpPDFTabGeneralPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + // updating the FilterData sequence and storing FilterData to configuration + pParent->mbUseLosslessCompression = mxRbLosslessCompression->get_active(); + pParent->mnQuality = static_cast<sal_Int32>(mxNfQuality->get_value(FieldUnit::PERCENT)); + pParent->mbReduceImageResolution = mxCbReduceImageResolution->get_active(); + pParent->mnMaxImageResolution = mxCoReduceImageResolution->get_active_text().toInt32(); + pParent->mbExportNotes = mxCbExportNotes->get_active(); + pParent->mbViewPDF = mxCbViewPDF->get_active(); + pParent->mbUseReferenceXObject = mxCbUseReferenceXObject->get_active(); + if ( mbIsPresentation ) + { + pParent->mbExportNotesPages = mxCbExportNotesPages->get_active(); + pParent->mbExportOnlyNotesPages = mxCbExportOnlyNotesPages->get_active(); + } + pParent->mbExportBookmarks = mxCbExportBookmarks->get_active(); + if ( mbIsPresentation ) + pParent->mbExportHiddenSlides = mxCbExportHiddenSlides->get_active(); + + if (mbIsSpreadsheet) + pParent->mbSinglePageSheets = mxCbSinglePageSheets->get_active(); + + pParent->mbIsSkipEmptyPages = !mxCbExportEmptyPages->get_active(); + pParent->mbIsExportPlaceholders = mxCbExportPlaceholders->get_active(); + pParent->mbAddStream = mxCbAddStream->get_visible() && mxCbAddStream->get_active(); + + pParent->mbIsRangeChecked = false; + if( mxRbRange->get_active() ) + { + pParent->mbIsRangeChecked = true; + pParent->msPageRange = mxEdPages->get_text(); //FIXME all right on other languages ? + } + else if( mxRbSelection->get_active() ) + { + pParent->mbSelectionIsChecked = mxRbSelection->get_active(); + } + + pParent->mnPDFTypeSelection = 0; + pParent->mbUseTaggedPDF = mxCbTaggedPDF->get_active(); + + const bool bIsPDFA = mxCbPDFA->get_active(); + const bool bIsPDFUA = mxCbPDFUA->get_active(); + + if (bIsPDFA) + { + pParent->mnPDFTypeSelection = 3; + OUString currentPDFAMode = mxRbPDFAVersion->get_active_id(); + if( currentPDFAMode == "1" ) + pParent->mnPDFTypeSelection = 1; + else if(currentPDFAMode == "2") + pParent->mnPDFTypeSelection = 2; + } + + pParent->mbPDFUACompliance = bIsPDFUA; + + if (!bIsPDFA && !bIsPDFUA) + mbUseTaggedPDFUserSelection = pParent->mbUseTaggedPDF; + + pParent->mbUseTaggedPDFUserSelection = mbUseTaggedPDFUserSelection; + pParent->mbExportFormFields = mxCbExportFormFields->get_active(); + + if( mxCbWatermark->get_active() ) + pParent->maWatermarkText = mxEdWatermark->get_text(); + + /* + * FIXME: the entries are only implicitly defined by the resource file. Should there + * ever be an additional form submit format this could get invalid. + */ + pParent->mnFormsType = mxLbFormsFormat->get_active(); + pParent->mbAllowDuplicateFieldNames = mxCbAllowDuplicateFieldNames->get_active(); +} + +std::unique_ptr<SfxTabPage> ImpPDFTabGeneralPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<ImpPDFTabGeneralPage>(pPage, pController, *rAttrSet); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleAllHdl, weld::Toggleable&, void) +{ + EnableExportNotesPages(); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, TogglePagesHdl, weld::Toggleable&, void) +{ + TogglePagesHdl(); + EnableExportNotesPages(); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleSelectionHdl, weld::Toggleable&, void) +{ + EnableExportNotesPages(); +} + +void ImpPDFTabGeneralPage::TogglePagesHdl() +{ + mxEdPages->set_sensitive( mxRbRange->get_active() ); + if (mxRbRange->get_active()) + mxEdPages->grab_focus(); +} + +void ImpPDFTabGeneralPage::EnableExportNotesPages() +{ + if ( mbIsPresentation ) + { + mxCbExportNotesPages->set_sensitive( !mxRbSelection->get_active() ); + mxCbExportOnlyNotesPages->set_sensitive( !mxRbSelection->get_active() && mxCbExportNotesPages->get_active() ); + } +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleExportFormFieldsHdl, weld::Toggleable&, void) +{ + mxFormsFrame->set_sensitive(mxCbExportFormFields->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleExportNotesPagesHdl, weld::Toggleable&, void) +{ + mxCbExportOnlyNotesPages->set_sensitive(mxCbExportNotesPages->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleCompressionHdl, weld::Toggleable&, void) +{ + mxQualityFrame->set_sensitive(mxRbJPEGCompression->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleReduceImageResolutionHdl, weld::Toggleable&, void) +{ + mxCoReduceImageResolution->set_sensitive(mxCbReduceImageResolution->get_active()); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleWatermarkHdl, weld::Toggleable&, void) +{ + mxEdWatermark->set_sensitive(mxCbWatermark->get_active()); + mxFtWatermark->set_sensitive(mxCbWatermark->get_active()); + if (mxCbWatermark->get_active()) + mxEdWatermark->grab_focus(); +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, ToggleAddStreamHdl, weld::Toggleable&, void) +{ + if (!mxCbAddStream->get_visible()) + return; + + if( mxCbAddStream->get_active() ) + { + mxRbAll->set_active(true); + mxRbRange->set_sensitive( false ); + mxRbSelection->set_sensitive( false ); + mxEdPages->set_sensitive( false ); + mxRbAll->set_sensitive( false ); + } + else + { + mxRbAll->set_sensitive(true); + mxRbRange->set_sensitive(true); + mxRbSelection->set_sensitive(true); + } +} + +IMPL_LINK_NOARG(ImpPDFTabGeneralPage, TogglePDFVersionOrUniversalAccessibilityHandle, weld::Toggleable&, void) +{ + const bool bIsPDFA = mxCbPDFA->get_active(); + const bool bIsPDFUA = mxCbPDFUA->get_active(); + + // set the security page status (and its controls as well) + ImpPDFTabSecurityPage* pSecPage = mpParent ? mpParent->getSecurityPage() : nullptr; + if (pSecPage) + pSecPage->ImplPDFASecurityControl(!bIsPDFA); + + mxCbTaggedPDF->set_sensitive(!bIsPDFA && !bIsPDFUA); + mxRbPDFAVersion->set_sensitive(bIsPDFA); + + if (bIsPDFA || bIsPDFUA) + { + // store the users selection of subordinate controls and set required PDF/A values + mbUseTaggedPDFUserSelection = mxCbTaggedPDF->get_active(); + mxCbTaggedPDF->set_active(true); + + // if a password was set, inform the user that this will not be used + if (pSecPage && pSecPage->hasPassword()) + { + std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(m_xContainer.get(), + VclMessageType::Warning, VclButtonsType::Ok, + PDFFilterResId(STR_WARN_PASSWORD_PDFA))); + xBox->run(); + } + } + else + { + // restore the users values of subordinate controls + mxCbTaggedPDF->set_active(mbUseTaggedPDFUserSelection); + } + + // PDF/A doesn't allow launch action, so enable/disable the selection on the Link page + ImpPDFTabLinksPage* pLinksPage = mpParent ? mpParent->getLinksPage() : nullptr; + if (pLinksPage) + pLinksPage->ImplPDFALinkControl(!bIsPDFA); +} + +/// The option features tab page +ImpPDFTabOpnFtrPage::ImpPDFTabOpnFtrPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfviewpage.ui", "PdfViewPage", &rCoreSet) + , mbUseCTLFont(false) + , mxRbOpnPageOnly(m_xBuilder->weld_radio_button("pageonly")) + , mxRbOpnOutline(m_xBuilder->weld_radio_button("outline")) + , mxRbOpnThumbs(m_xBuilder->weld_radio_button("thumbs")) + , mxNumInitialPage(m_xBuilder->weld_spin_button("page")) + , mxRbMagnDefault(m_xBuilder->weld_radio_button("fitdefault")) + , mxRbMagnFitWin(m_xBuilder->weld_radio_button("fitwin")) + , mxRbMagnFitWidth(m_xBuilder->weld_radio_button("fitwidth")) + , mxRbMagnFitVisible(m_xBuilder->weld_radio_button("fitvis")) + , mxRbMagnZoom(m_xBuilder->weld_radio_button("fitzoom")) + , mxNumZoom(m_xBuilder->weld_spin_button("zoom")) + , mxRbPgLyDefault(m_xBuilder->weld_radio_button("defaultlayout")) + , mxRbPgLySinglePage(m_xBuilder->weld_radio_button("singlelayout")) + , mxRbPgLyContinue(m_xBuilder->weld_radio_button("contlayout")) + , mxRbPgLyContinueFacing(m_xBuilder->weld_radio_button("contfacinglayout")) + , mxCbPgLyFirstOnLeft(m_xBuilder->weld_check_button("firstonleft")) +{ + mxRbMagnDefault->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnFitWin->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnFitWidth->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnFitVisible->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); + mxRbMagnZoom->connect_toggled( LINK( this, ImpPDFTabOpnFtrPage, ToggleRbMagnHdl ) ); +} + +ImpPDFTabOpnFtrPage::~ImpPDFTabOpnFtrPage() +{ +} + +std::unique_ptr<SfxTabPage> ImpPDFTabOpnFtrPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<ImpPDFTabOpnFtrPage>(pPage, pController, *rAttrSet); +} + +void ImpPDFTabOpnFtrPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mnInitialView = 0; + if( mxRbOpnOutline->get_active() ) + pParent->mnInitialView = 1; + else if( mxRbOpnThumbs->get_active() ) + pParent->mnInitialView = 2; + + pParent->mnMagnification = 0; + if( mxRbMagnFitWin->get_active() ) + pParent->mnMagnification = 1; + else if( mxRbMagnFitWidth->get_active() ) + pParent->mnMagnification = 2; + else if( mxRbMagnFitVisible->get_active() ) + pParent->mnMagnification = 3; + else if( mxRbMagnZoom->get_active() ) + { + pParent->mnMagnification = 4; + pParent->mnZoom = mxNumZoom->get_value(); + } + + pParent->mnInitialPage = mxNumInitialPage->get_value(); + + pParent->mnPageLayout = 0; + if( mxRbPgLySinglePage->get_active() ) + pParent->mnPageLayout = 1; + else if( mxRbPgLyContinue->get_active() ) + pParent->mnPageLayout = 2; + else if( mxRbPgLyContinueFacing->get_active() ) + pParent->mnPageLayout = 3; + + pParent->mbFirstPageLeft = mbUseCTLFont && mxCbPgLyFirstOnLeft->get_active(); +} + +void ImpPDFTabOpnFtrPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + mbUseCTLFont = pParent->mbUseCTLFont; + switch( pParent->mnPageLayout ) + { + default: + case 0: + mxRbPgLyDefault->set_active(true); + break; + case 1: + mxRbPgLySinglePage->set_active(true); + break; + case 2: + mxRbPgLyContinue->set_active(true); + break; + case 3: + mxRbPgLyContinueFacing->set_active(true); + break; + } + + switch( pParent->mnInitialView ) + { + default: + case 0: + mxRbOpnPageOnly->set_active(true); + break; + case 1: + mxRbOpnOutline->set_active(true); + break; + case 2: + mxRbOpnThumbs->set_active(true); + break; + } + + switch( pParent->mnMagnification ) + { + default: + case 0: + mxRbMagnDefault->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 1: + mxRbMagnFitWin->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 2: + mxRbMagnFitWidth->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 3: + mxRbMagnFitVisible->set_active(true); + mxNumZoom->set_sensitive(false); + break; + case 4: + mxRbMagnZoom->set_active(true); + mxNumZoom->set_sensitive(true); + break; + } + + mxNumZoom->set_value(pParent->mnZoom); + mxNumInitialPage->set_value(pParent->mnInitialPage); + + if (!mbUseCTLFont) + mxCbPgLyFirstOnLeft->hide(); + else + { + mxRbPgLyContinueFacing->connect_toggled(LINK(this, ImpPDFTabOpnFtrPage, ToggleRbPgLyContinueFacingHdl)); + mxCbPgLyFirstOnLeft->set_active(pParent->mbFirstPageLeft); + ToggleRbPgLyContinueFacingHdl(); + } +} + +IMPL_LINK_NOARG(ImpPDFTabOpnFtrPage, ToggleRbPgLyContinueFacingHdl, weld::Toggleable&, void) +{ + ToggleRbPgLyContinueFacingHdl(); +} + +void ImpPDFTabOpnFtrPage::ToggleRbPgLyContinueFacingHdl() +{ + mxCbPgLyFirstOnLeft->set_sensitive(mxRbPgLyContinueFacing->get_active()); +} + +IMPL_LINK_NOARG( ImpPDFTabOpnFtrPage, ToggleRbMagnHdl, weld::Toggleable&, void ) +{ + mxNumZoom->set_sensitive(mxRbMagnZoom->get_active()); +} + +/// The Viewer preferences tab page +ImpPDFTabViewerPage::ImpPDFTabViewerPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet ) + : SfxTabPage(pPage, pController, "filter/ui/pdfuserinterfacepage.ui", "PdfUserInterfacePage", &rCoreSet) + , mbIsPresentation(false) + , m_xCbResWinInit(m_xBuilder->weld_check_button("resize")) + , m_xCbCenterWindow(m_xBuilder->weld_check_button("center")) + , m_xCbOpenFullScreen(m_xBuilder->weld_check_button("open")) + , m_xCbDispDocTitle(m_xBuilder->weld_check_button("display")) + , m_xCbHideViewerMenubar(m_xBuilder->weld_check_button("menubar")) + , m_xCbHideViewerToolbar(m_xBuilder->weld_check_button("toolbar")) + , m_xCbHideViewerWindowControls(m_xBuilder->weld_check_button("window")) + , m_xCbTransitionEffects(m_xBuilder->weld_check_button("effects")) + , m_xRbAllBookmarkLevels(m_xBuilder->weld_radio_button("allbookmarks")) + , m_xRbVisibleBookmarkLevels(m_xBuilder->weld_radio_button("visiblebookmark")) + , m_xNumBookmarkLevels(m_xBuilder->weld_spin_button("visiblelevel")) +{ + m_xRbAllBookmarkLevels->connect_toggled(LINK(this, ImpPDFTabViewerPage, ToggleRbBookmarksHdl)); + m_xRbVisibleBookmarkLevels->connect_toggled(LINK(this, ImpPDFTabViewerPage, ToggleRbBookmarksHdl)); +} + +ImpPDFTabViewerPage::~ImpPDFTabViewerPage() +{ +} + +IMPL_LINK_NOARG( ImpPDFTabViewerPage, ToggleRbBookmarksHdl, weld::Toggleable&, void ) +{ + m_xNumBookmarkLevels->set_sensitive(m_xRbVisibleBookmarkLevels->get_active()); +} + +std::unique_ptr<SfxTabPage> ImpPDFTabViewerPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<ImpPDFTabViewerPage>(pPage, pController, *rAttrSet); +} + +void ImpPDFTabViewerPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mbHideViewerMenubar = m_xCbHideViewerMenubar->get_active(); + pParent->mbHideViewerToolbar = m_xCbHideViewerToolbar->get_active(); + pParent->mbHideViewerWindowControls = m_xCbHideViewerWindowControls->get_active(); + pParent->mbResizeWinToInit = m_xCbResWinInit->get_active(); + pParent->mbOpenInFullScreenMode = m_xCbOpenFullScreen->get_active(); + pParent->mbCenterWindow = m_xCbCenterWindow->get_active(); + pParent->mbDisplayPDFDocumentTitle = m_xCbDispDocTitle->get_active(); + pParent->mbUseTransitionEffects = m_xCbTransitionEffects->get_active(); + pParent->mnOpenBookmarkLevels = m_xRbAllBookmarkLevels->get_active() ? + -1 : static_cast<sal_Int32>(m_xNumBookmarkLevels->get_value()); +} + +void ImpPDFTabViewerPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + m_xCbHideViewerMenubar->set_active( pParent->mbHideViewerMenubar ); + m_xCbHideViewerToolbar->set_active( pParent->mbHideViewerToolbar ); + m_xCbHideViewerWindowControls->set_active( pParent->mbHideViewerWindowControls ); + + m_xCbResWinInit->set_active( pParent->mbResizeWinToInit ); + m_xCbOpenFullScreen->set_active( pParent->mbOpenInFullScreenMode ); + m_xCbCenterWindow->set_active( pParent->mbCenterWindow ); + m_xCbDispDocTitle->set_active( pParent->mbDisplayPDFDocumentTitle ); + mbIsPresentation = pParent->mbIsPresentation; + m_xCbTransitionEffects->set_active( pParent->mbUseTransitionEffects ); + m_xCbTransitionEffects->set_sensitive( mbIsPresentation ); + if( pParent->mnOpenBookmarkLevels < 0 ) + { + m_xRbAllBookmarkLevels->set_active(true); + m_xNumBookmarkLevels->set_sensitive( false ); + } + else + { + m_xRbVisibleBookmarkLevels->set_active(true); + m_xNumBookmarkLevels->set_sensitive(true); + m_xNumBookmarkLevels->set_value(pParent->mnOpenBookmarkLevels); + } +} + +/// The Security preferences tab page +ImpPDFTabSecurityPage::ImpPDFTabSecurityPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& i_rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfsecuritypage.ui", "PdfSecurityPage", &i_rCoreSet) + , msUserPwdTitle( PDFFilterResId( STR_PDF_EXPORT_UDPWD ) ) + , mbHaveOwnerPassword( false ) + , mbHaveUserPassword( false ) + , msOwnerPwdTitle( PDFFilterResId( STR_PDF_EXPORT_ODPWD ) ) + , mxPbSetPwd(m_xBuilder->weld_button("setpassword")) + , mxUserPwdSet(m_xBuilder->weld_widget("userpwdset")) + , mxUserPwdUnset(m_xBuilder->weld_widget("userpwdunset")) + , mxUserPwdPdfa(m_xBuilder->weld_widget("userpwdpdfa")) + , mxOwnerPwdSet(m_xBuilder->weld_widget("ownerpwdset")) + , mxOwnerPwdUnset(m_xBuilder->weld_widget("ownerpwdunset")) + , mxOwnerPwdPdfa(m_xBuilder->weld_widget("ownerpwdpdfa")) + , mxPrintPermissions(m_xBuilder->weld_widget("printing")) + , mxRbPrintNone(m_xBuilder->weld_radio_button("printnone")) + , mxRbPrintLowRes(m_xBuilder->weld_radio_button("printlow")) + , mxRbPrintHighRes(m_xBuilder->weld_radio_button("printhigh")) + , mxChangesAllowed(m_xBuilder->weld_widget("changes")) + , mxRbChangesNone(m_xBuilder->weld_radio_button("changenone")) + , mxRbChangesInsDel(m_xBuilder->weld_radio_button("changeinsdel")) + , mxRbChangesFillForm(m_xBuilder->weld_radio_button("changeform")) + , mxRbChangesComment(m_xBuilder->weld_radio_button("changecomment")) + , mxRbChangesAnyNoCopy(m_xBuilder->weld_radio_button("changeany")) + , mxContent(m_xBuilder->weld_widget("content")) + , mxCbEnableCopy(m_xBuilder->weld_check_button("enablecopy")) + , mxCbEnableAccessibility(m_xBuilder->weld_check_button("enablea11y")) + , mxPasswordTitle(m_xBuilder->weld_label("setpasswordstitle")) +{ + msStrSetPwd = mxPasswordTitle->get_label(); + mxPbSetPwd->connect_clicked(LINK(this, ImpPDFTabSecurityPage, ClickmaPbSetPwdHdl)); +} + +ImpPDFTabSecurityPage::~ImpPDFTabSecurityPage() +{ +} + +std::unique_ptr<SfxTabPage> ImpPDFTabSecurityPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<ImpPDFTabSecurityPage>(pPage, pController, *rAttrSet); +} + +void ImpPDFTabSecurityPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + // please note that in PDF/A-1a mode even if this are copied back, + // the security settings are forced disabled in PDFExport::Export + pParent->mbEncrypt = mbHaveUserPassword; + pParent->mxPreparedPasswords = mxPreparedPasswords; + + pParent->mbRestrictPermissions = mbHaveOwnerPassword; + pParent->maPreparedOwnerPassword = maPreparedOwnerPassword; + + // verify print status + pParent->mnPrint = 0; + if (mxRbPrintLowRes->get_active()) + pParent->mnPrint = 1; + else if (mxRbPrintHighRes->get_active()) + pParent->mnPrint = 2; + + // verify changes permitted + pParent->mnChangesAllowed = 0; + + if( mxRbChangesInsDel->get_active() ) + pParent->mnChangesAllowed = 1; + else if( mxRbChangesFillForm->get_active() ) + pParent->mnChangesAllowed = 2; + else if( mxRbChangesComment->get_active() ) + pParent->mnChangesAllowed = 3; + else if( mxRbChangesAnyNoCopy->get_active() ) + pParent->mnChangesAllowed = 4; + + pParent->mbCanCopyOrExtract = mxCbEnableCopy->get_active(); + pParent->mbCanExtractForAccessibility = mxCbEnableAccessibility->get_active(); +} + +void ImpPDFTabSecurityPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + switch( pParent->mnPrint ) + { + default: + case 0: + mxRbPrintNone->set_active(true); + break; + case 1: + mxRbPrintLowRes->set_active(true); + break; + case 2: + mxRbPrintHighRes->set_active(true); + break; + } + + switch( pParent->mnChangesAllowed ) + { + default: + case 0: + mxRbChangesNone->set_active(true); + break; + case 1: + mxRbChangesInsDel->set_active(true); + break; + case 2: + mxRbChangesFillForm->set_active(true); + break; + case 3: + mxRbChangesComment->set_active(true); + break; + case 4: + mxRbChangesAnyNoCopy->set_active(true); + break; + } + + mxCbEnableCopy->set_active(pParent->mbCanCopyOrExtract); + mxCbEnableAccessibility->set_active(pParent->mbCanExtractForAccessibility); + + // set the status of this windows, according to the PDFA selection + enablePermissionControls(); + + ImpPDFTabGeneralPage* pGeneralPage = pParent->getGeneralPage(); + + if (pGeneralPage) + ImplPDFASecurityControl(!pGeneralPage->IsPdfaSelected()); +} + +IMPL_LINK_NOARG(ImpPDFTabSecurityPage, ClickmaPbSetPwdHdl, weld::Button&, void) +{ + SfxPasswordDialog aPwdDialog(m_xContainer.get(), &msUserPwdTitle); + aPwdDialog.SetMinLen(0); + aPwdDialog.ShowMinLengthText(false); + aPwdDialog.ShowExtras( SfxShowExtras::CONFIRM | SfxShowExtras::PASSWORD2 | SfxShowExtras::CONFIRM2 ); + aPwdDialog.set_title(msStrSetPwd); + aPwdDialog.SetGroup2Text(msOwnerPwdTitle); + aPwdDialog.AllowAsciiOnly(); + if (aPwdDialog.run() == RET_OK) // OK issued get password and set it + { + OUString aUserPW(aPwdDialog.GetPassword()); + OUString aOwnerPW(aPwdDialog.GetPassword2()); + + mbHaveUserPassword = !aUserPW.isEmpty(); + mbHaveOwnerPassword = !aOwnerPW.isEmpty(); + + mxPreparedPasswords = vcl::PDFWriter::InitEncryption( aOwnerPW, aUserPW ); + if (!mxPreparedPasswords.is()) { + OUString msg; + ErrorHandler::GetErrorString(ERRCODE_IO_NOTSUPPORTED, msg); //TODO: handle failure + std::unique_ptr<weld::MessageDialog>( + Application::CreateMessageDialog( + GetFrameWeld(), VclMessageType::Error, VclButtonsType::Ok, msg)) + ->run(); + return; + } + + if( mbHaveOwnerPassword ) + { + maPreparedOwnerPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aOwnerPW ); + } + else + maPreparedOwnerPassword = Sequence< NamedValue >(); + } + enablePermissionControls(); +} + +void ImpPDFTabSecurityPage::enablePermissionControls() +{ + bool bIsPDFASel = false; + ImpPDFTabDialog* pParent = static_cast<ImpPDFTabDialog*>(GetDialogController()); + ImpPDFTabGeneralPage* pGeneralPage = pParent ? pParent->getGeneralPage() : nullptr; + if (pGeneralPage) + { + bIsPDFASel = pGeneralPage->IsPdfaSelected(); + } + if (bIsPDFASel) + { + mxUserPwdPdfa->show(); + mxUserPwdSet->hide(); + mxUserPwdUnset->hide(); + } + else + { + if (mbHaveUserPassword && m_xContainer->get_sensitive()) + { + mxUserPwdSet->show(); + mxUserPwdUnset->hide(); + mxUserPwdPdfa->hide(); + } + else + { + mxUserPwdUnset->show(); + mxUserPwdSet->hide(); + mxUserPwdPdfa->hide(); + } + } + + bool bLocalEnable = mbHaveOwnerPassword && m_xContainer->get_sensitive(); + if (bIsPDFASel) + { + mxOwnerPwdPdfa->show(); + mxOwnerPwdSet->hide(); + mxOwnerPwdUnset->hide(); + } + else + { + if (bLocalEnable) + { + mxOwnerPwdSet->show(); + mxOwnerPwdUnset->hide(); + mxOwnerPwdPdfa->hide(); + } + else + { + mxOwnerPwdUnset->show(); + mxOwnerPwdSet->hide(); + mxOwnerPwdPdfa->hide(); + } + } + + mxPrintPermissions->set_sensitive(bLocalEnable); + mxChangesAllowed->set_sensitive(bLocalEnable); + mxContent->set_sensitive(bLocalEnable); +} + +// This tab page is under control of the PDF/A-1a checkbox: +// TODO: implement a method to do it. +void ImpPDFTabSecurityPage::ImplPDFASecurityControl( bool bEnableSecurity ) +{ + m_xContainer->set_sensitive(bEnableSecurity); + // after enable, check the status of control as if the dialog was initialized + enablePermissionControls(); +} + +/// The link preferences tab page (relative and other stuff) +ImpPDFTabLinksPage::ImpPDFTabLinksPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdflinkspage.ui", "PdfLinksPage", &rCoreSet) + , mbOpnLnksDefaultUserState(false) + , mbOpnLnksLaunchUserState(false) + , mbOpnLnksBrowserUserState(false) + , m_xCbExprtBmkrToNmDst(m_xBuilder->weld_check_button("export")) + , m_xCbOOoToPDFTargets(m_xBuilder->weld_check_button("convert")) + , m_xCbExportRelativeFsysLinks(m_xBuilder->weld_check_button("exporturl")) + , m_xRbOpnLnksDefault(m_xBuilder->weld_radio_button("default")) + , m_xRbOpnLnksLaunch(m_xBuilder->weld_radio_button("openpdf")) + , m_xRbOpnLnksBrowser(m_xBuilder->weld_radio_button("openinternet")) +{ +} + +ImpPDFTabLinksPage::~ImpPDFTabLinksPage() +{ +} + +std::unique_ptr<SfxTabPage> ImpPDFTabLinksPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet) +{ + return std::make_unique<ImpPDFTabLinksPage>(pPage, pController, *rAttrSet); +} + +void ImpPDFTabLinksPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mbExportRelativeFsysLinks = m_xCbExportRelativeFsysLinks->get_active(); + + bool bIsPDFASel = false; + ImpPDFTabGeneralPage* pGeneralPage = pParent->getGeneralPage(); + if (pGeneralPage) + bIsPDFASel = pGeneralPage->IsPdfaSelected(); + // if PDF/A-1 was not selected while exiting dialog... + if( !bIsPDFASel ) + { + // ...get the control states + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); + } + // the control states, or the saved is used + // to form the stored selection + pParent->mnViewPDFMode = 0; + if( mbOpnLnksBrowserUserState ) + pParent->mnViewPDFMode = 2; + else if( mbOpnLnksLaunchUserState ) + pParent->mnViewPDFMode = 1; + + pParent->mbConvertOOoTargets = m_xCbOOoToPDFTargets->get_active(); + pParent->mbExportBmkToPDFDestination = m_xCbExprtBmkrToNmDst->get_active(); +} + +void ImpPDFTabLinksPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + m_xCbOOoToPDFTargets->set_active(pParent->mbConvertOOoTargets); + m_xCbExprtBmkrToNmDst->set_active(pParent->mbExportBmkToPDFDestination); + + m_xRbOpnLnksDefault->connect_toggled(LINK(this, ImpPDFTabLinksPage, ClickRbOpnLnksDefaultHdl)); + m_xRbOpnLnksBrowser->connect_toggled(LINK(this, ImpPDFTabLinksPage, ClickRbOpnLnksBrowserHdl)); + + m_xCbExportRelativeFsysLinks->set_active(pParent->mbExportRelativeFsysLinks); + switch( pParent->mnViewPDFMode ) + { + default: + case 0: + m_xRbOpnLnksDefault->set_active(true); + mbOpnLnksDefaultUserState = true; + break; + case 1: + m_xRbOpnLnksLaunch->set_active(true); + mbOpnLnksLaunchUserState = true; + break; + case 2: + m_xRbOpnLnksBrowser->set_active(true); + mbOpnLnksBrowserUserState = true; + break; + } + + // now check the status of PDF/A selection + // and set the link action accordingly + // PDF/A-2 doesn't allow launch action on links + + ImpPDFTabGeneralPage* pGeneralPage = pParent->getGeneralPage(); + if (pGeneralPage) + ImplPDFALinkControl(!pGeneralPage->mxCbPDFA->get_active()); +} + + +/** Called from general tab, with PDFA/1 selection status. + Retrieves/store the status of Launch action selection. + */ +void ImpPDFTabLinksPage::ImplPDFALinkControl( bool bEnableLaunch ) +{ + // set the value and position of link type selection + if( bEnableLaunch ) + { + m_xRbOpnLnksLaunch->set_sensitive(true); + // restore user state with no PDF/A-1 selected + m_xRbOpnLnksDefault->set_active(mbOpnLnksDefaultUserState); + m_xRbOpnLnksLaunch->set_active(mbOpnLnksLaunchUserState); + m_xRbOpnLnksBrowser->set_active(mbOpnLnksBrowserUserState); + } + else + { + // save user state with no PDF/A-1 selected + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); + m_xRbOpnLnksLaunch->set_sensitive(false); + if (mbOpnLnksLaunchUserState) + m_xRbOpnLnksBrowser->set_active(true); + } +} + +/// Reset the memory of Launch action present when PDF/A-1 was requested +IMPL_LINK_NOARG(ImpPDFTabLinksPage, ClickRbOpnLnksDefaultHdl, weld::Toggleable&, void) +{ + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); +} + +/// Reset the memory of a launch action present when PDF/A-1 was requested +IMPL_LINK_NOARG(ImpPDFTabLinksPage, ClickRbOpnLnksBrowserHdl, weld::Toggleable&, void) +{ + mbOpnLnksDefaultUserState = m_xRbOpnLnksDefault->get_active(); + mbOpnLnksLaunchUserState = m_xRbOpnLnksLaunch->get_active(); + mbOpnLnksBrowserUserState = m_xRbOpnLnksBrowser->get_active(); +} + +ImplErrorDialog::ImplErrorDialog(weld::Window* pParent, const std::set<vcl::PDFWriter::ErrorCode>& rErrors) + : MessageDialogController(pParent, "filter/ui/warnpdfdialog.ui", "WarnPDFDialog", "grid") + , m_xErrors(m_xBuilder->weld_tree_view("errors")) + , m_xExplanation(m_xBuilder->weld_label("message")) +{ + int nWidth = m_xErrors->get_approximate_digit_width() * 26; + int nHeight = m_xErrors->get_height_rows(9); + m_xErrors->set_size_request(nWidth, nHeight); + m_xExplanation->set_size_request(nWidth, nHeight); + + for (auto const& error : rErrors) + { + switch(error) + { + case vcl::PDFWriter::Warning_Transparency_Omitted_PDFA: + m_xErrors->append(PDFFilterResId(STR_WARN_TRANSP_PDFA), PDFFilterResId(STR_WARN_TRANSP_PDFA_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Warning_Transparency_Omitted_PDF13: + m_xErrors->append(PDFFilterResId(STR_WARN_TRANSP_VERSION), PDFFilterResId(STR_WARN_TRANSP_VERSION_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Warning_FormAction_Omitted_PDFA: + m_xErrors->append(PDFFilterResId(STR_WARN_FORMACTION_PDFA), PDFFilterResId(STR_WARN_FORMACTION_PDFA_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Warning_Transparency_Converted: + m_xErrors->append(PDFFilterResId(STR_WARN_TRANSP_CONVERTED), PDFFilterResId(STR_WARN_TRANSP_CONVERTED_SHORT), "dialog-warning"); + break; + case vcl::PDFWriter::Error_Signature_Failed: + m_xErrors->append(PDFFilterResId(STR_ERR_PDF_EXPORT_ABORTED), PDFFilterResId(STR_ERR_SIGNATURE_FAILED), "dialog-error"); + break; + default: + break; + } + } + + if (m_xErrors->n_children() > 0) + { + m_xErrors->select(0); + m_xExplanation->set_label(m_xErrors->get_id(0)); + } + + m_xErrors->connect_changed(LINK(this, ImplErrorDialog, SelectHdl)); +} + +IMPL_LINK_NOARG(ImplErrorDialog, SelectHdl, weld::TreeView&, void) +{ + OUString aExplanation = m_xErrors->get_selected_id(); + m_xExplanation->set_label(aExplanation); +} + +/// The digital signatures tab page +ImpPDFTabSigningPage::ImpPDFTabSigningPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rCoreSet) + : SfxTabPage(pPage, pController, "filter/ui/pdfsignpage.ui", "PdfSignPage", &rCoreSet) + , mxEdSignCert(m_xBuilder->weld_entry("cert")) + , mxPbSignCertSelect(m_xBuilder->weld_button("select")) + , mxPbSignCertClear(m_xBuilder->weld_button("clear")) + , mxEdSignPassword(m_xBuilder->weld_entry("password")) + , mxEdSignLocation(m_xBuilder->weld_entry("location")) + , mxEdSignContactInfo(m_xBuilder->weld_entry("contact")) + , mxEdSignReason(m_xBuilder->weld_entry("reason")) + , mxLBSignTSA(m_xBuilder->weld_combo_box("tsa")) +{ + mxPbSignCertSelect->set_sensitive(true); + mxPbSignCertSelect->connect_clicked(LINK(this, ImpPDFTabSigningPage, ClickmaPbSignCertSelect)); + mxPbSignCertClear->connect_clicked(LINK(this, ImpPDFTabSigningPage, ClickmaPbSignCertClear)); +} + +ImpPDFTabSigningPage::~ImpPDFTabSigningPage() +{ +} + +IMPL_LINK_NOARG(ImpPDFTabSigningPage, ClickmaPbSignCertSelect, weld::Button&, void) +{ + Reference< security::XDocumentDigitalSignatures > xSigner( + security::DocumentDigitalSignatures::createDefault( + comphelper::getProcessComponentContext())); + xSigner->setParentWindow(GetFrameWeld()->GetXWindow()); + + // The use may provide a description while choosing a certificate. + OUString aDescription; + maSignCertificate = xSigner->selectSigningCertificateWithType( + security::CertificateKind::CertificateKind_X509, aDescription); + + if (!maSignCertificate.is()) + return; + + mxEdSignCert->set_text(maSignCertificate->getSubjectName()); + mxPbSignCertClear->set_sensitive(true); + mxEdSignLocation->set_sensitive(true); + mxEdSignPassword->set_sensitive(true); + mxEdSignContactInfo->set_sensitive(true); + mxEdSignReason->set_sensitive(true); + mxEdSignReason->set_text(aDescription); + + try + { + std::optional<css::uno::Sequence<OUString>> aTSAURLs(officecfg::Office::Common::Security::Scripting::TSAURLs::get()); + if (aTSAURLs) + { + const css::uno::Sequence<OUString>& rTSAURLs = *aTSAURLs; + for (auto const& elem : rTSAURLs) + { + mxLBSignTSA->append_text(elem); + } + } + } + catch (const uno::Exception &) + { + TOOLS_INFO_EXCEPTION("filter.pdf", "TSAURLsDialog::TSAURLsDialog()"); + } + + // If more than only the "None" entry is there, enable the ListBox + if (mxLBSignTSA->get_count() > 1) + mxLBSignTSA->set_sensitive(true); +} + +IMPL_LINK_NOARG(ImpPDFTabSigningPage, ClickmaPbSignCertClear, weld::Button&, void) +{ + mxEdSignCert->set_text(""); + maSignCertificate.clear(); + mxPbSignCertClear->set_sensitive(false); + mxEdSignLocation->set_sensitive(false); + mxEdSignPassword->set_sensitive(false); + mxEdSignContactInfo->set_sensitive(false); + mxEdSignReason->set_sensitive(false); + mxLBSignTSA->set_sensitive(false); +} + +std::unique_ptr<SfxTabPage> ImpPDFTabSigningPage::Create( weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet* rAttrSet) +{ + return std::make_unique<ImpPDFTabSigningPage>(pPage, pController, *rAttrSet); +} + +void ImpPDFTabSigningPage::GetFilterConfigItem( ImpPDFTabDialog* pParent ) +{ + pParent->mbSignPDF = maSignCertificate.is(); + pParent->maSignCertificate = maSignCertificate; + pParent->msSignLocation = mxEdSignLocation->get_text(); + pParent->msSignPassword = mxEdSignPassword->get_text(); + pParent->msSignContact = mxEdSignContactInfo->get_text(); + pParent->msSignReason = mxEdSignReason->get_text(); + // Entry 0 is 'None' + if (mxLBSignTSA->get_active() >= 1) + pParent->msSignTSA = mxLBSignTSA->get_active_text(); +} + +void ImpPDFTabSigningPage::SetFilterConfigItem( const ImpPDFTabDialog* pParent ) +{ + mxEdSignLocation->set_sensitive(false); + mxEdSignPassword->set_sensitive(false); + mxEdSignContactInfo->set_sensitive(false); + mxEdSignReason->set_sensitive(false); + mxLBSignTSA->set_sensitive(false); + mxPbSignCertClear->set_sensitive(false); + + if (pParent->mbSignPDF) + { + mxEdSignPassword->set_text(pParent->msSignPassword); + mxEdSignLocation->set_text(pParent->msSignLocation); + mxEdSignContactInfo->set_text(pParent->msSignContact); + mxEdSignReason->set_text(pParent->msSignReason); + maSignCertificate = pParent->maSignCertificate; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/impdialog.hxx b/filter/source/pdf/impdialog.hxx new file mode 100644 index 000000000..219d47e6d --- /dev/null +++ b/filter/source/pdf/impdialog.hxx @@ -0,0 +1,419 @@ +/* -*- 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 . + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <svx/AccessibilityCheckDialog.hxx> + +#include <vcl/pdfwriter.hxx> +#include <vcl/FilterConfigItem.hxx> +#include <vcl/weld.hxx> + +#include <com/sun/star/beans/NamedValue.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +class ImpPDFTabGeneralPage; +class ImpPDFTabViewerPage; +class ImpPDFTabOpnFtrPage; +class ImpPDFTabLinksPage; + +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::lang; + +class ImplErrorDialog : public weld::MessageDialogController +{ +private: + std::unique_ptr<weld::TreeView> m_xErrors; + std::unique_ptr<weld::Label> m_xExplanation; + + DECL_LINK(SelectHdl, weld::TreeView&, void); + +public: + explicit ImplErrorDialog(weld::Window* pParent, const std::set<vcl::PDFWriter::ErrorCode>& rErrorCodes); +}; + + +class ImpPDFTabSecurityPage; +class ImpPDFTabLinksPage; + + +/// Class tabbed dialog +class ImpPDFTabDialog final : public SfxTabDialogController +{ + css::uno::Reference<css::lang::XComponent> mrDoc; + weld::Window* mpParent; + + FilterConfigItem maConfigItem; + FilterConfigItem maConfigI18N; + + Any maSelection; + + DECL_LINK(CancelHdl, weld::Button&, void); + DECL_LINK(OkHdl, weld::Button&, void); + + // the following data are the configuration used throughout the dialog and pages + bool mbIsPresentation; + bool mbIsSpreadsheet; + bool mbIsWriter; + bool mbSelectionPresent; + bool mbUseCTLFont; + bool mbUseLosslessCompression; + sal_Int32 mnQuality; + bool mbReduceImageResolution; + sal_Int32 mnMaxImageResolution; + bool mbUseTaggedPDF; + bool mbUseTaggedPDFUserSelection; + sal_Int32 mnPDFTypeSelection; + bool mbPDFUACompliance; + bool mbExportNotes; + bool mbViewPDF; + bool mbUseReferenceXObject; + bool mbExportNotesPages; + bool mbExportOnlyNotesPages; + bool mbUseTransitionEffects; + bool mbIsSkipEmptyPages; + bool mbIsExportPlaceholders; + bool mbAddStream; + sal_Int32 mnFormsType; + bool mbExportFormFields; + bool mbAllowDuplicateFieldNames; + bool mbExportBookmarks; + bool mbExportHiddenSlides; + bool mbSinglePageSheets; + sal_Int32 mnOpenBookmarkLevels; + + bool mbHideViewerToolbar; + bool mbHideViewerMenubar; + bool mbHideViewerWindowControls; + bool mbResizeWinToInit; + bool mbCenterWindow; + bool mbOpenInFullScreenMode; + bool mbDisplayPDFDocumentTitle; + sal_Int32 mnMagnification; + sal_Int32 mnInitialView; + sal_Int32 mnZoom; + sal_Int32 mnInitialPage; + + sal_Int32 mnPageLayout; + bool mbFirstPageLeft; + + bool mbEncrypt; + + bool mbRestrictPermissions; + css::uno::Sequence< css::beans::NamedValue > maPreparedOwnerPassword; + sal_Int32 mnPrint; + sal_Int32 mnChangesAllowed; + bool mbCanCopyOrExtract; + bool mbCanExtractForAccessibility; + css::uno::Reference< css::beans::XMaterialHolder > mxPreparedPasswords; + + std::shared_ptr< svx::AccessibilityCheckDialog > mpAccessibilityCheckDialog; + + bool mbIsRangeChecked; + OUString msPageRange; + bool mbSelectionIsChecked; + + bool mbExportRelativeFsysLinks; + sal_Int32 mnViewPDFMode; + bool mbConvertOOoTargets; + bool mbExportBmkToPDFDestination; + + bool mbSignPDF; + OUString msSignPassword; + OUString msSignLocation; + OUString msSignContact; + OUString msSignReason; + css::uno::Reference< css::security::XCertificate > maSignCertificate; + OUString msSignTSA; + + OUString maWatermarkText; + +public: + + friend class ImpPDFTabGeneralPage; + friend class ImpPDFTabViewerPage; + friend class ImpPDFTabOpnFtrPage; + friend class ImpPDFTabSecurityPage; + friend class ImpPDFTabLinksPage; + friend class ImpPDFTabSigningPage; + + ImpPDFTabDialog(weld::Window* pParent, const Sequence< PropertyValue >& rFilterData, + const css::uno::Reference< XComponent >& rDoc); + virtual ~ImpPDFTabDialog() override; + + Sequence< PropertyValue > GetFilterData(); + + ImpPDFTabSecurityPage* getSecurityPage() const; + ImpPDFTabLinksPage* getLinksPage() const; + ImpPDFTabGeneralPage* getGeneralPage() const; + +private: + virtual void PageCreated(const OString& rId, SfxTabPage& rPage) override; +}; + + +/// Class tab page general +class ImpPDFTabGeneralPage : public SfxTabPage +{ + friend class ImpPDFTabLinksPage; + + bool mbUseTaggedPDFUserSelection; + bool mbIsPresentation; + bool mbIsSpreadsheet; + bool mbIsWriter; + ImpPDFTabDialog* mpParent; + + std::unique_ptr<weld::RadioButton> mxRbAll; + std::unique_ptr<weld::RadioButton> mxRbRange; + std::unique_ptr<weld::RadioButton> mxRbSelection; + std::unique_ptr<weld::Entry> mxEdPages; + std::unique_ptr<weld::Label> mxSelectedSheets; + std::unique_ptr<weld::RadioButton> mxRbLosslessCompression; + std::unique_ptr<weld::RadioButton> mxRbJPEGCompression; + std::unique_ptr<weld::Widget> mxQualityFrame; + std::unique_ptr<weld::MetricSpinButton> mxNfQuality; + std::unique_ptr<weld::CheckButton> mxCbReduceImageResolution; + std::unique_ptr<weld::ComboBox> mxCoReduceImageResolution; + std::unique_ptr<weld::CheckButton> mxCbPDFA; + std::unique_ptr<weld::CheckButton> mxCbPDFUA; + std::unique_ptr<weld::ComboBox> mxRbPDFAVersion; + std::unique_ptr<weld::CheckButton> mxCbTaggedPDF; + std::unique_ptr<weld::CheckButton> mxCbExportFormFields; + std::unique_ptr<weld::Widget> mxFormsFrame; + std::unique_ptr<weld::ComboBox> mxLbFormsFormat; + std::unique_ptr<weld::CheckButton> mxCbAllowDuplicateFieldNames; + std::unique_ptr<weld::CheckButton> mxCbExportBookmarks; + std::unique_ptr<weld::CheckButton> mxCbExportHiddenSlides; + std::unique_ptr<weld::CheckButton> mxCbSinglePageSheets; + std::unique_ptr<weld::CheckButton> mxCbExportNotes; + std::unique_ptr<weld::CheckButton> mxCbViewPDF; + std::unique_ptr<weld::CheckButton> mxCbUseReferenceXObject; + std::unique_ptr<weld::CheckButton> mxCbExportNotesPages; + std::unique_ptr<weld::CheckButton> mxCbExportOnlyNotesPages; + std::unique_ptr<weld::CheckButton> mxCbExportEmptyPages; + std::unique_ptr<weld::CheckButton> mxCbExportPlaceholders; + std::unique_ptr<weld::CheckButton> mxCbAddStream; + std::unique_ptr<weld::CheckButton> mxCbWatermark; + std::unique_ptr<weld::Label> mxFtWatermark; + std::unique_ptr<weld::Entry> mxEdWatermark; + std::unique_ptr<weld::Label> mxSlidesFt; + std::unique_ptr<weld::Label> mxSheetsFt; + + DECL_LINK(ToggleAllHdl, weld::Toggleable&, void); + DECL_LINK(TogglePagesHdl, weld::Toggleable&, void); + DECL_LINK(ToggleSelectionHdl, weld::Toggleable&, void); + DECL_LINK(ToggleCompressionHdl, weld::Toggleable&, void); + DECL_LINK(ToggleReduceImageResolutionHdl, weld::Toggleable&, void); + DECL_LINK(ToggleWatermarkHdl, weld::Toggleable&, void); + DECL_LINK(ToggleAddStreamHdl, weld::Toggleable&, void); + DECL_LINK(ToggleExportFormFieldsHdl, weld::Toggleable&, void); + DECL_LINK(ToggleExportNotesPagesHdl, weld::Toggleable&, void); + + void TogglePagesHdl(); + void EnableExportNotesPages(); + + DECL_LINK(TogglePDFVersionOrUniversalAccessibilityHandle, weld::Toggleable&, void); + +public: + + ImpPDFTabGeneralPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabGeneralPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + void GetFilterConfigItem(ImpPDFTabDialog* paParent); + void SetFilterConfigItem(ImpPDFTabDialog* paParent); + bool IsPdfaSelected() const { return mxCbPDFA->get_active(); } + bool IsPdfUaSelected() const { return mxCbPDFUA->get_active(); } +}; + +/// Class tab page viewer +class ImpPDFTabOpnFtrPage : public SfxTabPage +{ + bool mbUseCTLFont; + + std::unique_ptr<weld::RadioButton> mxRbOpnPageOnly; + std::unique_ptr<weld::RadioButton> mxRbOpnOutline; + std::unique_ptr<weld::RadioButton> mxRbOpnThumbs; + std::unique_ptr<weld::SpinButton> mxNumInitialPage; + std::unique_ptr<weld::RadioButton> mxRbMagnDefault; + std::unique_ptr<weld::RadioButton> mxRbMagnFitWin; + std::unique_ptr<weld::RadioButton> mxRbMagnFitWidth; + std::unique_ptr<weld::RadioButton> mxRbMagnFitVisible; + std::unique_ptr<weld::RadioButton> mxRbMagnZoom; + std::unique_ptr<weld::SpinButton> mxNumZoom; + std::unique_ptr<weld::RadioButton> mxRbPgLyDefault; + std::unique_ptr<weld::RadioButton> mxRbPgLySinglePage; + std::unique_ptr<weld::RadioButton> mxRbPgLyContinue; + std::unique_ptr<weld::RadioButton> mxRbPgLyContinueFacing; + std::unique_ptr<weld::CheckButton> mxCbPgLyFirstOnLeft; + + DECL_LINK(ToggleRbPgLyContinueFacingHdl, weld::Toggleable&, void); + DECL_LINK(ToggleRbMagnHdl, weld::Toggleable&, void); + + void ToggleRbPgLyContinueFacingHdl(); + +public: + ImpPDFTabOpnFtrPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabOpnFtrPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); +}; + +/// Class tab page viewer +class ImpPDFTabViewerPage : public SfxTabPage +{ + bool mbIsPresentation; + + std::unique_ptr<weld::CheckButton> m_xCbResWinInit; + std::unique_ptr<weld::CheckButton> m_xCbCenterWindow; + std::unique_ptr<weld::CheckButton> m_xCbOpenFullScreen; + std::unique_ptr<weld::CheckButton> m_xCbDispDocTitle; + std::unique_ptr<weld::CheckButton> m_xCbHideViewerMenubar; + std::unique_ptr<weld::CheckButton> m_xCbHideViewerToolbar; + std::unique_ptr<weld::CheckButton> m_xCbHideViewerWindowControls; + std::unique_ptr<weld::CheckButton> m_xCbTransitionEffects; + std::unique_ptr<weld::RadioButton> m_xRbAllBookmarkLevels; + std::unique_ptr<weld::RadioButton> m_xRbVisibleBookmarkLevels; + std::unique_ptr<weld::SpinButton>m_xNumBookmarkLevels; + + DECL_LINK(ToggleRbBookmarksHdl, weld::Toggleable&, void); + +public: + ImpPDFTabViewerPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabViewerPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); +}; + +/// Class security tab page +class ImpPDFTabSecurityPage : public SfxTabPage +{ + OUString msStrSetPwd; + OUString msUserPwdTitle; + bool mbHaveOwnerPassword; + bool mbHaveUserPassword; + css::uno::Sequence< css::beans::NamedValue > maPreparedOwnerPassword; + OUString msOwnerPwdTitle; + + css::uno::Reference< css::beans::XMaterialHolder > mxPreparedPasswords; + + std::unique_ptr<weld::Button> mxPbSetPwd; + std::unique_ptr<weld::Widget> mxUserPwdSet; + std::unique_ptr<weld::Widget> mxUserPwdUnset; + std::unique_ptr<weld::Widget> mxUserPwdPdfa; + std::unique_ptr<weld::Widget> mxOwnerPwdSet; + std::unique_ptr<weld::Widget> mxOwnerPwdUnset; + std::unique_ptr<weld::Widget> mxOwnerPwdPdfa; + std::unique_ptr<weld::Widget> mxPrintPermissions; + std::unique_ptr<weld::RadioButton> mxRbPrintNone; + std::unique_ptr<weld::RadioButton> mxRbPrintLowRes; + std::unique_ptr<weld::RadioButton> mxRbPrintHighRes; + std::unique_ptr<weld::Widget> mxChangesAllowed; + std::unique_ptr<weld::RadioButton> mxRbChangesNone; + std::unique_ptr<weld::RadioButton> mxRbChangesInsDel; + std::unique_ptr<weld::RadioButton> mxRbChangesFillForm; + std::unique_ptr<weld::RadioButton> mxRbChangesComment; + std::unique_ptr<weld::RadioButton> mxRbChangesAnyNoCopy; + std::unique_ptr<weld::Widget> mxContent; + std::unique_ptr<weld::CheckButton> mxCbEnableCopy; + std::unique_ptr<weld::CheckButton> mxCbEnableAccessibility; + std::unique_ptr<weld::Label> mxPasswordTitle; + + DECL_LINK(ClickmaPbSetPwdHdl, weld::Button&, void); + + void enablePermissionControls(); + +public: + ImpPDFTabSecurityPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabSecurityPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); + void ImplPDFASecurityControl( bool bEnableSecurity ); + bool hasPassword() const { return mbHaveOwnerPassword || mbHaveUserPassword; } +}; + +/// Implements the relative link stuff +class ImpPDFTabLinksPage : public SfxTabPage +{ + bool mbOpnLnksDefaultUserState; + bool mbOpnLnksLaunchUserState; + bool mbOpnLnksBrowserUserState; + + std::unique_ptr<weld::CheckButton> m_xCbExprtBmkrToNmDst; + std::unique_ptr<weld::CheckButton> m_xCbOOoToPDFTargets; + std::unique_ptr<weld::CheckButton> m_xCbExportRelativeFsysLinks; + std::unique_ptr<weld::RadioButton> m_xRbOpnLnksDefault; + std::unique_ptr<weld::RadioButton> m_xRbOpnLnksLaunch; + std::unique_ptr<weld::RadioButton> m_xRbOpnLnksBrowser; + + DECL_LINK(ClickRbOpnLnksDefaultHdl, weld::Toggleable&, void); + DECL_LINK(ClickRbOpnLnksBrowserHdl, weld::Toggleable&, void); + +public: + ImpPDFTabLinksPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabLinksPage() override; + + static std::unique_ptr<SfxTabPage> Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); + + void ImplPDFALinkControl( bool bEnableLaunch ); +}; + +//class to implement the digital signing +class ImpPDFTabSigningPage : public SfxTabPage +{ + css::uno::Reference< css::security::XCertificate > maSignCertificate; + + std::unique_ptr<weld::Entry> mxEdSignCert; + std::unique_ptr<weld::Button> mxPbSignCertSelect; + std::unique_ptr<weld::Button> mxPbSignCertClear; + std::unique_ptr<weld::Entry> mxEdSignPassword; + std::unique_ptr<weld::Entry> mxEdSignLocation; + std::unique_ptr<weld::Entry> mxEdSignContactInfo; + std::unique_ptr<weld::Entry> mxEdSignReason; + std::unique_ptr<weld::ComboBox> mxLBSignTSA; + + DECL_LINK(ClickmaPbSignCertSelect, weld::Button&, void); + DECL_LINK(ClickmaPbSignCertClear, weld::Button&, void); + +public: + ImpPDFTabSigningPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rSet); + virtual ~ImpPDFTabSigningPage() override; + + static std::unique_ptr<SfxTabPage> Create( weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rAttrSet ); + + void GetFilterConfigItem( ImpPDFTabDialog* paParent); + void SetFilterConfigItem( const ImpPDFTabDialog* paParent ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfdecomposer.cxx b/filter/source/pdf/pdfdecomposer.cxx new file mode 100644 index 000000000..7a032bf36 --- /dev/null +++ b/filter/source/pdf/pdfdecomposer.cxx @@ -0,0 +1,123 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * 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/. + */ + +#include <vector> + +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <cppuhelper/implbase2.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx> +#include <drawinglayer/primitive2d/Primitive2DContainer.hxx> +#include <vcl/bitmapex.hxx> +#include <vcl/pdfread.hxx> +#include <vcl/svapp.hxx> +#include <vcl/outdev.hxx> +#include <vcl/BinaryDataContainer.hxx> +#include <vcl/BinaryDataContainerTools.hxx> +#include <toolkit/helper/vclunohelper.hxx> + +#include <com/sun/star/graphic/XPdfDecomposer.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/util/XBinaryDataContainer.hpp> + +using namespace css; + +namespace +{ +/// Class to convert the PDF data into a XPrimitive2D (containing only a bitmap). +class XPdfDecomposer + : public ::cppu::WeakAggImplHelper2<graphic::XPdfDecomposer, lang::XServiceInfo> +{ +public: + explicit XPdfDecomposer(uno::Reference<uno::XComponentContext> const& context); + XPdfDecomposer(const XPdfDecomposer&) = delete; + XPdfDecomposer& operator=(const XPdfDecomposer&) = delete; + + // XPdfDecomposer + uno::Sequence<uno::Reference<graphic::XPrimitive2D>> SAL_CALL + getDecomposition(const uno::Reference<util::XBinaryDataContainer>& xDataContainer, + const uno::Sequence<beans::PropertyValue>& xDecompositionParameters) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + sal_Bool SAL_CALL supportsService(const OUString&) override; + uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; +}; + +XPdfDecomposer::XPdfDecomposer(uno::Reference<uno::XComponentContext> const&) {} + +uno::Sequence<uno::Reference<graphic::XPrimitive2D>> SAL_CALL +XPdfDecomposer::getDecomposition(const uno::Reference<util::XBinaryDataContainer>& xDataContainer, + const uno::Sequence<beans::PropertyValue>& xParameters) +{ + sal_Int32 nPageIndex = -1; + + for (const beans::PropertyValue& rProperty : xParameters) + { + if (rProperty.Name == "PageIndex") + { + rProperty.Value >>= nPageIndex; + break; + } + } + + if (nPageIndex < 0) + nPageIndex = 0; + + BinaryDataContainer aDataContainer = vcl::convertUnoBinaryDataContainer(xDataContainer); + + std::vector<BitmapEx> aBitmaps; + int rv = vcl::RenderPDFBitmaps(aDataContainer.getData(), aDataContainer.getSize(), aBitmaps, + nPageIndex, 1); + if (rv == 0) + return {}; // happens if we do not have PDFium + + BitmapEx aReplacement(aBitmaps[0]); + + // short form for scale and translate transformation + const Size aBitmapSize(aReplacement.GetSizePixel()); + // ImpGraphic::getPrefMapMode() requires mm100 for bitmaps rendered from vector graphic data. + const Size aMM100( + Application::GetDefaultDevice()->PixelToLogic(aBitmapSize, MapMode(MapUnit::Map100thMM))); + const basegfx::B2DHomMatrix aBitmapTransform(basegfx::utils::createScaleTranslateB2DHomMatrix( + aMM100.getWidth(), aMM100.getHeight(), 0, 0)); + + // create primitive + return drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::BitmapPrimitive2D( + VCLUnoHelper::CreateVCLXBitmap(aReplacement), aBitmapTransform) + } + .toSequence(); +} + +OUString SAL_CALL XPdfDecomposer::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFDecomposer"; +} + +sal_Bool SAL_CALL XPdfDecomposer::supportsService(const OUString& rServiceName) +{ + return cppu::supportsService(this, rServiceName); +} + +uno::Sequence<OUString> SAL_CALL XPdfDecomposer::getSupportedServiceNames() +{ + return { "com.sun.star.graphic.PdfTools" }; +} +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PdfDecomposer_get_implementation(css::uno::XComponentContext* context, + css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new XPdfDecomposer(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/filter/source/pdf/pdfdialog.cxx b/filter/source/pdf/pdfdialog.cxx new file mode 100644 index 000000000..7c3e5dda1 --- /dev/null +++ b/filter/source/pdf/pdfdialog.cxx @@ -0,0 +1,139 @@ +/* -*- 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 "pdfdialog.hxx" +#include "impdialog.hxx" +#include <vcl/svapp.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; + +PDFDialog::PDFDialog( const Reference< XComponentContext > &rxContext ) +: PDFDialog_Base( rxContext ) +{ +} + + +PDFDialog::~PDFDialog() +{ +} + + +Sequence< sal_Int8 > SAL_CALL PDFDialog::getImplementationId() +{ + return css::uno::Sequence<sal_Int8>(); +} + + +OUString SAL_CALL PDFDialog::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFDialog"; +} + + +Sequence< OUString > SAL_CALL PDFDialog::getSupportedServiceNames() +{ + return { "com.sun.star.document.PDFDialog" }; +} + +std::unique_ptr<weld::DialogController> PDFDialog::createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) +{ + if( mxSrcDoc.is() ) + return std::make_unique<ImpPDFTabDialog>(Application::GetFrameWeld(rParent), maFilterData, mxSrcDoc); + return nullptr; +} + +void PDFDialog::executedDialog( sal_Int16 nExecutionResult ) +{ + if (nExecutionResult && m_xDialog) + maFilterData = static_cast<ImpPDFTabDialog*>(m_xDialog.get())->GetFilterData(); + destroyDialog(); +} + +Reference< XPropertySetInfo > SAL_CALL PDFDialog::getPropertySetInfo() +{ + Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) ); + return xInfo; +} + +::cppu::IPropertyArrayHelper& PDFDialog::getInfoHelper() +{ + return *getArrayHelper(); +} + +::cppu::IPropertyArrayHelper* PDFDialog::createArrayHelper() const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper( aProps ); +} + + +Sequence< PropertyValue > SAL_CALL PDFDialog::getPropertyValues() +{ + sal_Int32 i, nCount; + + for( i = 0, nCount = maMediaDescriptor.getLength(); i < nCount; i++ ) + { + if ( maMediaDescriptor[ i ].Name == "FilterData" ) + break; + } + + if( i == nCount ) + maMediaDescriptor.realloc( ++nCount ); + auto pMediaDescriptor = maMediaDescriptor.getArray(); + + pMediaDescriptor[ i ].Name = "FilterData"; + pMediaDescriptor[ i ].Value <<= maFilterData; + + return maMediaDescriptor; +} + + +void SAL_CALL PDFDialog::setPropertyValues( const Sequence< PropertyValue >& rProps ) +{ + maMediaDescriptor = rProps; + + for( const PropertyValue& rProp : std::as_const(maMediaDescriptor) ) + { + if ( rProp.Name == "FilterData" ) + { + rProp.Value >>= maFilterData; + break; + } + } +} + + +void SAL_CALL PDFDialog::setSourceDocument( const Reference< XComponent >& xDoc ) +{ + mxSrcDoc = xDoc; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PDFDialog_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new PDFDialog(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfdialog.hxx b/filter/source/pdf/pdfdialog.hxx new file mode 100644 index 000000000..fcfd1d097 --- /dev/null +++ b/filter/source/pdf/pdfdialog.hxx @@ -0,0 +1,72 @@ +/* -*- 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 . + */ + +#pragma once + +#include <svtools/genericunodialog.hxx> + +#include <comphelper/proparrhlp.hxx> +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/beans/XPropertyAccess.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/lang/XComponent.hpp> + +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::uno; + +typedef ::cppu::ImplInheritanceHelper < ::svt::OGenericUnoDialog, XPropertyAccess, XExporter > PDFDialog_Base; + +class PDFDialog final: + public PDFDialog_Base, + public ::comphelper::OPropertyArrayUsageHelper< PDFDialog > +{ +private: + Sequence< PropertyValue > maMediaDescriptor; + Sequence< PropertyValue > maFilterData; + Reference< XComponent > mxSrcDoc; + + // OGenericUnoDialog + virtual Sequence< sal_Int8 > SAL_CALL getImplementationId() override; + virtual OUString SAL_CALL getImplementationName() override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + virtual std::unique_ptr<weld::DialogController> createDialog(const css::uno::Reference<css::awt::XWindow>& rParent) override; + virtual void executedDialog( sal_Int16 nExecutionResult ) override; + virtual Reference< XPropertySetInfo> SAL_CALL getPropertySetInfo() override; + virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override; + virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override; + + // XPropertyAccess + using OPropertySetHelper::getPropertyValues; + virtual Sequence< PropertyValue > SAL_CALL getPropertyValues( ) override; + using OPropertySetHelper::setPropertyValues; + virtual void SAL_CALL setPropertyValues( const Sequence< PropertyValue >& aProps ) override; + + // XExporter + virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override; + +public: + + explicit PDFDialog( const Reference< XComponentContext >& rxContext ); + virtual ~PDFDialog() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfexport.cxx b/filter/source/pdf/pdfexport.cxx new file mode 100644 index 000000000..7a233aad0 --- /dev/null +++ b/filter/source/pdf/pdfexport.cxx @@ -0,0 +1,1374 @@ +/* -*- 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 <osl/file.hxx> +#include <tools/debug.hxx> +#include <tools/urlobj.hxx> +#include <tools/poly.hxx> +#include <tools/diagnose_ex.h> +#include <unotools/resmgr.hxx> +#include <utility> +#include <vcl/canvastools.hxx> +#include <vcl/mapmod.hxx> +#include <vcl/gdimtf.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/string.hxx> +#include <comphelper/storagehelper.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <toolkit/awt/vclxdevice.hxx> +#include <unotools/configmgr.hxx> +#include <cppuhelper/compbase.hxx> +#include <cppuhelper/basemutex.hxx> +#include <officecfg/Office/Common.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> + +#include "pdfexport.hxx" +#include <strings.hrc> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/awt/XDevice.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/frame/ModuleManager.hpp> +#include <com/sun/star/frame/XStorable.hpp> +#include <com/sun/star/document/XDocumentProperties.hpp> +#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/view/XViewSettingsSupplier.hpp> +#include <com/sun/star/task/XInteractionRequest.hpp> +#include <com/sun/star/task/PDFExportException.hpp> +#include <com/sun/star/io/IOException.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/drawing/XShapes.hpp> +#include <com/sun/star/security/XCertificate.hpp> +#include <com/sun/star/beans/XMaterialHolder.hpp> +#include <com/sun/star/xml/crypto/SEInitializer.hpp> + +#include <memory> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::io; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::view; +using namespace ::com::sun::star::graphic; + + +PDFExport::PDFExport( const Reference< XComponent >& rxSrcDoc, + const Reference< task::XStatusIndicator >& rxStatusIndicator, + const Reference< task::XInteractionHandler >& rxIH, + const Reference< XComponentContext >& xContext ) : + mxSrcDoc ( rxSrcDoc ), + mxContext ( xContext ), + mxStatusIndicator ( rxStatusIndicator ), + mxIH ( rxIH ), + mbUseTaggedPDF ( false ), + mnPDFTypeSelection ( 0 ), + mbPDFUACompliance ( false), + mbExportNotes ( true ), + mbExportPlaceholders ( false ), + mbUseReferenceXObject ( false ), + mbExportNotesPages ( false ), + mbExportOnlyNotesPages ( false ), + mbUseTransitionEffects ( true ), + mbExportBookmarks ( true ), + mbExportHiddenSlides ( false ), + mbSinglePageSheets ( false ), + mnOpenBookmarkLevels ( -1 ), + mbUseLosslessCompression ( false ), + mbReduceImageResolution ( true ), + mbSkipEmptyPages ( true ), + mbAddStream ( false ), + mnMaxImageResolution ( 300 ), + mnQuality ( 80 ), + mnFormsFormat ( 0 ), + mbExportFormFields ( true ), + mbAllowDuplicateFieldNames ( false ), + mnProgressValue ( 0 ), + mbRemoveTransparencies ( false ), + + mbIsRedactMode ( false ), + maWatermarkColor ( COL_LIGHTGREEN ), + maWatermarkFontName ( "Helvetica" ), + + mbHideViewerToolbar ( false ), + mbHideViewerMenubar ( false ), + mbHideViewerWindowControls ( false ), + mbFitWindow ( false ), + mbCenterWindow ( false ), + mbOpenInFullScreenMode ( false ), + mbDisplayPDFDocumentTitle ( true ), + mnPDFDocumentMode ( 0 ), + mnPDFDocumentAction ( 0 ), + mnZoom ( 100 ), + mnInitialPage ( 1 ), + mnPDFPageLayout ( 0 ), + + mbEncrypt ( false ), + mbRestrictPermissions ( false ), + mnPrintAllowed ( 2 ), + mnChangesAllowed ( 4 ), + mbCanCopyOrExtract ( true ), + mbCanExtractForAccessibility( true ), + + // #i56629 + mbExportRelativeFsysLinks ( false ), + mnDefaultLinkAction ( 0 ), + mbConvertOOoTargetToPDFTarget( false ), + mbExportBmkToDest ( false ), + mbSignPDF ( false ) +{ +} + + +PDFExport::~PDFExport() +{ +} + + +bool PDFExport::ExportSelection( vcl::PDFWriter& rPDFWriter, + Reference< css::view::XRenderable > const & rRenderable, + const Any& rSelection, + const StringRangeEnumerator& rRangeEnum, + Sequence< PropertyValue >& rRenderOptions, + sal_Int32 nPageCount ) +{ + bool bRet = false; + try + { + Any* pFirstPage = nullptr; + Any* pLastPage = nullptr; + + bool bExportNotesPages = false; + + auto rRenderOptionsRange = asNonConstRange(rRenderOptions); + for( sal_Int32 nData = 0, nDataCount = rRenderOptions.getLength(); nData < nDataCount; ++nData ) + { + if ( rRenderOptions[ nData ].Name == "IsFirstPage" ) + pFirstPage = &rRenderOptionsRange[ nData ].Value; + else if ( rRenderOptions[ nData ].Name == "IsLastPage" ) + pLastPage = &rRenderOptionsRange[ nData ].Value; + else if ( rRenderOptions[ nData ].Name == "ExportNotesPages" ) + rRenderOptionsRange[ nData ].Value >>= bExportNotesPages; + } + + OutputDevice* pOut = rPDFWriter.GetReferenceDevice(); + + if( pOut ) + { + if ( nPageCount ) + { + vcl::PDFExtOutDevData& rPDFExtOutDevData = dynamic_cast<vcl::PDFExtOutDevData&>(*pOut->GetExtOutDevData()); + rPDFExtOutDevData.SetIsExportNotesPages( bExportNotesPages ); + + sal_Int32 nCurrentPage(0); + StringRangeEnumerator::Iterator aIter = rRangeEnum.begin(); + StringRangeEnumerator::Iterator aEnd = rRangeEnum.end(); + while ( aIter != aEnd ) + { + const Sequence< PropertyValue > aRenderer( rRenderable->getRenderer( *aIter, rSelection, rRenderOptions ) ); + awt::Size aPageSize; + + for( const PropertyValue& rProp : aRenderer ) + { + if ( rProp.Name == "PageSize" ) + { + rProp.Value >>= aPageSize; + break; + } + } + + rPDFExtOutDevData.SetCurrentPageNumber( nCurrentPage ); + + GDIMetaFile aMtf; + const MapMode aMapMode( MapUnit::Map100thMM ); + const Size aMtfSize( aPageSize.Width, aPageSize.Height ); + + pOut->Push(); + pOut->EnableOutput( false ); + pOut->SetMapMode( aMapMode ); + + aMtf.SetPrefSize( aMtfSize ); + aMtf.SetPrefMapMode( aMapMode ); + aMtf.Record( pOut ); + + // #i35176# + // IsLastPage property. + const sal_Int32 nCurrentRenderer = *aIter; + ++aIter; + if ( pLastPage && aIter == aEnd ) + *pLastPage <<= true; + + rRenderable->render( nCurrentRenderer, rSelection, rRenderOptions ); + + aMtf.Stop(); + aMtf.WindStart(); + + bool bEmptyPage = false; + if( aMtf.GetActionSize() && + ( !mbSkipEmptyPages || aPageSize.Width || aPageSize.Height ) ) + { + // We convert the whole metafile into a bitmap to get rid of the + // text covered by redaction shapes + if (mbIsRedactMode) + { + try + { + Graphic aGraph(aMtf); + // use antialiasing to improve how graphic objects look + BitmapEx bmp = aGraph.GetBitmapEx(GraphicConversionParameters(Size(0, 0), false, true, false)); + Graphic bgraph(bmp); + aMtf = bgraph.GetGDIMetaFile(); + } + catch(const Exception&) + { + TOOLS_WARN_EXCEPTION("filter.pdf", "Something went wrong while converting metafile to bitmap"); + } + } + + ImplExportPage(rPDFWriter, rPDFExtOutDevData, aMtf); + bRet = true; + } + else + { + bEmptyPage = true; + } + + pOut->Pop(); + + if ( mxStatusIndicator.is() ) + mxStatusIndicator->setValue( mnProgressValue ); + if ( pFirstPage ) + *pFirstPage <<= false; + + ++mnProgressValue; + if (!bEmptyPage) + { + // Calculate the page number in the PDF output, which may be smaller than the page number in + // case of hidden slides or a partial export. + ++nCurrentPage; + } + } + } + else + { + bRet = true; // #i18334# nPageCount == 0, + rPDFWriter.NewPage( 10000, 10000 ); // creating dummy page + rPDFWriter.SetMapMode(MapMode(MapUnit::Map100thMM)); + } + } + } + catch(const RuntimeException &) + { + } + return bRet; +} + +namespace { + +class PDFExportStreamDoc : public vcl::PDFOutputStream +{ +private: + + Reference< XComponent > m_xSrcDoc; + Sequence< beans::NamedValue > m_aPreparedPassword; + +public: + + PDFExportStreamDoc( const Reference< XComponent >& xDoc, const Sequence<beans::NamedValue>& rPwd ) + : m_xSrcDoc( xDoc ), + m_aPreparedPassword( rPwd ) + {} + + virtual void write( const Reference< XOutputStream >& xStream ) override; +}; + +} + +void PDFExportStreamDoc::write( const Reference< XOutputStream >& xStream ) +{ + Reference< css::frame::XStorable > xStore( m_xSrcDoc, UNO_QUERY ); + if( !xStore.is() ) + return; + + Sequence< beans::PropertyValue > aArgs( 2 + (m_aPreparedPassword.hasElements() ? 1 : 0) ); + aArgs.getArray()[0].Name = "FilterName"; + aArgs.getArray()[1].Name = "OutputStream"; + aArgs.getArray()[1].Value <<= xStream; + if( m_aPreparedPassword.hasElements() ) + { + aArgs.getArray()[2].Name = "EncryptionData"; + aArgs.getArray()[2].Value <<= m_aPreparedPassword; + } + + try + { + xStore->storeToURL( "private:stream", aArgs ); + } + catch( const IOException& ) + { + } +} + + +static OUString getMimetypeForDocument( const Reference< XComponentContext >& xContext, + const Reference< XComponent >& xDoc ) noexcept +{ + OUString aDocMimetype; + try + { + // get document service name + Reference< css::frame::XStorable > xStore( xDoc, UNO_QUERY ); + Reference< frame::XModuleManager2 > xModuleManager = frame::ModuleManager::create(xContext); + if( xStore.is() ) + { + OUString aDocServiceName = xModuleManager->identify( Reference< XInterface >( xStore, uno::UNO_QUERY ) ); + if ( !aDocServiceName.isEmpty() ) + { + // get the actual filter name + Reference< lang::XMultiServiceFactory > xConfigProvider = + configuration::theDefaultProvider::get( xContext ); + beans::NamedValue aPathProp; + aPathProp.Name = "nodepath"; + aPathProp.Value <<= OUString( "/org.openoffice.Setup/Office/Factories/" ); + uno::Sequence< uno::Any > aArgs{ uno::Any(aPathProp) }; + + Reference< container::XNameAccess > xSOFConfig( + xConfigProvider->createInstanceWithArguments( + "com.sun.star.configuration.ConfigurationAccess", aArgs ), + uno::UNO_QUERY ); + + Reference< container::XNameAccess > xApplConfig; + xSOFConfig->getByName( aDocServiceName ) >>= xApplConfig; + if ( xApplConfig.is() ) + { + OUString aFilterName; + xApplConfig->getByName( "ooSetupFactoryActualFilter" ) >>= aFilterName; + if( !aFilterName.isEmpty() ) + { + // find the related type name + OUString aTypeName; + Reference< container::XNameAccess > xFilterFactory( + xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.FilterFactory", xContext), + uno::UNO_QUERY ); + + Sequence< beans::PropertyValue > aFilterData; + xFilterFactory->getByName( aFilterName ) >>= aFilterData; + for ( const beans::PropertyValue& rProp : std::as_const(aFilterData) ) + if ( rProp.Name == "Type" ) + rProp.Value >>= aTypeName; + + if ( !aTypeName.isEmpty() ) + { + // find the mediatype + Reference< container::XNameAccess > xTypeDetection( + xContext->getServiceManager()->createInstanceWithContext("com.sun.star.document.TypeDetection", xContext), + UNO_QUERY ); + + Sequence< beans::PropertyValue > aTypeData; + xTypeDetection->getByName( aTypeName ) >>= aTypeData; + for ( const beans::PropertyValue& rProp : std::as_const(aTypeData) ) + if ( rProp.Name == "MediaType" ) + rProp.Value >>= aDocMimetype; + } + } + } + } + } + } + catch (...) + { + } + return aDocMimetype; +} + +uno::Reference<security::XCertificate> +PDFExport::GetCertificateFromSubjectName(const std::u16string_view& rSubjectName) const +{ + uno::Reference<xml::crypto::XSEInitializer> xSEInitializer + = xml::crypto::SEInitializer::create(mxContext); + uno::Reference<xml::crypto::XXMLSecurityContext> xSecurityContext + = xSEInitializer->createSecurityContext(OUString()); + uno::Reference<xml::crypto::XSecurityEnvironment> xSecurityEnvironment + = xSecurityContext->getSecurityEnvironment(); + for (const auto& xCertificate : xSecurityEnvironment->getPersonalCertificates()) + { + if (xCertificate->getSubjectName() == rSubjectName) + { + return xCertificate; + } + } + + return {}; +} + +bool PDFExport::Export( const OUString& rFile, const Sequence< PropertyValue >& rFilterData ) +{ + INetURLObject aURL( rFile ); + bool bRet = false; + + std::set< vcl::PDFWriter::ErrorCode > aErrors; + + if( aURL.GetProtocol() != INetProtocol::File ) + { + OUString aTmp; + + if( osl::FileBase::getFileURLFromSystemPath( rFile, aTmp ) == osl::FileBase::E_None ) + aURL = INetURLObject(aTmp); + } + + if( aURL.GetProtocol() == INetProtocol::File ) + { + Reference< XRenderable > xRenderable( mxSrcDoc, UNO_QUERY ); + + if( xRenderable.is() ) + { + rtl::Reference<VCLXDevice> xDevice(new VCLXDevice); + OUString aPageRange; + Any aSelection; + vcl::PDFWriter::PDFWriterContext aContext; + OUString aOpenPassword, aPermissionPassword; + Reference< beans::XMaterialHolder > xEnc; + Sequence< beans::NamedValue > aPreparedPermissionPassword; + + + // getting the string for the creator + OUString aCreator; + Reference< XServiceInfo > xInfo( mxSrcDoc, UNO_QUERY ); + if ( xInfo.is() ) + { + if ( xInfo->supportsService( "com.sun.star.presentation.PresentationDocument" ) ) + aCreator += "Impress"; + else if ( xInfo->supportsService( "com.sun.star.drawing.DrawingDocument" ) ) + aCreator += "Draw"; + else if ( xInfo->supportsService( "com.sun.star.text.TextDocument" ) ) + aCreator += "Writer"; + else if ( xInfo->supportsService( "com.sun.star.sheet.SpreadsheetDocument" ) ) + aCreator += "Calc"; + else if ( xInfo->supportsService( "com.sun.star.formula.FormulaProperties" ) ) + aCreator += "Math"; + } + + Reference< document::XDocumentPropertiesSupplier > xDocumentPropsSupplier( mxSrcDoc, UNO_QUERY ); + if ( xDocumentPropsSupplier.is() ) + { + Reference< document::XDocumentProperties > xDocumentProps( xDocumentPropsSupplier->getDocumentProperties() ); + if ( xDocumentProps.is() ) + { + aContext.DocumentInfo.Title = xDocumentProps->getTitle(); + aContext.DocumentInfo.Author = xDocumentProps->getAuthor(); + aContext.DocumentInfo.Subject = xDocumentProps->getSubject(); + aContext.DocumentInfo.Keywords = ::comphelper::string::convertCommaSeparated(xDocumentProps->getKeywords()); + } + } + // getting the string for the producer + OUString aProducerOverride = officecfg::Office::Common::Save::Document::GeneratorOverride::get(); + if( !aProducerOverride.isEmpty()) + aContext.DocumentInfo.Producer = aProducerOverride; + else + aContext.DocumentInfo.Producer = + utl::ConfigManager::getProductName() + + " " + + utl::ConfigManager::getProductVersion(); + + aContext.DocumentInfo.Creator = aCreator; + + OUString aSignCertificateSubjectName; + for ( const beans::PropertyValue& rProp : rFilterData ) + { + if ( rProp.Name == "PageRange" ) + rProp.Value >>= aPageRange; + else if ( rProp.Name == "Selection" ) + aSelection = rProp.Value; + else if ( rProp.Name == "UseLosslessCompression" ) + rProp.Value >>= mbUseLosslessCompression; + else if ( rProp.Name == "Quality" ) + rProp.Value >>= mnQuality; + else if ( rProp.Name == "ReduceImageResolution" ) + rProp.Value >>= mbReduceImageResolution; + else if ( rProp.Name == "IsSkipEmptyPages" ) + rProp.Value >>= mbSkipEmptyPages; + else if ( rProp.Name == "MaxImageResolution" ) + rProp.Value >>= mnMaxImageResolution; + else if ( rProp.Name == "UseTaggedPDF" ) + rProp.Value >>= mbUseTaggedPDF; + else if ( rProp.Name == "SelectPdfVersion" ) + rProp.Value >>= mnPDFTypeSelection; + else if ( rProp.Name == "PDFUACompliance" ) + rProp.Value >>= mbPDFUACompliance; + else if ( rProp.Name == "ExportNotes" ) + rProp.Value >>= mbExportNotes; + else if ( rProp.Name == "ExportNotesPages" ) + rProp.Value >>= mbExportNotesPages; + else if ( rProp.Name == "ExportOnlyNotesPages" ) + rProp.Value >>= mbExportOnlyNotesPages; + else if ( rProp.Name == "UseTransitionEffects" ) + rProp.Value >>= mbUseTransitionEffects; + else if ( rProp.Name == "ExportFormFields" ) + rProp.Value >>= mbExportFormFields; + else if ( rProp.Name == "FormsType" ) + rProp.Value >>= mnFormsFormat; + else if ( rProp.Name == "AllowDuplicateFieldNames" ) + rProp.Value >>= mbAllowDuplicateFieldNames; + // viewer properties + else if ( rProp.Name == "HideViewerToolbar" ) + rProp.Value >>= mbHideViewerToolbar; + else if ( rProp.Name == "HideViewerMenubar" ) + rProp.Value >>= mbHideViewerMenubar; + else if ( rProp.Name == "HideViewerWindowControls" ) + rProp.Value >>= mbHideViewerWindowControls; + else if ( rProp.Name == "ResizeWindowToInitialPage" ) + rProp.Value >>= mbFitWindow; + else if ( rProp.Name == "CenterWindow" ) + rProp.Value >>= mbCenterWindow; + else if ( rProp.Name == "OpenInFullScreenMode" ) + rProp.Value >>= mbOpenInFullScreenMode; + else if ( rProp.Name == "DisplayPDFDocumentTitle" ) + rProp.Value >>= mbDisplayPDFDocumentTitle; + else if ( rProp.Name == "InitialView" ) + rProp.Value >>= mnPDFDocumentMode; + else if ( rProp.Name == "Magnification" ) + rProp.Value >>= mnPDFDocumentAction; + else if ( rProp.Name == "Zoom" ) + rProp.Value >>= mnZoom; + else if ( rProp.Name == "InitialPage" ) + rProp.Value >>= mnInitialPage; + else if ( rProp.Name == "PageLayout" ) + rProp.Value >>= mnPDFPageLayout; + else if ( rProp.Name == "FirstPageOnLeft" ) + rProp.Value >>= aContext.FirstPageLeft; + else if ( rProp.Name == "IsAddStream" ) + rProp.Value >>= mbAddStream; + else if ( rProp.Name == "Watermark" ) + rProp.Value >>= msWatermark; + else if ( rProp.Name == "WatermarkColor" ) + { + sal_Int32 nColor{}; + if (rProp.Value >>= nColor) + { + maWatermarkColor = Color(ColorTransparency, nColor); + } + } + else if (rProp.Name == "WatermarkFontHeight") + { + sal_Int32 nFontHeight{}; + if (rProp.Value >>= nFontHeight) + { + moWatermarkFontHeight = nFontHeight; + } + } + else if (rProp.Name == "WatermarkRotateAngle") + { + sal_Int32 nRotateAngle{}; + if (rProp.Value >>= nRotateAngle) + { + moWatermarkRotateAngle = Degree10(nRotateAngle); + } + } + else if (rProp.Name == "WatermarkFontName") + { + OUString aFontName{}; + if (rProp.Value >>= aFontName) + { + maWatermarkFontName = aFontName; + } + } + else if ( rProp.Name == "TiledWatermark" ) + rProp.Value >>= msTiledWatermark; + // now all the security related properties... + else if ( rProp.Name == "EncryptFile" ) + rProp.Value >>= mbEncrypt; + else if ( rProp.Name == "DocumentOpenPassword" ) + rProp.Value >>= aOpenPassword; + else if ( rProp.Name == "RestrictPermissions" ) + rProp.Value >>= mbRestrictPermissions; + else if ( rProp.Name == "PermissionPassword" ) + rProp.Value >>= aPermissionPassword; + else if ( rProp.Name == "PreparedPasswords" ) + rProp.Value >>= xEnc; + else if ( rProp.Name == "PreparedPermissionPassword" ) + rProp.Value >>= aPreparedPermissionPassword; + else if ( rProp.Name == "Printing" ) + rProp.Value >>= mnPrintAllowed; + else if ( rProp.Name == "Changes" ) + rProp.Value >>= mnChangesAllowed; + else if ( rProp.Name == "EnableCopyingOfContent" ) + rProp.Value >>= mbCanCopyOrExtract; + else if ( rProp.Name == "EnableTextAccessForAccessibilityTools" ) + rProp.Value >>= mbCanExtractForAccessibility; + // i56629 links extra (relative links and other related stuff) + else if ( rProp.Name == "ExportLinksRelativeFsys" ) + rProp.Value >>= mbExportRelativeFsysLinks; + else if ( rProp.Name == "PDFViewSelection" ) + rProp.Value >>= mnDefaultLinkAction; + else if ( rProp.Name == "ConvertOOoTargetToPDFTarget" ) + rProp.Value >>= mbConvertOOoTargetToPDFTarget; + else if ( rProp.Name == "ExportBookmarksToPDFDestination" ) + rProp.Value >>= mbExportBmkToDest; + else if ( rProp.Name == "ExportBookmarks" ) + rProp.Value >>= mbExportBookmarks; + else if ( rProp.Name == "ExportHiddenSlides" ) + rProp.Value >>= mbExportHiddenSlides; + else if ( rProp.Name == "SinglePageSheets" ) + rProp.Value >>= mbSinglePageSheets; + else if ( rProp.Name == "OpenBookmarkLevels" ) + rProp.Value >>= mnOpenBookmarkLevels; + else if ( rProp.Name == "SignPDF" ) + rProp.Value >>= mbSignPDF; + else if ( rProp.Name == "SignatureLocation" ) + rProp.Value >>= msSignLocation; + else if ( rProp.Name == "SignatureReason" ) + rProp.Value >>= msSignReason; + else if ( rProp.Name == "SignatureContactInfo" ) + rProp.Value >>= msSignContact; + else if ( rProp.Name == "SignaturePassword" ) + rProp.Value >>= msSignPassword; + else if ( rProp.Name == "SignatureCertificate" ) + rProp.Value >>= maSignCertificate; + else if (rProp.Name == "SignCertificateSubjectName") + rProp.Value >>= aSignCertificateSubjectName; + else if ( rProp.Name == "SignatureTSA" ) + rProp.Value >>= msSignTSA; + else if ( rProp.Name == "ExportPlaceholders" ) + rProp.Value >>= mbExportPlaceholders; + else if ( rProp.Name == "UseReferenceXObject" ) + rProp.Value >>= mbUseReferenceXObject; + // Redaction & bitmap related stuff + else if ( rProp.Name == "IsRedactMode" ) + rProp.Value >>= mbIsRedactMode; + } + + if (!maSignCertificate.is() && !aSignCertificateSubjectName.isEmpty()) + { + maSignCertificate = GetCertificateFromSubjectName(aSignCertificateSubjectName); + } + + aContext.URL = aURL.GetMainURL(INetURLObject::DecodeMechanism::ToIUri); + + // set the correct version, depending on user request + switch( mnPDFTypeSelection ) + { + default: + case 0: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6; + break; + case 1: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_1; + mbUseTaggedPDF = true; // force the tagged PDF as well + mbRemoveTransparencies = true; // does not allow transparencies + mbEncrypt = false; // no encryption + xEnc.clear(); + break; + case 2: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_2; + mbUseTaggedPDF = true; // force the tagged PDF as well + mbRemoveTransparencies = false; // does allow transparencies + mbEncrypt = false; // no encryption + xEnc.clear(); + break; + case 3: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_A_3; + mbUseTaggedPDF = true; // force the tagged PDF as well + mbRemoveTransparencies = false; // does allow transparencies + mbEncrypt = false; // no encryption + xEnc.clear(); + break; + case 15: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_5; + break; + case 16: + aContext.Version = vcl::PDFWriter::PDFVersion::PDF_1_6; + break; + } + + // PDF/UA support + aContext.UniversalAccessibilityCompliance = mbPDFUACompliance; + if (mbPDFUACompliance) + { + mbUseTaggedPDF = true; + } + + // copy in context the values default in the constructor or set by the FilterData sequence of properties + aContext.Tagged = mbUseTaggedPDF; + + // values used in viewer + aContext.HideViewerToolbar = mbHideViewerToolbar; + aContext.HideViewerMenubar = mbHideViewerMenubar; + aContext.HideViewerWindowControls = mbHideViewerWindowControls; + aContext.FitWindow = mbFitWindow; + aContext.CenterWindow = mbCenterWindow; + aContext.OpenInFullScreenMode = mbOpenInFullScreenMode; + aContext.DisplayPDFDocumentTitle = mbDisplayPDFDocumentTitle; + aContext.InitialPage = mnInitialPage-1; + aContext.OpenBookmarkLevels = mnOpenBookmarkLevels; + + switch( mnPDFDocumentMode ) + { + default: + case 0: + aContext.PDFDocumentMode = vcl::PDFWriter::ModeDefault; + break; + case 1: + aContext.PDFDocumentMode = vcl::PDFWriter::UseOutlines; + break; + case 2: + aContext.PDFDocumentMode = vcl::PDFWriter::UseThumbs; + break; + } + switch( mnPDFDocumentAction ) + { + default: + case 0: + aContext.PDFDocumentAction = vcl::PDFWriter::ActionDefault; + break; + case 1: + aContext.PDFDocumentAction = vcl::PDFWriter::FitInWindow; + break; + case 2: + aContext.PDFDocumentAction = vcl::PDFWriter::FitWidth; + break; + case 3: + aContext.PDFDocumentAction = vcl::PDFWriter::FitVisible; + break; + case 4: + aContext.PDFDocumentAction = vcl::PDFWriter::ActionZoom; + aContext.Zoom = mnZoom; + break; + } + + switch( mnPDFPageLayout ) + { + default: + case 0: + aContext.PageLayout = vcl::PDFWriter::DefaultLayout; + break; + case 1: + aContext.PageLayout = vcl::PDFWriter::SinglePage; + break; + case 2: + aContext.PageLayout = vcl::PDFWriter::Continuous; + break; + case 3: + aContext.PageLayout = vcl::PDFWriter::ContinuousFacing; + break; + } + + aContext.FirstPageLeft = false; + + // check if PDF/A, which does not allow encryption + if( aContext.Version != vcl::PDFWriter::PDFVersion::PDF_A_1 ) + { + // set check for permission change password + // if not enabled and no permission password, force permissions to default as if PDF where without encryption + if( mbRestrictPermissions && (xEnc.is() || !aPermissionPassword.isEmpty()) ) + { + mbEncrypt = true; // permission set as desired, done after + } + else + { + // force permission to default + mnPrintAllowed = 2 ; + mnChangesAllowed = 4 ; + mbCanCopyOrExtract = true; + mbCanExtractForAccessibility = true ; + } + + switch( mnPrintAllowed ) + { + case 0: // initialized when aContext is build, means no printing + break; + default: + case 2: + aContext.Encryption.CanPrintFull = true; + [[fallthrough]]; + case 1: + aContext.Encryption.CanPrintTheDocument = true; + break; + } + + switch( mnChangesAllowed ) + { + case 0: // already in struct PDFSecPermissions CTOR + break; + case 1: + aContext.Encryption.CanAssemble = true; + break; + case 2: + aContext.Encryption.CanFillInteractive = true; + break; + case 3: + aContext.Encryption.CanAddOrModify = true; + break; + default: + case 4: + aContext.Encryption.CanModifyTheContent = + aContext.Encryption.CanCopyOrExtract = + aContext.Encryption.CanAddOrModify = + aContext.Encryption.CanFillInteractive = true; + break; + } + + aContext.Encryption.CanCopyOrExtract = mbCanCopyOrExtract; + aContext.Encryption.CanExtractForAccessibility = mbCanExtractForAccessibility; + if( mbEncrypt && ! xEnc.is() ) + xEnc = vcl::PDFWriter::InitEncryption( aPermissionPassword, aOpenPassword ); + if( mbEncrypt && !aPermissionPassword.isEmpty() && ! aPreparedPermissionPassword.hasElements() ) + aPreparedPermissionPassword = comphelper::OStorageHelper::CreatePackageEncryptionData( aPermissionPassword ); + } + // after this point we don't need the legacy clear passwords anymore + // however they are still inside the passed filter data sequence + // which is sadly out of our control + aPermissionPassword.clear(); + aOpenPassword.clear(); + + /* + * FIXME: the entries are only implicitly defined by the resource file. Should there + * ever be an additional form submit format this could get invalid. + */ + switch( mnFormsFormat ) + { + case 1: + aContext.SubmitFormat = vcl::PDFWriter::PDF; + break; + case 2: + aContext.SubmitFormat = vcl::PDFWriter::HTML; + break; + case 3: + aContext.SubmitFormat = vcl::PDFWriter::XML; + break; + default: + case 0: + aContext.SubmitFormat = vcl::PDFWriter::FDF; + break; + } + aContext.AllowDuplicateFieldNames = mbAllowDuplicateFieldNames; + + // get model + Reference< frame::XModel > xModel( mxSrcDoc, UNO_QUERY ); + { + // #i56629: Relative link stuff + // set the base URL of the file: then base URL + aContext.BaseURL = xModel->getURL(); + // relative link option is private to PDF Export filter and limited to local filesystem only + aContext.RelFsys = mbExportRelativeFsysLinks; + // determine the default acton for PDF links + switch( mnDefaultLinkAction ) + { + default: + // default: URI, without fragment conversion (the bookmark in PDF may not work) + case 0: + aContext.DefaultLinkAction = vcl::PDFWriter::URIAction; + break; + case 1: + // view PDF through the reader application + aContext.ForcePDFAction = true; + aContext.DefaultLinkAction = vcl::PDFWriter::LaunchAction; + break; + case 2: + // view PDF through an Internet browser + aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination; + break; + } + aContext.ConvertOOoTargetToPDFTarget = mbConvertOOoTargetToPDFTarget; + + // check for Link Launch action, not allowed on PDF/A-1 + // this code chunk checks when the filter is called from scripting + if( aContext.Version == vcl::PDFWriter::PDFVersion::PDF_A_1 && + aContext.DefaultLinkAction == vcl::PDFWriter::LaunchAction ) + { + // force the similar allowed URI action + aContext.DefaultLinkAction = vcl::PDFWriter::URIActionDestination; + // and remove the remote goto action forced on PDF file + aContext.ForcePDFAction = false; + } + } + + aContext.SignPDF = mbSignPDF; + aContext.SignLocation = msSignLocation; + aContext.SignContact = msSignContact; + aContext.SignReason = msSignReason; + aContext.SignPassword = msSignPassword; + aContext.SignCertificate = maSignCertificate; + aContext.SignTSA = msSignTSA; + aContext.UseReferenceXObject = mbUseReferenceXObject; + + // all context data set, time to create the printing device + vcl::PDFWriter aPDFWriter( aContext, xEnc ); + OutputDevice* pOut = aPDFWriter.GetReferenceDevice(); + + DBG_ASSERT( pOut, "PDFExport::Export: no reference device" ); + xDevice->SetOutputDevice(pOut); + + if( mbAddStream ) + { + // export stream + // get mimetype + OUString aSrcMimetype = getMimetypeForDocument( mxContext, mxSrcDoc ); + aPDFWriter.AddStream( aSrcMimetype, + new PDFExportStreamDoc( mxSrcDoc, aPreparedPermissionPassword ) + ); + } + + if ( pOut ) + { + DBG_ASSERT( pOut->GetExtOutDevData() == nullptr, "PDFExport: ExtOutDevData already set!!!" ); + vcl::PDFExtOutDevData aPDFExtOutDevData( *pOut ); + pOut->SetExtOutDevData( &aPDFExtOutDevData ); + aPDFExtOutDevData.SetIsExportNotes( mbExportNotes ); + aPDFExtOutDevData.SetIsExportTaggedPDF( mbUseTaggedPDF ); + aPDFExtOutDevData.SetIsExportTransitionEffects( mbUseTransitionEffects ); + aPDFExtOutDevData.SetIsExportFormFields( mbExportFormFields ); + aPDFExtOutDevData.SetIsExportBookmarks( mbExportBookmarks ); + aPDFExtOutDevData.SetIsExportHiddenSlides( mbExportHiddenSlides ); + aPDFExtOutDevData.SetIsSinglePageSheets( mbSinglePageSheets ); + aPDFExtOutDevData.SetIsLosslessCompression( mbUseLosslessCompression ); + aPDFExtOutDevData.SetCompressionQuality( mnQuality ); + aPDFExtOutDevData.SetIsReduceImageResolution( mbReduceImageResolution ); + aPDFExtOutDevData.SetIsExportNamedDestinations( mbExportBmkToDest ); + + Sequence< PropertyValue > aRenderOptions{ + comphelper::makePropertyValue("RenderDevice", uno::Reference<awt::XDevice>(xDevice)), + comphelper::makePropertyValue("ExportNotesPages", false), + comphelper::makePropertyValue("IsFirstPage", true), + comphelper::makePropertyValue("IsLastPage", false), + comphelper::makePropertyValue("IsSkipEmptyPages", mbSkipEmptyPages), + comphelper::makePropertyValue("PageRange", aPageRange), + comphelper::makePropertyValue("ExportPlaceholders", mbExportPlaceholders), + comphelper::makePropertyValue("SinglePageSheets", mbSinglePageSheets) + }; + Any& rExportNotesValue = aRenderOptions.getArray()[ 1 ].Value; + + if( !aPageRange.isEmpty() || !aSelection.hasValue() ) + { + aSelection = Any(); + aSelection <<= mxSrcDoc; + } + bool bExportNotesPages = false; + bool bReChangeToNormalView = false; + static const OUStringLiteral sShowOnlineLayout( u"ShowOnlineLayout" ); + bool bReHideWhitespace = false; + static const OUStringLiteral sHideWhitespace(u"HideWhitespace"); + uno::Reference< beans::XPropertySet > xViewProperties; + + if ( aCreator == "Writer" ) + { + // #i92835: if Writer is in web layout mode this has to be switched to normal view and back to web view in the end + try + { + Reference< view::XViewSettingsSupplier > xVSettingsSupplier( xModel->getCurrentController(), uno::UNO_QUERY_THROW ); + xViewProperties = xVSettingsSupplier->getViewSettings(); + xViewProperties->getPropertyValue( sShowOnlineLayout ) >>= bReChangeToNormalView; + if( bReChangeToNormalView ) + { + xViewProperties->setPropertyValue( sShowOnlineLayout, uno::Any( false ) ); + } + + // Also, disable hide-whitespace during export. + xViewProperties->getPropertyValue(sHideWhitespace) >>= bReHideWhitespace; + if (bReHideWhitespace) + { + xViewProperties->setPropertyValue(sHideWhitespace, uno::Any(false)); + } + } + catch( const uno::Exception& ) + { + } + + } + + const sal_Int32 nPageCount = xRenderable->getRendererCount( aSelection, aRenderOptions ); + + if ( mbExportNotesPages && aCreator == "Impress" ) + { + uno::Reference< drawing::XShapes > xShapes; // do not allow to export notes when exporting a selection + if ( ! ( aSelection >>= xShapes ) ) + bExportNotesPages = true; + } + const bool bExportPages = !bExportNotesPages || !mbExportOnlyNotesPages; + + if( aPageRange.isEmpty() || mbSinglePageSheets) + { + aPageRange = OUString::number( 1 ) + "-" + OUString::number(nPageCount ); + } + StringRangeEnumerator aRangeEnum( aPageRange, 0, nPageCount-1 ); + + if ( mxStatusIndicator.is() ) + { + std::locale loc(Translate::Create("flt")); + sal_Int32 nTotalPageCount = aRangeEnum.size(); + if ( bExportPages && bExportNotesPages ) + nTotalPageCount *= 2; + mxStatusIndicator->start(Translate::get(PDF_PROGRESS_BAR, loc), nTotalPageCount); + } + + bRet = nPageCount > 0; + + if ( bRet && bExportPages ) + bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount ); + + if ( bRet && bExportNotesPages ) + { + rExportNotesValue <<= true; + bRet = ExportSelection( aPDFWriter, xRenderable, aSelection, aRangeEnum, aRenderOptions, nPageCount ); + } + if ( mxStatusIndicator.is() ) + mxStatusIndicator->end(); + + // if during the export the doc locale was set copy it to PDF writer + const css::lang::Locale& rLoc( aPDFExtOutDevData.GetDocumentLocale() ); + if( !rLoc.Language.isEmpty() ) + aPDFWriter.SetDocumentLocale( rLoc ); + + if( bRet ) + { + aPDFExtOutDevData.PlayGlobalActions( aPDFWriter ); + bRet = aPDFWriter.Emit(); + aErrors = aPDFWriter.GetErrors(); + } + pOut->SetExtOutDevData( nullptr ); + if( bReChangeToNormalView ) + { + try + { + xViewProperties->setPropertyValue( sShowOnlineLayout, uno::Any( true ) ); + } + catch( const uno::Exception& ) + { + } + } + if( bReHideWhitespace ) + { + try + { + xViewProperties->setPropertyValue( sHideWhitespace, uno::Any( true ) ); + } + catch( const uno::Exception& ) + { + } + } + } + } + } + + // show eventual errors during export + showErrors( aErrors ); + + return bRet; +} + + +namespace +{ + +typedef cppu::WeakComponentImplHelper< task::XInteractionRequest > PDFErrorRequestBase; + +class PDFErrorRequest : private cppu::BaseMutex, + public PDFErrorRequestBase +{ + task::PDFExportException maExc; +public: + explicit PDFErrorRequest( task::PDFExportException aExc ); + + // XInteractionRequest + virtual uno::Any SAL_CALL getRequest() override; + virtual uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL getContinuations() override; +}; + + +PDFErrorRequest::PDFErrorRequest( task::PDFExportException aExc ) : + PDFErrorRequestBase( m_aMutex ), + maExc(std::move( aExc )) +{ +} + + +uno::Any SAL_CALL PDFErrorRequest::getRequest() +{ + osl::MutexGuard const guard( m_aMutex ); + + uno::Any aRet; + aRet <<= maExc; + return aRet; +} + + +uno::Sequence< uno::Reference< task::XInteractionContinuation > > SAL_CALL PDFErrorRequest::getContinuations() +{ + return uno::Sequence< uno::Reference< task::XInteractionContinuation > >(); +} + +} // end anonymous namespace + + +void PDFExport::showErrors( const std::set< vcl::PDFWriter::ErrorCode >& rErrors ) +{ + if( ! rErrors.empty() && mxIH.is() ) + { + task::PDFExportException aExc; + aExc.ErrorCodes = comphelper::containerToSequence<sal_Int32>( rErrors ); + Reference< task::XInteractionRequest > xReq( new PDFErrorRequest( std::move(aExc) ) ); + mxIH->handle( xReq ); + } +} + + +void PDFExport::ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& rPDFExtOutDevData, const GDIMetaFile& rMtf ) +{ + //Rectangle(Point, Size) creates a rectangle off by 1, use Rectangle(long, long, long, long) instead + basegfx::B2DPolygon aSize(tools::Polygon(tools::Rectangle(0, 0, rMtf.GetPrefSize().Width(), rMtf.GetPrefSize().Height())).getB2DPolygon()); + basegfx::B2DPolygon aSizePDF(OutputDevice::LogicToLogic(aSize, rMtf.GetPrefMapMode(), MapMode(MapUnit::MapPoint))); + basegfx::B2DRange aRangePDF(aSizePDF.getB2DRange()); + tools::Rectangle aPageRect( Point(), rMtf.GetPrefSize() ); + + rWriter.NewPage( aRangePDF.getWidth(), aRangePDF.getHeight() ); + rWriter.SetMapMode( rMtf.GetPrefMapMode() ); + + vcl::PDFWriter::PlayMetafileContext aCtx; + GDIMetaFile aMtf; + if( mbRemoveTransparencies ) + { + aCtx.m_bTransparenciesWereRemoved = rWriter.GetReferenceDevice()-> + RemoveTransparenciesFromMetaFile( rMtf, aMtf, mnMaxImageResolution, mnMaxImageResolution, + false, true, mbReduceImageResolution ); + // tdf#134736 if the metafile was replaced then rPDFExtOutDevData's PageSyncData mActions + // all still point to MetaAction indexes in the original metafile that are now invalid. + // Throw them all away in the absence of a way to reposition them to new positions of + // their replacements. + if (aCtx.m_bTransparenciesWereRemoved) + rPDFExtOutDevData.ResetSyncData(); + } + else + { + aMtf = rMtf; + } + aCtx.m_nMaxImageResolution = mbReduceImageResolution ? mnMaxImageResolution : 0; + aCtx.m_bOnlyLosslessCompression = mbUseLosslessCompression; + aCtx.m_nJPEGQuality = mnQuality; + + + rWriter.SetClipRegion( basegfx::B2DPolyPolygon( + basegfx::utils::createPolygonFromRect( vcl::unotools::b2DRectangleFromRectangle(aPageRect) ) ) ); + + rWriter.PlayMetafile( aMtf, aCtx, &rPDFExtOutDevData ); + + rPDFExtOutDevData.ResetSyncData(); + + if (!msWatermark.isEmpty()) + { + ImplWriteWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) ); + } + else if (!msTiledWatermark.isEmpty()) + { + ImplWriteTiledWatermark( rWriter, Size(aRangePDF.getWidth(), aRangePDF.getHeight()) ); + } +} + + +void PDFExport::ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ) +{ + vcl::Font aFont( maWatermarkFontName, Size( 0, moWatermarkFontHeight ? *moWatermarkFontHeight : 3*rPageSize.Height()/4 ) ); + aFont.SetItalic( ITALIC_NONE ); + aFont.SetWidthType( WIDTH_NORMAL ); + aFont.SetWeight( WEIGHT_NORMAL ); + aFont.SetAlignment( ALIGN_BOTTOM ); + tools::Long nTextWidth = rPageSize.Width(); + if( rPageSize.Width() < rPageSize.Height() ) + { + nTextWidth = rPageSize.Height(); + aFont.SetOrientation( 2700_deg10 ); + } + + if (moWatermarkRotateAngle) + { + aFont.SetOrientation(*moWatermarkRotateAngle); + if (rPageSize.Width() < rPageSize.Height()) + { + // Set text width based on the shorter side, so rotation can't push text outside the + // page boundaries. + nTextWidth = rPageSize.Width(); + } + } + + // adjust font height for text to fit + OutputDevice* pDev = rWriter.GetReferenceDevice(); + pDev->Push(); + pDev->SetFont( aFont ); + pDev->SetMapMode( MapMode( MapUnit::MapPoint ) ); + int w = 0; + if (moWatermarkFontHeight) + { + w = pDev->GetTextWidth(msWatermark); + } + else + { + while( ( w = pDev->GetTextWidth( msWatermark ) ) > nTextWidth ) + { + if (w == 0) + break; + tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w; + if( nNewHeight == aFont.GetFontHeight() ) + { + nNewHeight--; + if( nNewHeight <= 0 ) + break; + } + aFont.SetFontHeight( nNewHeight ); + pDev->SetFont( aFont ); + } + } + tools::Long nTextHeight = pDev->GetTextHeight(); + // leave some maneuvering room for rounding issues, also + // some fonts go a little outside ascent/descent + nTextHeight += nTextHeight/20; + pDev->Pop(); + + rWriter.Push(); + rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); + rWriter.SetFont( aFont ); + rWriter.SetTextColor(maWatermarkColor); + Point aTextPoint; + tools::Rectangle aTextRect; + if( rPageSize.Width() > rPageSize.Height() ) + { + aTextPoint = Point( (rPageSize.Width()-w)/2, + rPageSize.Height()-(rPageSize.Height()-nTextHeight)/2 ); + aTextRect = tools::Rectangle( Point( (rPageSize.Width()-w)/2, + (rPageSize.Height()-nTextHeight)/2 ), + Size( w, nTextHeight ) ); + } + else + { + aTextPoint = Point( (rPageSize.Width()-nTextHeight)/2, + (rPageSize.Height()-w)/2 ); + aTextRect = tools::Rectangle( aTextPoint, Size( nTextHeight, w ) ); + } + + if (moWatermarkRotateAngle) + { + // First set the text's starting point to the center of the page. + tools::Rectangle aPageRectangle(Point(0, 0), rPageSize); + aTextPoint = aPageRectangle.Center(); + // Then adjust it so that the text remains centered, based on the rotation angle. + basegfx::B2DPolygon aTextPolygon + = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(0, -nTextHeight, w, 0)); + basegfx::B2DHomMatrix aMatrix; + aMatrix.rotate(-1 * toRadians(*moWatermarkRotateAngle)); + aTextPolygon.transform(aMatrix); + basegfx::B2DPoint aPolygonCenter = aTextPolygon.getB2DRange().getCenter(); + aTextPoint.AdjustX(-aPolygonCenter.getX()); + aTextPoint.AdjustY(-aPolygonCenter.getY()); + + aTextRect = aPageRectangle; + } + + rWriter.SetClipRegion(); + rWriter.BeginTransparencyGroup(); + rWriter.DrawText( aTextPoint, msWatermark ); + rWriter.EndTransparencyGroup( aTextRect, 50 ); + rWriter.Pop(); +} + +void PDFExport::ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ) +{ + OUString watermark = msTiledWatermark; + // Maximum number of characters in one line. + // it is set to 21 to make it look like tiled watermarks as online in secure view + const int lineLength = 21; + vcl::Font aFont( "Liberation Sans", Size( 0, 40 ) ); + aFont.SetItalic( ITALIC_NONE ); + aFont.SetWidthType( WIDTH_NORMAL ); + aFont.SetWeight( WEIGHT_NORMAL ); + aFont.SetAlignment( ALIGN_BOTTOM ); + aFont.SetFontHeight(40); + aFont.SetOrientation(450_deg10); + + OutputDevice* pDev = rWriter.GetReferenceDevice(); + pDev->SetFont(aFont); + pDev->Push(); + pDev->SetFont(aFont); + pDev->SetMapMode( MapMode( MapUnit::MapPoint ) ); + int w = 0; + int watermarkcount = ((rPageSize.Width()) / 200)+1; + tools::Long nTextWidth = rPageSize.Width() / (watermarkcount*1.5); + OUString oneLineText = watermark; + + if(watermark.getLength() > lineLength) + oneLineText = watermark.copy(0, lineLength); + + while((w = pDev->GetTextWidth(oneLineText)) > nTextWidth) + { + if(w==0) + break; + + tools::Long nNewHeight = aFont.GetFontHeight() * nTextWidth / w; + aFont.SetFontHeight(nNewHeight); + pDev->SetFont( aFont ); + } + // maximum number of watermark count for the width + if(watermarkcount > 8) + watermarkcount = 8; + + pDev->Pop(); + + rWriter.Push(); + rWriter.SetMapMode( MapMode( MapUnit::MapPoint ) ); + rWriter.SetFont(aFont); + rWriter.SetTextColor( Color(19,20,22) ); + // center watermarks horizontally + Point aTextPoint( (rPageSize.Width()/2) - (((nTextWidth*watermarkcount)+(watermarkcount-1)*nTextWidth)/2), + pDev->GetTextHeight()); + + for( int i = 0; i < watermarkcount; i ++) + { + while(aTextPoint.getY()+pDev->GetTextHeight()*3 <= rPageSize.Height()) + { + tools::Rectangle aTextRect(aTextPoint, Size(nTextWidth*2,pDev->GetTextHeight()*4)); + + pDev->Push(); + rWriter.SetClipRegion(); + rWriter.BeginTransparencyGroup(); + rWriter.SetTextColor( Color(19,20,22) ); + rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom); + rWriter.EndTransparencyGroup( aTextRect, 50 ); + pDev->Pop(); + + pDev->Push(); + rWriter.SetClipRegion(); + rWriter.BeginTransparencyGroup(); + rWriter.SetTextColor( Color(236,235,233) ); + rWriter.DrawText(aTextRect, watermark, DrawTextFlags::MultiLine|DrawTextFlags::Center|DrawTextFlags::VCenter|DrawTextFlags::WordBreak|DrawTextFlags::Bottom); + rWriter.EndTransparencyGroup( aTextRect, 50 ); + pDev->Pop(); + + aTextPoint.Move(0, pDev->GetTextHeight()*3); + } + aTextPoint=Point( aTextPoint.getX(), pDev->GetTextHeight() ); + aTextPoint.Move( nTextWidth*1.5, 0 ); + } + + rWriter.Pop(); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfexport.hxx b/filter/source/pdf/pdfexport.hxx new file mode 100644 index 000000000..dfd371c31 --- /dev/null +++ b/filter/source/pdf/pdfexport.hxx @@ -0,0 +1,145 @@ +/* -*- 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 . + */ + +#pragma once + +#include <tools/multisel.hxx> +#include <vcl/pdfwriter.hxx> +#include <vcl/pdfextoutdevdata.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <com/sun/star/task/XInteractionHandler.hpp> +#include <com/sun/star/task/XStatusIndicator.hpp> +#include <com/sun/star/uno/Reference.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> +#include <com/sun/star/view/XRenderable.hpp> + +class GDIMetaFile; +class Size; + +namespace vcl { class PDFWriter; } + +class PDFExport +{ +private: + + css::uno::Reference< css::lang::XComponent > mxSrcDoc; + css::uno::Reference< css::uno::XComponentContext > mxContext; + css::uno::Reference< css::task::XStatusIndicator > mxStatusIndicator; + css::uno::Reference< css::task::XInteractionHandler > mxIH; + + bool mbUseTaggedPDF; + sal_Int32 mnPDFTypeSelection; + bool mbPDFUACompliance; + bool mbExportNotes; + bool mbExportPlaceholders; + bool mbUseReferenceXObject; + bool mbExportNotesPages; + bool mbExportOnlyNotesPages; + bool mbUseTransitionEffects; + bool mbExportBookmarks; + bool mbExportHiddenSlides; + bool mbSinglePageSheets; + sal_Int32 mnOpenBookmarkLevels; + + bool mbUseLosslessCompression; + bool mbReduceImageResolution; + bool mbSkipEmptyPages; + bool mbAddStream; + sal_Int32 mnMaxImageResolution; + sal_Int32 mnQuality; + sal_Int32 mnFormsFormat; + bool mbExportFormFields; + bool mbAllowDuplicateFieldNames; + sal_Int32 mnProgressValue; + bool mbRemoveTransparencies; + + bool mbIsRedactMode; + + OUString msWatermark; + Color maWatermarkColor; + std::optional<sal_Int32> moWatermarkFontHeight; + OUString maWatermarkFontName; + std::optional<Degree10> moWatermarkRotateAngle; + OUString msTiledWatermark; + + // these variable are here only to have a location in filter/pdf to set the default + // to be used by the macro (when the FilterData are set by the macro itself) + bool mbHideViewerToolbar; + bool mbHideViewerMenubar; + bool mbHideViewerWindowControls; + bool mbFitWindow; + bool mbCenterWindow; + bool mbOpenInFullScreenMode; + bool mbDisplayPDFDocumentTitle; + sal_Int32 mnPDFDocumentMode; + sal_Int32 mnPDFDocumentAction; + sal_Int32 mnZoom; + sal_Int32 mnInitialPage; + sal_Int32 mnPDFPageLayout; + + bool mbEncrypt; + bool mbRestrictPermissions; + sal_Int32 mnPrintAllowed; + sal_Int32 mnChangesAllowed; + bool mbCanCopyOrExtract; + bool mbCanExtractForAccessibility; + + // #i56629 + bool mbExportRelativeFsysLinks; + sal_Int32 mnDefaultLinkAction; + bool mbConvertOOoTargetToPDFTarget; + bool mbExportBmkToDest; + void ImplExportPage( vcl::PDFWriter& rWriter, vcl::PDFExtOutDevData& rPDFExtOutDevData, + const GDIMetaFile& rMtf ); + + bool mbSignPDF; + OUString msSignLocation; + OUString msSignContact; + OUString msSignReason; + OUString msSignPassword; + css::uno::Reference< css::security::XCertificate > maSignCertificate; + OUString msSignTSA; + + void ImplWriteWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ); + void ImplWriteTiledWatermark( vcl::PDFWriter& rWriter, const Size& rPageSize ); + css::uno::Reference<css::security::XCertificate> GetCertificateFromSubjectName(const std::u16string_view& rSubjectName) const; + + +public: + + PDFExport( const css::uno::Reference< css::lang::XComponent >& rxSrcDoc, + const css::uno::Reference< css::task::XStatusIndicator >& xStatusIndicator, + const css::uno::Reference< css::task::XInteractionHandler >& xIH, + const css::uno::Reference< css::uno::XComponentContext >& xFact ); + ~PDFExport(); + + bool ExportSelection( vcl::PDFWriter& rPDFWriter, + css::uno::Reference< css::view::XRenderable > const & rRenderable, + const css::uno::Any& rSelection, + const StringRangeEnumerator& rRangeEnum, + css::uno::Sequence< css::beans::PropertyValue >& rRenderOptions, + sal_Int32 nPageCount ); + + bool Export( const OUString& rFile, const css::uno::Sequence< css::beans::PropertyValue >& rFilterData ); + + void showErrors( const std::set<vcl::PDFWriter::ErrorCode>& ); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdffilter.component b/filter/source/pdf/pdffilter.component new file mode 100644 index 000000000..5f3dc7879 --- /dev/null +++ b/filter/source/pdf/pdffilter.component @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.PDF.PDFDialog" + constructor="filter_PDFDialog_get_implementation"> + <service name="com.sun.star.document.PDFDialog"/> + </implementation> + <implementation name="com.sun.star.comp.PDF.PDFFilter" + constructor="filter_PDFFilter_get_implementation"> + <service name="com.sun.star.document.PDFFilter"/> + </implementation> + <implementation name="com.sun.star.comp.PDF.PDFExportInteractionHandler" + constructor="filter_PDFExportInteractionHandler_get_implementation"> + <service name="com.sun.star.filter.pdfexport.PDFExportInteractionHandler"/> + </implementation> + <implementation name="com.sun.star.comp.PDF.PDFDecomposer" + constructor="filter_PdfDecomposer_get_implementation"> + <service name="com.sun.star.graphic.PdfTools"/> + </implementation> +</component> diff --git a/filter/source/pdf/pdffilter.cxx b/filter/source/pdf/pdffilter.cxx new file mode 100644 index 000000000..746a1dd9b --- /dev/null +++ b/filter/source/pdf/pdffilter.cxx @@ -0,0 +1,295 @@ +/* -*- 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 "pdffilter.hxx" +#include "pdfexport.hxx" +#include <cppuhelper/supportsservice.hxx> +#include <vcl/svapp.hxx> +#include <vcl/window.hxx> +#include <svl/outstrm.hxx> +#include <unotools/ucbstreamhelper.hxx> +#include <unotools/tempfile.hxx> +#include <vcl/FilterConfigItem.hxx> +#include <memory> + +#include <com/sun/star/io/XOutputStream.hpp> + +#include <comphelper/propertysequence.hxx> +#include <comphelper/sequence.hxx> + +#include <boost/property_tree/json_parser/error.hpp> + +using namespace ::com::sun::star::io; + +PDFFilter::PDFFilter( const Reference< XComponentContext > &rxContext ) : + mxContext( rxContext ) +{ +} + + +PDFFilter::~PDFFilter() +{ +} + + +bool PDFFilter::implExport( const Sequence< PropertyValue >& rDescriptor ) +{ + Reference< XOutputStream > xOStm; + Sequence< PropertyValue > aFilterData; + OUString aFilterOptions; + sal_Int32 nLength = rDescriptor.getLength(); + const PropertyValue* pValue = rDescriptor.getConstArray(); + bool bIsRedactMode = false; + bool bRet = false; + Reference< task::XStatusIndicator > xStatusIndicator; + Reference< task::XInteractionHandler > xIH; + + for (sal_Int32 i = 0; i < nLength; ++i) + { + if ( pValue[ i ].Name == "OutputStream" ) + pValue[ i ].Value >>= xOStm; + else if ( pValue[ i ].Name == "FilterData" ) + pValue[ i ].Value >>= aFilterData; + else if ( pValue[ i ].Name == "FilterOptions" ) + pValue[ i ].Value >>= aFilterOptions; + else if ( pValue[ i ].Name == "StatusIndicator" ) + pValue[ i ].Value >>= xStatusIndicator; + else if ( pValue[i].Name == "InteractionHandler" ) + pValue[i].Value >>= xIH; + } + + for (sal_Int32 i = 0 ; i < nLength; ++i) + { + if ( pValue[i].Name == "IsRedactMode") + pValue[i].Value >>= bIsRedactMode; + } + + if (!aFilterData.hasElements() && aFilterOptions.startsWith("{")) + { + try + { + // Allow setting filter data keys from the cmdline. + std::vector<PropertyValue> aData + = comphelper::JsonToPropertyValues(aFilterOptions.toUtf8()); + aFilterData = comphelper::containerToSequence(aData); + } + catch (const boost::property_tree::json_parser::json_parser_error& e) + { + // This wasn't a valid json; maybe came from import filter (tdf#150846) + SAL_WARN("filter.pdf", "error parsing FilterOptions: " << e.message()); + } + } + + /* we don't get FilterData if we are exporting directly + to pdf, but we have to use the last user settings (especially for the CompressMode) */ + if ( !aFilterData.hasElements() ) + { + FilterConfigItem aCfgItem( u"Office.Common/Filter/PDF/Export/" ); + aCfgItem.ReadBool( "UseLosslessCompression", false ); + aCfgItem.ReadInt32( "Quality", 90 ); + aCfgItem.ReadBool( "ReduceImageResolution", false ); + aCfgItem.ReadInt32( "MaxImageResolution", 300 ); + aCfgItem.ReadBool( "UseTaggedPDF", false ); + aCfgItem.ReadInt32( "SelectPdfVersion", 0 ); + aCfgItem.ReadBool("PDFUACompliance", false); + aCfgItem.ReadBool( "ExportNotes", false ); + aCfgItem.ReadBool( "ExportPlaceholders", false ); + aCfgItem.ReadBool( "ExportNotesPages", false ); + aCfgItem.ReadBool( "ExportOnlyNotesPages", false ); + aCfgItem.ReadBool( "UseTransitionEffects", true ); + aCfgItem.ReadBool( "IsSkipEmptyPages", false ); + aCfgItem.ReadBool( "ExportFormFields", true ); + aCfgItem.ReadInt32( "FormsType", 0 ); + aCfgItem.ReadBool( "HideViewerToolbar", false ); + aCfgItem.ReadBool( "HideViewerMenubar", false ); + aCfgItem.ReadBool( "HideViewerWindowControls", false ); + aCfgItem.ReadBool( "ResizeWindowToInitialPage", false ); + aCfgItem.ReadBool( "CenterWindow", false ); + aCfgItem.ReadBool( "OpenInFullScreenMode", false ); + aCfgItem.ReadBool( "DisplayPDFDocumentTitle", true ); + aCfgItem.ReadInt32( "InitialView", 0 ); + aCfgItem.ReadInt32( "Magnification", 0 ); + aCfgItem.ReadInt32( "Zoom", 100 ); + aCfgItem.ReadInt32( "PageLayout", 0 ); + aCfgItem.ReadBool( "FirstPageOnLeft", false ); + aCfgItem.ReadInt32( "InitialPage", 1 ); + aCfgItem.ReadBool( "IsAddStream", false ); + + // the encryption is not available when exporting directly, since the encryption is off by default and the selection + // (encrypt or not) is not persistent; it's available through macro though, + // provided the correct property values are set, see help + + // now, the relative link stuff + aCfgItem.ReadBool( "ExportLinksRelativeFsys", false ); + aCfgItem.ReadInt32("PDFViewSelection", 0 ); + aCfgItem.ReadBool( "ConvertOOoTargetToPDFTarget", false ); + aCfgItem.ReadBool( "ExportBookmarksToPDFDestination", false ); + + aCfgItem.ReadBool( "ExportBookmarks", true ); + aCfgItem.ReadBool( "ExportHiddenSlides", false ); + aCfgItem.ReadBool( "SinglePageSheets", false ); + aCfgItem.ReadInt32( "OpenBookmarkLevels", -1 ); + + aCfgItem.ReadBool( "IsRedactMode", false); + + aFilterData = aCfgItem.GetFilterData(); + } + + + if (bIsRedactMode) + { + bool bFound = false; + + for (PropertyValue& rProp : asNonConstRange(aFilterData)) + { + if (rProp.Name == "IsRedactMode") + { + rProp.Value <<= bIsRedactMode; + bFound = true; + break; + } + } + + if (!bFound) + { + sal_Int32 nNewSize = aFilterData.getLength() + 1; + aFilterData.realloc( nNewSize ); + auto pFilterData = aFilterData.getArray(); + pFilterData[nNewSize - 1].Name = "IsRedactMode"; + pFilterData[nNewSize - 1].Value <<= bIsRedactMode; + } + } + + if( mxSrcDoc.is() && xOStm.is() ) + { + PDFExport aExport( mxSrcDoc, xStatusIndicator, xIH, mxContext ); + ::utl::TempFile aTempFile; + + aTempFile.EnableKillingFile(); + bRet = aExport.Export( aTempFile.GetURL(), aFilterData ); + + if( bRet ) + { + std::unique_ptr<SvStream> pIStm(::utl::UcbStreamHelper::CreateStream( aTempFile.GetURL(), StreamMode::READ )); + + if( pIStm ) + { + SvOutputStream aOStm( xOStm ); + + aOStm.WriteStream( *pIStm ); + bRet = ( aOStm.Tell() && ( aOStm.GetError() == ERRCODE_NONE ) ); + } + } + } + + return bRet; +} + +namespace { + +class FocusWindowWaitCursor +{ +private: + + VclPtr<vcl::Window> m_pFocusWindow; + +public: + FocusWindowWaitCursor() : + m_pFocusWindow( Application::GetFocusWindow() ) + { + if( m_pFocusWindow ) + { + m_pFocusWindow->AddEventListener( LINK( this, FocusWindowWaitCursor, DestroyedLink ) ); + m_pFocusWindow->EnterWait(); + } + } + + ~FocusWindowWaitCursor() + { + if( m_pFocusWindow ) + { + m_pFocusWindow->LeaveWait(); + m_pFocusWindow->RemoveEventListener( LINK( this, FocusWindowWaitCursor, DestroyedLink ) ); + } + } + + DECL_LINK( DestroyedLink, VclWindowEvent&, void ); +}; + +} + +IMPL_LINK( FocusWindowWaitCursor, DestroyedLink, VclWindowEvent&, rEvent, void ) +{ + if( rEvent.GetId() == VclEventId::ObjectDying ) + m_pFocusWindow = nullptr; +} + + +sal_Bool SAL_CALL PDFFilter::filter( const Sequence< PropertyValue >& rDescriptor ) +{ + FocusWindowWaitCursor aCur; + + const bool bRet = implExport( rDescriptor ); + + return bRet; +} + + +void SAL_CALL PDFFilter::cancel( ) +{ +} + + +void SAL_CALL PDFFilter::setSourceDocument( const Reference< XComponent >& xDoc ) +{ + mxSrcDoc = xDoc; +} + + +void SAL_CALL PDFFilter::initialize( const css::uno::Sequence< css::uno::Any >& ) +{ +} + + +OUString SAL_CALL PDFFilter::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFFilter"; +} + + +sal_Bool SAL_CALL PDFFilter::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService( this, rServiceName ); +} + + +css::uno::Sequence< OUString > SAL_CALL PDFFilter::getSupportedServiceNames( ) +{ + return { "com.sun.star.document.PDFFilter" }; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PDFFilter_get_implementation( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new PDFFilter(context)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdffilter.hxx b/filter/source/pdf/pdffilter.hxx new file mode 100644 index 000000000..28869272c --- /dev/null +++ b/filter/source/pdf/pdffilter.hxx @@ -0,0 +1,70 @@ +/* -*- 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 . + */ + +#pragma once + +#include <com/sun/star/document/XFilter.hpp> +#include <com/sun/star/document/XExporter.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XComponent.hpp> +#include <cppuhelper/implbase.hxx> +#include <com/sun/star/uno/XComponentContext.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::document; + + +class PDFFilter : public cppu::WeakImplHelper < XFilter, XExporter, XInitialization, XServiceInfo > +{ +private: + + Reference< XComponentContext > mxContext; + Reference< XComponent > mxSrcDoc; + + bool implExport( const Sequence< PropertyValue >& rDescriptor ); + +protected: + + // XFilter + virtual sal_Bool SAL_CALL filter( const Sequence< PropertyValue >& rDescriptor ) override; + virtual void SAL_CALL cancel( ) override; + + // XExporter + virtual void SAL_CALL setSourceDocument( const Reference< XComponent >& xDoc ) override; + + // XInitialization + virtual void SAL_CALL initialize( const Sequence< Any >& aArguments ) override; + + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + +public: + + explicit PDFFilter( const Reference< XComponentContext >& rxContext ); + virtual ~PDFFilter() override; +}; + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfinteract.cxx b/filter/source/pdf/pdfinteract.cxx new file mode 100644 index 000000000..cf38cf4a0 --- /dev/null +++ b/filter/source/pdf/pdfinteract.cxx @@ -0,0 +1,97 @@ +/* -*- 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 "pdfinteract.hxx" +#include "impdialog.hxx" + +#include <com/sun/star/task/XInteractionRequest.hpp> +#include <com/sun/star/task/PDFExportException.hpp> +#include <comphelper/namedvaluecollection.hxx> +#include <cppuhelper/supportsservice.hxx> +#include <vcl/svapp.hxx> + +PDFInteractionHandler::PDFInteractionHandler() +{ +} + +PDFInteractionHandler::~PDFInteractionHandler() +{ +} + +void SAL_CALL PDFInteractionHandler::handle( const Reference< task::XInteractionRequest >& i_xRequest ) +{ + handleInteractionRequest( i_xRequest ); +} + +void SAL_CALL PDFInteractionHandler::initialize(const css::uno::Sequence<css::uno::Any>& rArguments) +{ + comphelper::NamedValueCollection aProperties(rArguments); + if (aProperties.has("Parent")) + aProperties.get("Parent") >>= m_xParent; +} + +sal_Bool SAL_CALL PDFInteractionHandler::handleInteractionRequest( const Reference< task::XInteractionRequest >& i_xRequest ) +{ + bool bHandled = false; + + Any aRequest( i_xRequest->getRequest() ); + task::PDFExportException aExc; + if( aRequest >>= aExc ) + { + std::set< vcl::PDFWriter::ErrorCode > aCodes; + sal_Int32 nCodes = aExc.ErrorCodes.getLength(); + for( sal_Int32 i = 0; i < nCodes; i++ ) + aCodes.insert( static_cast<vcl::PDFWriter::ErrorCode>(aExc.ErrorCodes.getConstArray()[i]) ); + + ImplErrorDialog aDlg(Application::GetFrameWeld(m_xParent), aCodes); + aDlg.run(); + bHandled = true; + } + return bHandled; +} + + + +OUString SAL_CALL PDFInteractionHandler::getImplementationName() +{ + return "com.sun.star.comp.PDF.PDFExportInteractionHandler"; +} + + +sal_Bool SAL_CALL PDFInteractionHandler::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService( this, rServiceName ); +} + + +css::uno::Sequence< OUString > SAL_CALL PDFInteractionHandler::getSupportedServiceNames( ) +{ + return { "com.sun.star.filter.pdfexport.PDFExportInteractionHandler" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +filter_PDFExportInteractionHandler_get_implementation( + css::uno::XComponentContext* , css::uno::Sequence<css::uno::Any> const&) +{ + return cppu::acquire(new PDFInteractionHandler()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/filter/source/pdf/pdfinteract.hxx b/filter/source/pdf/pdfinteract.hxx new file mode 100644 index 000000000..0af5c260b --- /dev/null +++ b/filter/source/pdf/pdfinteract.hxx @@ -0,0 +1,61 @@ +/* -*- 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 . + */ + +#pragma once + +#include <cppuhelper/implbase.hxx> + +#include <com/sun/star/awt/XWindow.hpp> +#include <com/sun/star/lang/XInitialization.hpp> +#include <com/sun/star/task/XInteractionHandler2.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::lang; + + +class PDFInteractionHandler : public cppu::WeakImplHelper<css::lang::XInitialization, + css::task::XInteractionHandler2, + XServiceInfo> +{ +private: + css::uno::Reference<css::awt::XWindow> m_xParent; +protected: + // XServiceInfo + virtual OUString SAL_CALL getImplementationName() override; + virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override; + virtual Sequence< OUString > SAL_CALL getSupportedServiceNames() override; + + // XInitialization + virtual void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override; + + // XInteractionHandler + virtual void SAL_CALL handle( const Reference< task::XInteractionRequest >& ) override; + + // XInteractionHandler2 + virtual sal_Bool SAL_CALL handleInteractionRequest( const Reference< task::XInteractionRequest >& ) override; + +public: + + PDFInteractionHandler(); + virtual ~PDFInteractionHandler() override; +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |