/* -*- 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 "sdmodeltestbase.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star; /// Impress miscellaneous tests. class SdMiscTest : public SdModelTestBaseXML { public: void testTdf96206(); void testTdf96708(); void testTdf99396(); void testTdf99396TextEdit(); void testFillGradient(); void testTdf44774(); void testTdf38225(); void testTdf101242_ODF_no_settings(); void testTdf101242_ODF_add_settings(); void testTdf101242_settings_keep(); void testTdf101242_settings_remove(); void testTdf119392(); void testTdf67248(); void testTdf119956(); void testTdf120527(); void testTdf98839_ShearVFlipH(); void testTdf130988(); void testTdf131033(); void testTdf129898LayerDrawnInSlideshow(); CPPUNIT_TEST_SUITE(SdMiscTest); CPPUNIT_TEST(testTdf96206); CPPUNIT_TEST(testTdf96708); CPPUNIT_TEST(testTdf99396); CPPUNIT_TEST(testTdf99396TextEdit); CPPUNIT_TEST(testFillGradient); CPPUNIT_TEST(testTdf44774); CPPUNIT_TEST(testTdf38225); CPPUNIT_TEST(testTdf101242_ODF_no_settings); CPPUNIT_TEST(testTdf101242_ODF_add_settings); CPPUNIT_TEST(testTdf101242_settings_keep); CPPUNIT_TEST(testTdf101242_settings_remove); CPPUNIT_TEST(testTdf119392); CPPUNIT_TEST(testTdf67248); CPPUNIT_TEST(testTdf119956); CPPUNIT_TEST(testTdf120527); CPPUNIT_TEST(testTdf98839_ShearVFlipH); CPPUNIT_TEST(testTdf130988); CPPUNIT_TEST(testTdf131033); CPPUNIT_TEST(testTdf129898LayerDrawnInSlideshow); CPPUNIT_TEST_SUITE_END(); virtual void registerNamespaces(xmlXPathContextPtr& pXmlXPathCtx) override { static const struct { char const * pPrefix; char const * pURI; } namespaces[] = { // ODF { "config", "urn:oasis:names:tc:opendocument:xmlns:config:1.0"}, { "draw", "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" }, { "fo", "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" }, { "loext", "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" }, { "office", "urn:oasis:names:tc:opendocument:xmlns:office:1.0" }, { "style", "urn:oasis:names:tc:opendocument:xmlns:style:1.0" }, { "svg", "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" }, { "text", "urn:oasis:names:tc:opendocument:xmlns:text:1.0" }, }; for (size_t i = 0; i < SAL_N_ELEMENTS(namespaces); ++i) { xmlXPathRegisterNs(pXmlXPathCtx, reinterpret_cast(namespaces[i].pPrefix), reinterpret_cast(namespaces[i].pURI)); } } private: sd::DrawDocShellRef Load(const OUString& rURL, sal_Int32 nFormat); }; sd::DrawDocShellRef SdMiscTest::Load(const OUString& rURL, sal_Int32 nFormat) { uno::Reference< frame::XDesktop2 > xDesktop = frame::Desktop::create(::comphelper::getProcessComponentContext()); CPPUNIT_ASSERT(xDesktop.is()); // create a frame uno::Reference< frame::XFrame > xTargetFrame = xDesktop->findFrame("_blank", 0); CPPUNIT_ASSERT(xTargetFrame.is()); // This ContainerWindow corresponds to the outermost window of a running LibreOffice. // It needs a non-zero size and must be shown. Otherwise visible elements like the // LayerTabBar in Draw have zero size and cannot get mouse events. // The here used size is freely chosen. uno::Reference xContainerWindow = xTargetFrame->getContainerWindow(); CPPUNIT_ASSERT(xContainerWindow.is()); xContainerWindow->setPosSize(0, 0, 1024, 768, awt::PosSize::SIZE); VclPtr pContainerWindow = VCLUnoHelper::GetWindow(xContainerWindow); CPPUNIT_ASSERT(pContainerWindow); pContainerWindow->Show(true); // 1. Open the document sd::DrawDocShellRef xDocSh = loadURL(rURL, nFormat); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocSh.is()); uno::Reference< frame::XModel2 > xModel2(xDocSh->GetModel(), uno::UNO_QUERY); CPPUNIT_ASSERT(xModel2.is()); uno::Reference< frame::XController2 > 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()); sd::ViewShell *pViewShell = xDocSh->GetViewShell(); CPPUNIT_ASSERT(pViewShell); // Draw has no slidesorter, Impress never shows a LayerTabBar if (sd::ViewShell::ST_DRAW == pViewShell->GetShellType()) { sd::LayerTabBar* pLayerTabBar = static_cast(pViewShell)->GetLayerTabControl(); CPPUNIT_ASSERT(pLayerTabBar); pLayerTabBar->StateChanged(StateChangedType::InitShow); } else { sd::slidesorter::SlideSorterViewShell* pSSVS = nullptr; for (int i = 0; i < 1000; i++) { // Process all Tasks - slide sorter is created here while (Scheduler::ProcessTaskScheduling()); if ((pSSVS = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase())) != nullptr) break; osl::Thread::wait(std::chrono::milliseconds(100)); } CPPUNIT_ASSERT(pSSVS); } return xDocSh; } void SdMiscTest::testTdf96206() { // Copying/pasting slide referring to a non-default master with a text duplicated the master sd::DrawDocShellRef xDocSh = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/odp/tdf96206.odp"), ODP); sd::ViewShell *pViewShell = xDocSh->GetViewShell(); auto pSSVS = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase()); auto& rSSController = pSSVS->GetSlideSorter().GetController(); const sal_uInt16 nMasterPageCnt1 = xDocSh->GetDoc()->GetMasterSdPageCount(PageKind::Standard); CPPUNIT_ASSERT_EQUAL(sal_uInt16(2), nMasterPageCnt1); rSSController.GetClipboard().DoCopy(); rSSController.GetClipboard().DoPaste(); const sal_uInt16 nMasterPageCnt2 = xDocSh->GetDoc()->GetMasterSdPageCount(PageKind::Standard); CPPUNIT_ASSERT_EQUAL(nMasterPageCnt1, nMasterPageCnt2); xDocSh->DoClose(); } void SdMiscTest::testTdf96708() { sd::DrawDocShellRef xDocSh = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/odp/tdf96708.odp"), ODP); sd::ViewShell *pViewShell = xDocSh->GetViewShell(); auto pSSVS = sd::slidesorter::SlideSorterViewShell::GetSlideSorter(pViewShell->GetViewShellBase()); auto& rSSController = pSSVS->GetSlideSorter().GetController(); auto& rPageSelector = rSSController.GetPageSelector(); const sal_uInt16 nMasterPageCnt1 = xDocSh->GetDoc()->GetMasterSdPageCount(PageKind::Standard); CPPUNIT_ASSERT_EQUAL(sal_uInt16(4), nMasterPageCnt1); rPageSelector.SelectAllPages(); rSSController.GetClipboard().DoCopy(); // Now wait for timers to trigger creation of auto-layout osl::Thread::wait(std::chrono::milliseconds(100)); Scheduler::ProcessTaskScheduling(); rSSController.GetClipboard().DoPaste(); const sal_uInt16 nMasterPageCnt2 = xDocSh->GetDoc()->GetMasterSdPageCount(PageKind::Standard); CPPUNIT_ASSERT_EQUAL(nMasterPageCnt1, nMasterPageCnt2); xDocSh->DoClose(); } void SdMiscTest::testTdf99396() { // Load the document and select the table. sd::DrawDocShellRef xDocSh = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf99396.odp"), ODP); sd::ViewShell *pViewShell = xDocSh->GetViewShell(); SdPage* pPage = pViewShell->GetActualPage(); SdrObject* pObject = pPage->GetObj(0); SdrView* pView = pViewShell->GetView(); pView->MarkObj(pObject, pView->GetSdrPageView()); // Make sure that the undo stack is empty. CPPUNIT_ASSERT_EQUAL(static_cast(0), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount()); // Set the vertical alignment of the cells to bottom. sdr::table::SvxTableController* pTableController = dynamic_cast(pView->getSelectionController().get()); CPPUNIT_ASSERT(pTableController); SfxRequest aRequest(pViewShell->GetViewFrame(), SID_TABLE_VERT_BOTTOM); pTableController->Execute(aRequest); // This was 0, it wasn't possible to undo a vertical alignment change. CPPUNIT_ASSERT_EQUAL(static_cast(1), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount()); xDocSh->DoClose(); } void SdMiscTest::testTdf99396TextEdit() { // Load the document and select the table. sd::DrawDocShellRef xDocSh = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf99396.odp"), ODP); sd::ViewShell* pViewShell = xDocSh->GetViewShell(); SdPage* pPage = pViewShell->GetActualPage(); auto pTableObject = dynamic_cast(pPage->GetObj(0)); CPPUNIT_ASSERT(pTableObject); SdrView* pView = pViewShell->GetView(); pView->MarkObj(pTableObject, pView->GetSdrPageView()); // Make sure that the undo stack is empty. CPPUNIT_ASSERT_EQUAL(static_cast(0), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount()); // Set horizontal and vertical adjustment during text edit. pView->SdrBeginTextEdit(pTableObject); CPPUNIT_ASSERT(pView->GetTextEditObject()); { SfxRequest aRequest(pViewShell->GetViewFrame(), SID_ATTR_PARA_ADJUST_RIGHT); SfxItemSet aEditAttr(xDocSh->GetDoc()->GetPool()); pView->GetAttributes(aEditAttr); SfxItemSet aNewAttr(*(aEditAttr.GetPool()), aEditAttr.GetRanges()); aNewAttr.Put(SvxAdjustItem(SvxAdjust::Right, EE_PARA_JUST)); aRequest.Done(aNewAttr); const SfxItemSet* pArgs = aRequest.GetArgs(); pView->SetAttributes(*pArgs); } { auto pTableController = dynamic_cast(pView->getSelectionController().get()); CPPUNIT_ASSERT(pTableController); SfxRequest aRequest(pViewShell->GetViewFrame(), SID_TABLE_VERT_BOTTOM); pTableController->Execute(aRequest); } pView->SdrEndTextEdit(); // Check that the result is what we expect. { uno::Reference xTable = pTableObject->getTable(); uno::Reference xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY); drawing::TextVerticalAdjust eAdjust = xCell->getPropertyValue("TextVerticalAdjust").get(); CPPUNIT_ASSERT_EQUAL(int(drawing::TextVerticalAdjust_BOTTOM), static_cast(eAdjust)); } { const EditTextObject& rEdit = pTableObject->getText(0)->GetOutlinerParaObject()->GetTextObject(); const SfxItemSet& rParaAttribs = rEdit.GetParaAttribs(0); auto pAdjust = rParaAttribs.GetItem(EE_PARA_JUST); CPPUNIT_ASSERT_EQUAL(SvxAdjust::Right, pAdjust->GetAdjust()); } // Now undo. xDocSh->GetUndoManager()->Undo(); // Check again that the result is what we expect. { uno::Reference xTable = pTableObject->getTable(); uno::Reference xCell(xTable->getCellByPosition(0, 0), uno::UNO_QUERY); drawing::TextVerticalAdjust eAdjust = xCell->getPropertyValue("TextVerticalAdjust").get(); // This failed: Undo() did not change it from drawing::TextVerticalAdjust_BOTTOM. CPPUNIT_ASSERT_EQUAL(int(drawing::TextVerticalAdjust_TOP), static_cast(eAdjust)); } { const EditTextObject& rEdit = pTableObject->getText(0)->GetOutlinerParaObject()->GetTextObject(); const SfxItemSet& rParaAttribs = rEdit.GetParaAttribs(0); auto pAdjust = rParaAttribs.GetItem(EE_PARA_JUST); CPPUNIT_ASSERT_EQUAL(SvxAdjust::Center, pAdjust->GetAdjust()); } /* * now test tdf#103950 - Undo does not revert bundled font size changes for table cells */ pTableObject = dynamic_cast(pPage->GetObj(0)); pView->MarkObj(pTableObject, pView->GetSdrPageView()); // select table { SfxRequest aRequest(pViewShell->GetViewFrame(), SID_GROW_FONT_SIZE); static_cast(pViewShell)->ExecChar(aRequest); } CPPUNIT_ASSERT_EQUAL(static_cast(2), xDocSh->GetDoc()->GetUndoManager()->GetUndoActionCount()); xDocSh->DoClose(); } void SdMiscTest::testFillGradient() { ::sd::DrawDocShellRef xDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Impress); uno::Reference xDrawPagesSupplier = getDoc( xDocShRef ); uno::Reference xDrawPages = xDrawPagesSupplier->getDrawPages(); // Insert a new page. uno::Reference xDrawPage(xDrawPages->insertNewByIndex(0), uno::UNO_SET_THROW ); uno::Reference xShapes(xDrawPage,uno::UNO_QUERY_THROW); uno::Reference const xDoc(xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY); // Create a rectangle uno::Reference xShape1(xDoc->createInstance("com.sun.star.drawing.RectangleShape"),uno::UNO_QUERY_THROW ); uno::Reference xPropSet(xShape1, uno::UNO_QUERY_THROW); // Set FillStyle and FillGradient awt::Gradient aGradient; aGradient.StartColor = sal_Int32(Color(255, 0, 0)); aGradient.EndColor = sal_Int32(Color(0, 255, 0)); xPropSet->setPropertyValue("FillStyle", uno::makeAny(drawing::FillStyle_GRADIENT)); xPropSet->setPropertyValue("FillGradient", uno::makeAny(aGradient)); // Add the rectangle to the page. xShapes->add(xShape1); // Retrieve the shape and check FillStyle and FillGradient uno::Reference xIndexAccess(xDrawPage, uno::UNO_QUERY_THROW); uno::Reference xPropSet2(xIndexAccess->getByIndex(0), uno::UNO_QUERY_THROW); drawing::FillStyle eFillStyle; awt::Gradient aGradient2; CPPUNIT_ASSERT(xPropSet2->getPropertyValue("FillStyle") >>= eFillStyle); CPPUNIT_ASSERT_EQUAL(int(drawing::FillStyle_GRADIENT), static_cast(eFillStyle)); CPPUNIT_ASSERT(xPropSet2->getPropertyValue("FillGradient") >>= aGradient2); CPPUNIT_ASSERT_EQUAL(sal_Int32(Color(255, 0, 0)),aGradient2.StartColor); CPPUNIT_ASSERT_EQUAL(sal_Int32(Color(0, 255, 0)),aGradient2.EndColor); xDocShRef->DoClose(); } void SdMiscTest::testTdf44774() { sd::DrawDocShellRef xDocShRef = new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Draw); const uno::Reference xLoadable(xDocShRef->GetModel(), uno::UNO_QUERY_THROW); xLoadable->initNew(); SfxStyleSheetBasePool* pSSPool = xDocShRef->GetStyleSheetPool(); // Create a new style with an empty name, like what happens in UI when creating a new style SfxStyleSheetBase& rStyleA = pSSPool->Make("", SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined); // Assign a new name, which does not yet set its ApiName rStyleA.SetName("StyleA"); // Create another style SfxStyleSheetBase& rStyleB = pSSPool->Make("StyleB", SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined); // ... and set its parent to the first one rStyleB.SetParent("StyleA"); // Now save the file and reload xDocShRef = saveAndReload(xDocShRef.get(), ODG); pSSPool = xDocShRef->GetStyleSheetPool(); SfxStyleSheetBase* pStyle = pSSPool->Find("StyleB", SfxStyleFamily::Para); CPPUNIT_ASSERT(pStyle); // The parent set in StyleB used to reset, because parent style's msApiName was empty CPPUNIT_ASSERT_EQUAL(OUString("StyleA"), pStyle->GetParent()); xDocShRef->DoClose(); } void SdMiscTest::testTdf38225() { sd::DrawDocShellRef xDocShRef = new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Draw); const uno::Reference xLoadable(xDocShRef->GetModel(), uno::UNO_QUERY_THROW); xLoadable->initNew(); SfxStyleSheetBasePool* pSSPool = xDocShRef->GetStyleSheetPool(); // Create a new style with a name pSSPool->Make("StyleWithName1", SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined); // Now save the file and reload xDocShRef = saveAndReload(xDocShRef.get(), ODG); pSSPool = xDocShRef->GetStyleSheetPool(); SfxStyleSheetBase* pStyle = pSSPool->Find("StyleWithName1", SfxStyleFamily::Para); CPPUNIT_ASSERT(pStyle); // Rename the style CPPUNIT_ASSERT(pStyle->SetName("StyleWithName2")); // Save the file and reload again xDocShRef = saveAndReload(xDocShRef.get(), ODG); pSSPool = xDocShRef->GetStyleSheetPool(); // The problem was that the style kept the old name upon reloading pStyle = pSSPool->Find("StyleWithName1", SfxStyleFamily::Para); CPPUNIT_ASSERT(!pStyle); pStyle = pSSPool->Find("StyleWithName2", SfxStyleFamily::Para); CPPUNIT_ASSERT(pStyle); xDocShRef->DoClose(); } void SdMiscTest::testTdf120527() { sd::DrawDocShellRef xDocShRef = new sd::DrawDocShell(SfxObjectCreateMode::EMBEDDED, false, DocumentType::Draw); uno::Reference xLoadable(xDocShRef->GetModel(), uno::UNO_QUERY); CPPUNIT_ASSERT(xLoadable.is()); xLoadable->initNew(); // Load a bitmap into the bitmap table. uno::Reference xFactory(xDocShRef->GetModel(), uno::UNO_QUERY); CPPUNIT_ASSERT(xFactory.is()); uno::Reference xBitmaps( xFactory->createInstance("com.sun.star.drawing.BitmapTable"), uno::UNO_QUERY); CPPUNIT_ASSERT(xBitmaps.is()); OUString aGraphicURL = m_directories.getURLFromSrc("/sd/qa/unit/data/tdf120527.jpg"); xBitmaps->insertByName("test", uno::makeAny(aGraphicURL)); // Create a graphic. uno::Reference xShape( xFactory->createInstance("com.sun.star.drawing.GraphicObjectShape"), uno::UNO_QUERY); CPPUNIT_ASSERT(xShape.is()); uno::Reference xShapeProperySet(xShape, uno::UNO_QUERY); CPPUNIT_ASSERT(xShapeProperySet.is()); xShapeProperySet->setPropertyValue("GraphicURL", xBitmaps->getByName("test")); // Insert it. uno::Reference xDrawPagesSupplier(xDocShRef->GetModel(), uno::UNO_QUERY); CPPUNIT_ASSERT(xDrawPagesSupplier.is()); uno::Reference xDrawPages = xDrawPagesSupplier->getDrawPages(); CPPUNIT_ASSERT(xDrawPages.is()); uno::Reference xDrawPage(xDrawPages->getByIndex(0), uno::UNO_QUERY); CPPUNIT_ASSERT(xDrawPage.is()); // This failed with a lang.IllegalArgumentException. xDrawPage->add(xShape); // Verify that the graphic was actually consumed. uno::Reference xGraphic; xShapeProperySet->getPropertyValue("Graphic") >>= xGraphic; CPPUNIT_ASSERT(xGraphic.is()); xDocShRef->DoClose(); } /// Draw miscellaneous tests. // Since LO 6.2 the visible/printable/locked information for layers is always // written as ODF attributes draw:display and draw:protected. It is only read from // there, if the config items VisibleLayers, PrintableLayers and LockedLayers do // not exist. The user option WriteLayerStateAsConfigItem can be set to 'true' to // write these config items in addition to the ODF attributes for to produce // documents for older LO versions or Apache OpenOffice. With value 'false' no // config items are written. The 'testTdf101242_xyz' tests combine source // files with and without config items with option values 'true' and 'false'. void SdMiscTest::testTdf101242_ODF_add_settings() { // Loads a document, which has the visible/printable/locked information for layers // only in the ODF attributes draw:display and draw:protected. The resaved document // should still have the ODF attributes and in addition the config items in settings.xml. // "Load" is needed for to handle layers, simple "loadURL" does not work. sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf101242_ODF.odg"), ODG); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); // Saving including items in settings.xml std::shared_ptr pBatch( comphelper::ConfigurationChanges::create() ); officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, pBatch); pBatch->commit(); utl::TempFile aTempFile; aTempFile.EnableKillingFile(); save(xDocShRef.get(), getFormat(ODG), aTempFile ); // Verify, that the saved document still has the ODF attributes xmlDocUniquePtr pXmlDoc = parseExport(aTempFile, "styles.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc); const OString sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']"); // Verify, that the saved document has got the items in settings.xml xmlDocUniquePtr pXmlDoc2 = parseExport(aTempFile, "settings.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2); const OString sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry"); // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout' // The first three bits depend on initialization and may change. The values in file are Base64 encoded. OUString sBase64; uno::Sequence aDecodedSeq; sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x0F, static_cast(aDecodedSeq[0]) & 0x1F ); sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x17, static_cast(aDecodedSeq[0]) & 0x1F); sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x04, static_cast(aDecodedSeq[0]) & 0x1F); xDocShRef->DoClose(); } void SdMiscTest::testTdf101242_ODF_no_settings() { // Loads a document, which has the visible/printable/locked information for layers // only in the ODF attributes draw:display and draw:protected. The resave document // should have only the ODF attributes and no config items in settings.xml. sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf101242_ODF.odg"), ODG); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); // Saving without items in settings.xml std::shared_ptr pBatch( comphelper::ConfigurationChanges::create() ); officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(false, pBatch); pBatch->commit(); utl::TempFile aTempFile; aTempFile.EnableKillingFile(); save(xDocShRef.get(), getFormat(ODG), aTempFile ); // Verify, that the saved document still has the ODF attributes xmlDocUniquePtr pXmlDoc = parseExport(aTempFile, "styles.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc); const OString sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']"); // Verify, that the saved document has no layer items in settings.xml xmlDocUniquePtr pXmlDoc2 = parseExport(aTempFile, "settings.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2); const OString sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry"); xmlXPathObjectPtr pXmlObj=getXPathNode(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']"); CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj->nodesetval)); xmlXPathFreeObject(pXmlObj); pXmlObj=getXPathNode(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']"); CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj->nodesetval)); xmlXPathFreeObject(pXmlObj); pXmlObj=getXPathNode(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']"); CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj->nodesetval)); xmlXPathFreeObject(pXmlObj); xDocShRef->DoClose(); } void SdMiscTest::testTdf101242_settings_keep() { // Loads a document, which has the visible/printable/locked information for layers // only in the config items in settings.xml. That is the case for all old documents. // The resaved document should have the ODF attributes draw:display and draw:protected // and should still have these config items in settings.xml. sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf101242_settings.odg"), ODG); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); // Saving including items in settings.xml std::shared_ptr pBatch( comphelper::ConfigurationChanges::create() ); officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, pBatch); pBatch->commit(); utl::TempFile aTempFile; aTempFile.EnableKillingFile(); save(xDocShRef.get(), getFormat(ODG), aTempFile ); // Verify, that the saved document has the ODF attributes xmlDocUniquePtr pXmlDoc = parseExport(aTempFile, "styles.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc); const OString sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']"); // Verify, that the saved document still has the items in settings.xml xmlDocUniquePtr pXmlDoc2 = parseExport(aTempFile, "settings.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2); const OString sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry"); // Value is a bitfield with first Byte in order '* * * measurelines controls backgroundobjects background layout' // The first three bits depend on initialization and may change. The values in file are Base64 encoded. OUString sBase64; uno::Sequence aDecodedSeq; sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x0F, static_cast(aDecodedSeq[0]) & 0x1F ); sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x17, static_cast(aDecodedSeq[0]) & 0x1F); sBase64 = getXPathContent(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x04, static_cast(aDecodedSeq[0]) & 0x1F); xDocShRef->DoClose(); } void SdMiscTest::testTdf101242_settings_remove() { // Loads a document, which has the visible/printable/locked information for layers // only in the config items in settings.xml. That is the case for all old documents. // The resaved document should have only the ODF attributes draw:display and draw:protected // and should have no config items in settings.xml. sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("/sd/qa/unit/data/tdf101242_settings.odg"), ODG); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); // Saving without config items in settings.xml std::shared_ptr pBatch( comphelper::ConfigurationChanges::create() ); officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(false, pBatch); pBatch->commit(); utl::TempFile aTempFile; aTempFile.EnableKillingFile(); save(xDocShRef.get(), getFormat(ODG), aTempFile ); // Verify, that the saved document has the ODF attributes xmlDocUniquePtr pXmlDoc = parseExport(aTempFile, "styles.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'styles.xml'", pXmlDoc); const OString sPathStart("/office:document-styles/office:master-styles/draw:layer-set/draw:layer"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='backgroundobjects' and @draw:protected='true']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='controls' and @draw:display='screen']"); assertXPath(pXmlDoc, sPathStart + "[@draw:name='measurelines' and @draw:display='printer']"); // Verify, that the saved document has no layer items in settings.xml xmlDocUniquePtr pXmlDoc2 = parseExport(aTempFile, "settings.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc2); const OString sPathStart2("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry"); xmlXPathObjectPtr pXmlObj=getXPathNode(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='VisibleLayers']"); CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj->nodesetval)); xmlXPathFreeObject(pXmlObj); pXmlObj=getXPathNode(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='PrintableLayers']"); CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj->nodesetval)); xmlXPathFreeObject(pXmlObj); pXmlObj=getXPathNode(pXmlDoc2, sPathStart2 + "/config:config-item[@config:name='LockedLayers']"); CPPUNIT_ASSERT_EQUAL(0, xmlXPathNodeSetGetLength(pXmlObj->nodesetval)); xmlXPathFreeObject(pXmlObj); xDocShRef->DoClose(); } void SdMiscTest::testTdf119392() { // Loads a document which has two user layers "V--" and "V-L". Inserts a new layer "-P-" between them. // Checks, that the bitfields in the saved file have the bits in the correct order, in case // option WriteLayerAsConfigItem is true and the config items are written. std::shared_ptr batch( comphelper::ConfigurationChanges::create() ); officecfg::Office::Common::Misc::WriteLayerStateAsConfigItem::set(true, batch); batch->commit(); sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("sd/qa/unit/data/tdf119392_InsertLayer.odg"), ODG); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); // Insert layer "-P-", not visible, printable, not locked SdrView* pView = xDocShRef -> GetViewShell()->GetView(); pView -> InsertNewLayer("-P-", 6); // 0..4 standard layer, 5 layer "V--" SdrPageView* pPageView = pView -> GetSdrPageView(); pPageView -> SetLayerVisible("-P-", false); pPageView -> SetLayerPrintable("-P-", true); pPageView -> SetLayerLocked("-P-", false); utl::TempFile aTempFile; aTempFile.EnableKillingFile(); save(xDocShRef.get(), getFormat(ODG), aTempFile ); // Verify correct bit order in bitfield in the config items in settings.xml xmlDocUniquePtr pXmlDoc = parseExport(aTempFile, "settings.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'settings.xml'", pXmlDoc); const OString sPathStart("/office:document-settings/office:settings/config:config-item-set[@config:name='ooo:view-settings']/config:config-item-map-indexed[@config:name='Views']/config:config-item-map-entry"); // First Byte is in order 'V-L -P- V-- measurelines controls backgroundobjects background layout' // Bits need to be: visible=10111111=0xbf=191 printable=01011111=0x5f=95 locked=10000000=0x80=128 // The values in file are Base64 encoded. OUString sBase64; uno::Sequence aDecodedSeq; sBase64 = getXPathContent(pXmlDoc, sPathStart + "/config:config-item[@config:name='VisibleLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item VisibleLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0xbF, static_cast(aDecodedSeq[0]) & 0xff); // & 0xff forces unambiguous types for CPPUNIT_ASSERT_EQUAL sBase64 = getXPathContent(pXmlDoc, sPathStart + "/config:config-item[@config:name='PrintableLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item PrintableLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x5f, static_cast(aDecodedSeq[0]) & 0xff); sBase64 = getXPathContent(pXmlDoc, sPathStart + "/config:config-item[@config:name='LockedLayers']"); CPPUNIT_ASSERT_MESSAGE( "Item LockedLayers does not exists.", !sBase64.isEmpty()); comphelper::Base64::decode(aDecodedSeq, sBase64); CPPUNIT_ASSERT_EQUAL( 0x80, static_cast(aDecodedSeq[0]) & 0xff); xDocShRef->DoClose(); } void SdMiscTest::testTdf67248() { // The document tdf67248.odg has been created with a German UI. It has a user layer named "Background". // On opening the user layer must still exists. The error was, that it was merged into the standard // layer "background". sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("sd/qa/unit/data/tdf67248.odg"), ODG); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); SdrLayerAdmin& rLayerAdmin = xDocShRef->GetDoc()->GetLayerAdmin(); CPPUNIT_ASSERT_EQUAL( sal_uInt16(6), rLayerAdmin.GetLayerCount()); xDocShRef->DoClose(); } void SdMiscTest::testTdf119956() { sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc("sd/qa/unit/data/tdf119956.odg"), ODG); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); sd::GraphicViewShell* pGraphicViewShell = static_cast(xDocShRef -> GetViewShell()); CPPUNIT_ASSERT(pGraphicViewShell); sd::LayerTabBar* pLayerTabBar = pGraphicViewShell->GetLayerTabControl(); CPPUNIT_ASSERT(pLayerTabBar); // Alt+Click sets a tab in edit mode, so that you can rename it. // The error was, that Alt+Click on a tab, which was not the current tab, did not set the clicked tab // as current tab. As a result, the entered text was applied to the wrong tab. // The test document has the layer tabs "layout", "controls", "measurelines" and "Layer4" in this order // The "pagePos" is 0, 1, 2, 3 // Make sure, that tab "layout" is the current tab. MouseEvent aSyntheticMouseEvent; if (pLayerTabBar->GetCurPagePos() != 0) { sal_uInt16 nIdOfTabPos0(pLayerTabBar->GetPageId(0)); tools::Rectangle aTabPos0Rect(pLayerTabBar->GetPageRect(nIdOfTabPos0)); aSyntheticMouseEvent = MouseEvent(aTabPos0Rect.Center(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, 0); pLayerTabBar->MouseButtonDown(aSyntheticMouseEvent); } CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pLayerTabBar->GetCurPagePos()); // Alt+Click on tab "Layer4" sal_uInt16 nIdOfTabPos3(pLayerTabBar->GetPageId(3)); tools::Rectangle aTabPos3Rect(pLayerTabBar->GetPageRect(nIdOfTabPos3)); aSyntheticMouseEvent = MouseEvent(aTabPos3Rect.Center(), 1, MouseEventModifiers::SYNTHETIC, MOUSE_LEFT, KEY_MOD2); pLayerTabBar->MouseButtonDown(aSyntheticMouseEvent); // Make sure, tab 3 is current tab now. CPPUNIT_ASSERT_EQUAL(sal_uInt16(3), pLayerTabBar->GetCurPagePos()); xDocShRef->DoClose(); } void SdMiscTest::testTdf98839_ShearVFlipH() { // Loads a document with a sheared shape and mirrors it const OUString sURL = "sd/qa/unit/data/tdf98839_ShearVFlipH.odg"; sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc(sURL), ODG); sd::GraphicViewShell* pViewShell = static_cast(xDocShRef->GetViewShell()); SdPage* pPage = pViewShell->GetActualPage(); SdrObjCustomShape* pShape = static_cast(pPage->GetObj(0)); pShape->Mirror(Point(4000, 2000), Point(4000, 10000)); // Save and examine attribute draw:transform utl::TempFile aTempFile; aTempFile.EnableKillingFile(); save(xDocShRef.get(), getFormat(ODG), aTempFile); xmlDocUniquePtr pXmlDoc = parseExport(aTempFile, "content.xml"); CPPUNIT_ASSERT_MESSAGE("Failed to get 'content.xml'", pXmlDoc); const OString sPathStart("/office:document-content/office:body/office:drawing/draw:page"); assertXPath(pXmlDoc, sPathStart); const OUString sTransform = getXPath(pXmlDoc, sPathStart + "/draw:custom-shape","transform"); // Error was, that the shear angle had a wrong sign. CPPUNIT_ASSERT_MESSAGE("expected: draw:transform='skewX (-0.64350...)", sTransform.startsWith("skewX (-")); xDocShRef->DoClose(); } void SdMiscTest::testTdf130988() { const OUString sURL("sd/qa/unit/data/tdf130988_3D_create_lathe.odg"); sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc(sURL), ODG); //emulate command .uno:ConvertInto3DLathe sd::ViewShell* pViewShell = xDocShRef->GetViewShell(); E3dView* pView = dynamic_cast(pViewShell->GetView()); pView->MarkNextObj(); pView->ConvertMarkedObjTo3D(false, basegfx::B2DPoint(8000.0, -3000.0), basegfx::B2DPoint(3000.0, -8000.0)); E3dScene* pObj = dynamic_cast(pView->GetMarkedObjectByIndex(0)); CPPUNIT_ASSERT(pObj); // Error was, that the created 3D object had a wrong path. Instead examining // the path directly, I use the scene distance, because that is easier. The // scene distance is calculated from the object while creating. const double fDistance = pObj->GetDistance(); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("D3DSceneDistance", 7071.0, fDistance, 0.5); xDocShRef->DoClose(); } void SdMiscTest::testTdf131033() { const OUString sURL("sd/qa/unit/data/tdf131033_3D_SceneSizeIn2d.odg"); sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc(sURL), ODG); // The document contains a polygon, so that emulate command .uno:ConvertInto3DLathe // by direct call of ConvertMarkedObjTo3D works. // It produces a rotation around a vertical axis, which is far away from the // generating shape. sd::ViewShell* pViewShell = xDocShRef->GetViewShell(); E3dView* pView = dynamic_cast(pViewShell->GetView()); pView->MarkNextObj(); pView->ConvertMarkedObjTo3D(false, basegfx::B2DPoint(11000.0, -5000.0), basegfx::B2DPoint(11000.0, -9000.0)); E3dScene* pObj = dynamic_cast(pView->GetMarkedObjectByIndex(0)); CPPUNIT_ASSERT(pObj); // Error was, that the 2D representation of the scene did not contain the default 20° // rotation of the new scene around x-axis and therefore was not high enough. const double fSnapRectHeight = pObj->GetSnapRect().getHeight(); CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("2D height", 7096.0, fSnapRectHeight, 1.0); xDocShRef->DoClose(); } void SdMiscTest::testTdf129898LayerDrawnInSlideshow() { // Versions LO 6.2 to 6.4 have produced files, where the layer DrawnInSlideshow has // got visible=false and printable=false attributes. Those files should be repaired now. const OUString sURL = "sd/qa/unit/data/tdf129898_faulty_DrawnInSlideshow.odp"; sd::DrawDocShellRef xDocShRef = Load(m_directories.getURLFromSrc(sURL), ODP); CPPUNIT_ASSERT_MESSAGE("Failed to load file.", xDocShRef.is()); // Verify model const OUString sName = "DrawnInSlideshow"; SdrLayerAdmin& rLayerAdmin = xDocShRef->GetDoc()->GetLayerAdmin(); SdrLayer* pLayer = rLayerAdmin.GetLayer(sName); CPPUNIT_ASSERT_MESSAGE("No layer DrawnInSlideshow", pLayer); CPPUNIT_ASSERT(pLayer->IsVisibleODF() && pLayer->IsPrintableODF()); // Verify view sd::DrawViewShell* pViewShell = static_cast(xDocShRef->GetViewShell()); SdrPageView* pPageView = pViewShell->GetView()->GetSdrPageView(); CPPUNIT_ASSERT(pPageView->IsLayerVisible(sName) && pPageView->IsLayerPrintable(sName)); xDocShRef->DoClose(); } CPPUNIT_TEST_SUITE_REGISTRATION(SdMiscTest); CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */