/* -*- 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/. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace css::lang; using namespace ::com::sun::star; using namespace ::com::sun::star::uno; class ScPDFExportTest : public test::BootstrapFixture, public unotest::MacrosTest { Reference mxComponent; Reference xTargetFrame; public: ScPDFExportTest() {} virtual void setUp() override final; virtual void tearDown() override final; // helpers private: std::shared_ptr exportToPDF(const uno::Reference& xModel, const ScRange& range); static bool hasTextInPdf(const std::shared_ptr& pPDFFile, const char* sText, bool& bFound); void setFont(ScFieldEditEngine& rEE, sal_Int32 nStart, sal_Int32 nEnd, const OUString& rFontName); // unit tests public: void testExportRange_Tdf120161(); void testExportFitToPage_Tdf103516(); CPPUNIT_TEST_SUITE(ScPDFExportTest); CPPUNIT_TEST(testExportRange_Tdf120161); CPPUNIT_TEST(testExportFitToPage_Tdf103516); CPPUNIT_TEST_SUITE_END(); }; void ScPDFExportTest::setUp() { test::BootstrapFixture::setUp(); mxDesktop.set( css::frame::Desktop::create(comphelper::getComponentContext(getMultiServiceFactory()))); { uno::Reference xDesktop = mxDesktop; CPPUNIT_ASSERT(xDesktop.is()); // Create spreadsheet uno::Sequence args(1); args[0].Name = "Hidden"; args[0].Value <<= true; mxComponent = xDesktop->loadComponentFromURL("private:factory/scalc", "_blank", 0, args); CPPUNIT_ASSERT(mxComponent.is()); // create a frame xTargetFrame = xDesktop->findFrame("_blank", 0); CPPUNIT_ASSERT(xTargetFrame.is()); uno::Reference xModel(mxComponent, uno::UNO_QUERY); uno::Reference xModel2(xModel, UNO_QUERY); CPPUNIT_ASSERT(xModel2.is()); Reference xController = xModel2->createDefaultViewController(xTargetFrame); CPPUNIT_ASSERT(xController.is()); // introduce model/view/controller to each other xController->attachModel(xModel2.get()); xModel2->connectController(xController.get()); xTargetFrame->setComponent(xController->getComponentWindow(), xController.get()); xController->attachFrame(xTargetFrame); xModel2->setCurrentController(xController.get()); } } void ScPDFExportTest::tearDown() { if (mxComponent.is()) mxComponent->dispose(); test::BootstrapFixture::tearDown(); } bool ScPDFExportTest::hasTextInPdf(const std::shared_ptr& pPDFFile, const char* sText, bool& bFound) { SvStream* pStream = pPDFFile->GetStream(StreamMode::STD_READ); CPPUNIT_ASSERT(pStream); // get file size pStream->Seek(STREAM_SEEK_TO_END); const std::size_t nFileSize = pStream->Tell(); if (nFileSize == 0) return false; // read file content char* pBuffer = new char[nFileSize]; pStream->Seek(STREAM_SEEK_TO_BEGIN); const std::size_t nRead = pStream->ReadBytes(pBuffer, nFileSize); if (nRead == nFileSize) { const std::string haystack(pBuffer, pBuffer + nFileSize); const std::string needle(sText); const std::size_t n = haystack.find(needle); bFound = (n != std::string::npos); } delete[] pBuffer; // close and return the status pStream = nullptr; pPDFFile->CloseStream(); return (nRead == nFileSize); } std::shared_ptr ScPDFExportTest::exportToPDF(const uno::Reference& xModel, const ScRange& range) { // create temp file name auto pTempFile = std::make_shared(); pTempFile->EnableKillingFile(); OUString sFileURL = pTempFile->GetURL(); // Note: under Windows path path should be with "/" delimiters instead of "\\" // due to usage of INetURLObject() that converts "\\" to hexadecimal notation. ::osl::FileBase::getFileURLFromSystemPath(sFileURL, sFileURL); // get XSpreadsheet uno::Reference xDoc(xModel, uno::UNO_QUERY_THROW); uno::Reference xSheets(xDoc->getSheets(), UNO_SET_THROW); uno::Reference xIndex(xSheets, uno::UNO_QUERY_THROW); uno::Reference rSheet(xIndex->getByIndex(0), UNO_QUERY_THROW); // select requested cells to print // query for the XCellRange interface uno::Reference xCellRange = rSheet->getCellRangeByPosition( range.aStart.Col(), range.aStart.Row(), range.aEnd.Col(), range.aEnd.Row()); { uno::Reference xController = xModel->getCurrentController(); CPPUNIT_ASSERT(xController.is()); uno::Reference xSelection(xController, uno::UNO_QUERY_THROW); CPPUNIT_ASSERT(xSelection.is()); uno::Any rCellRangeAny(xCellRange); xSelection->select(rCellRangeAny); } // init special pdf export params css::uno::Sequence aFilterData(3); aFilterData[0].Name = "Selection"; aFilterData[0].Value <<= xCellRange; aFilterData[1].Name = "Printing"; aFilterData[1].Value <<= sal_Int32(2); aFilterData[2].Name = "ViewPDFAfterExport"; aFilterData[2].Value <<= true; // init set of params for storeToURL() call css::uno::Sequence seqArguments(3); seqArguments[0].Name = "FilterData"; seqArguments[0].Value <<= aFilterData; seqArguments[1].Name = "FilterName"; seqArguments[1].Value <<= OUString("calc_pdf_Export"); seqArguments[2].Name = "URL"; seqArguments[2].Value <<= sFileURL; // call storeToURL() uno::Reference xComponent(mxComponent, UNO_SET_THROW); uno::Reference xStorable(xComponent, UNO_QUERY); xStorable->storeToURL(sFileURL, seqArguments); // return file object with generated PDF return pTempFile; } void ScPDFExportTest::setFont(ScFieldEditEngine& rEE, sal_Int32 nStart, sal_Int32 nEnd, const OUString& rFontName) { ESelection aSel; aSel.nStartPara = aSel.nEndPara = 0; aSel.nStartPos = nStart; aSel.nEndPos = nEnd; SfxItemSet aItemSet = rEE.GetEmptyItemSet(); SvxFontItem aItem(FAMILY_MODERN, rFontName, "", PITCH_VARIABLE, RTL_TEXTENCODING_UTF8, EE_CHAR_FONTINFO); aItemSet.Put(aItem); rEE.QuickSetAttribs(aItemSet, aSel); } // Selection was not taken into account during export into PDF void ScPDFExportTest::testExportRange_Tdf120161() { // create test document uno::Reference xModel(mxComponent, uno::UNO_QUERY); uno::Reference xDoc(xModel, uno::UNO_QUERY_THROW); uno::Reference xSheets(xDoc->getSheets(), UNO_SET_THROW); uno::Reference xIndex(xSheets, uno::UNO_QUERY_THROW); xSheets->insertNewByName("First Sheet", 0); uno::Reference rSheet(xIndex->getByIndex(0), UNO_QUERY_THROW); // 2. Setup data { SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(mxComponent); CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell); ScDocShellRef xDocSh = dynamic_cast(pFoundShell); CPPUNIT_ASSERT(xDocSh.get() != nullptr); // put some content into the first row with default font ScDocument& rDoc = xDocSh->GetDocument(); for (unsigned int r = 0; r < 1; ++r) for (unsigned int c = 0; c < 14; ++c) rDoc.SetValue(ScAddress(c, r, 0), (r + 1) * (c + 1)); // set "Text" to H1 cell with "DejaVuSans" font ScFieldEditEngine& rEE = rDoc.GetEditEngine(); rEE.Clear(); rEE.SetTextCurrentDefaults("Text"); setFont(rEE, 0, 4, "DejaVuSans"); // set font for first 4 chars rDoc.SetEditText(ScAddress(7, 0, 0), rEE.CreateTextObject()); } // A1:G1 { ScRange range1(0, 0, 0, 6, 0, 0); std::shared_ptr pPDFFile = exportToPDF(xModel, range1); bool bFound = false; CPPUNIT_ASSERT(hasTextInPdf(pPDFFile, "DejaVuSans", bFound)); CPPUNIT_ASSERT_EQUAL(false, bFound); } // G1:H1 { ScRange range1(6, 0, 0, 7, 0, 0); std::shared_ptr pPDFFile = exportToPDF(xModel, range1); bool bFound = false; CPPUNIT_ASSERT(hasTextInPdf(pPDFFile, "DejaVuSans", bFound)); CPPUNIT_ASSERT_EQUAL(true, bFound); } // H1:I1 { ScRange range1(7, 0, 0, 8, 0, 0); std::shared_ptr pPDFFile = exportToPDF(xModel, range1); bool bFound = false; CPPUNIT_ASSERT(hasTextInPdf(pPDFFile, "DejaVuSans", bFound)); CPPUNIT_ASSERT_EQUAL(true, bFound); } } void ScPDFExportTest::testExportFitToPage_Tdf103516() { // create test document uno::Reference xModel(mxComponent, uno::UNO_QUERY); uno::Reference xDoc(xModel, uno::UNO_QUERY_THROW); uno::Reference xSheets(xDoc->getSheets(), UNO_SET_THROW); uno::Reference xIndex(xSheets, uno::UNO_QUERY_THROW); xSheets->insertNewByName("First Sheet", 0); uno::Reference rSheet(xIndex->getByIndex(0), UNO_QUERY_THROW); // 2. Setup data { SfxObjectShell* pFoundShell = SfxObjectShell::GetShellFromComponent(mxComponent); CPPUNIT_ASSERT_MESSAGE("Failed to access document shell", pFoundShell); ScDocShellRef xDocSh = dynamic_cast(pFoundShell); CPPUNIT_ASSERT(xDocSh.get() != nullptr); // put some content into the table ScDocument& rDoc = xDocSh->GetDocument(); for (unsigned int r = 0; r < 80; ++r) for (unsigned int c = 0; c < 12; ++c) rDoc.SetValue(ScAddress(c, r, 0), (r + 1) * (c + 1)); } // A1:G50: 2-page export { ScRange range1(0, 0, 0, 6, 49, 0); std::shared_ptr pPDFFile = exportToPDF(xModel, range1); bool bFound = false; CPPUNIT_ASSERT(hasTextInPdf(pPDFFile, "/Count 2>>", bFound)); CPPUNIT_ASSERT_EQUAL(true, bFound); } // A1:L80: 4-page export { ScRange range1(0, 0, 0, 11, 79, 0); std::shared_ptr pPDFFile = exportToPDF(xModel, range1); bool bFound = false; CPPUNIT_ASSERT(hasTextInPdf(pPDFFile, "/Count 4>>", bFound)); CPPUNIT_ASSERT_EQUAL(true, bFound); } // set fit to page: width=1 page, height=0 (automatic) uno::Reference xStyleFamSupp(xDoc, UNO_QUERY_THROW); uno::Reference xStyleFamiliesNames(xStyleFamSupp->getStyleFamilies(), UNO_SET_THROW); uno::Reference xPageStyles(xStyleFamiliesNames->getByName("PageStyles"), UNO_QUERY_THROW); uno::Any aDefaultStyle = xPageStyles->getByName("Default"); uno::Reference xProp(aDefaultStyle, UNO_QUERY_THROW); uno::Any aScaleX, aScaleY; sal_Int16 nScale; aScaleX <<= static_cast(1); xProp->setPropertyValue("ScaleToPagesX", aScaleX); aScaleX = xProp->getPropertyValue("ScaleToPagesX"); aScaleX >>= nScale; CPPUNIT_ASSERT_EQUAL(sal_Int16(1), nScale); aScaleY = xProp->getPropertyValue("ScaleToPagesY"); aScaleY >>= nScale; CPPUNIT_ASSERT_EQUAL(sal_Int16(0), nScale); // A1:G50 with fit to page width=1: slightly smaller zoom results only 1-page export { ScRange range1(0, 0, 0, 6, 49, 0); std::shared_ptr pPDFFile = exportToPDF(xModel, range1); bool bFound = false; CPPUNIT_ASSERT(hasTextInPdf(pPDFFile, "/Count 1>>", bFound)); CPPUNIT_ASSERT_EQUAL(true, bFound); } // A1:L80 with fit to page width=1: slightly smaller zoom results only 1-page export { ScRange range1(0, 0, 0, 11, 79, 0); std::shared_ptr pPDFFile = exportToPDF(xModel, range1); bool bFound = false; CPPUNIT_ASSERT(hasTextInPdf(pPDFFile, "/Count 1>>", bFound)); CPPUNIT_ASSERT_EQUAL(true, bFound); } } CPPUNIT_TEST_SUITE_REGISTRATION(ScPDFExportTest); CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */