diff options
Diffstat (limited to 'sw/qa/uibase/uiview/uiview.cxx')
-rw-r--r-- | sw/qa/uibase/uiview/uiview.cxx | 318 |
1 files changed, 318 insertions, 0 deletions
diff --git a/sw/qa/uibase/uiview/uiview.cxx b/sw/qa/uibase/uiview/uiview.cxx new file mode 100644 index 0000000000..ceae7d644c --- /dev/null +++ b/sw/qa/uibase/uiview/uiview.cxx @@ -0,0 +1,318 @@ +/* -*- 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 <swmodeltestbase.hxx> + +#include <comphelper/processfactory.hxx> +#include <osl/file.hxx> +#include <comphelper/propertyvalue.hxx> +#include <comphelper/scopeguard.hxx> +#include <vcl/scheduler.hxx> + +#include <com/sun/star/frame/XDispatchHelper.hpp> +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XComponentLoader.hpp> +#include <com/sun/star/frame/XStorable2.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/packages/zip/ZipFileAccess.hpp> +#include <com/sun/star/view/XSelectionSupplier.hpp> + +#include <unotxdoc.hxx> +#include <docsh.hxx> +#include <wrtsh.hxx> +#include <swmodule.hxx> +#include <view.hxx> + +/// Covers sw/source/uibase/uiview/ fixes. +class SwUibaseUiviewTest : public SwModelTestBase +{ +public: + SwUibaseUiviewTest() + : SwModelTestBase("/sw/qa/uibase/uiview/data/") + { + } +}; + +CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testUpdateAllObjectReplacements) +{ + // Make a temporary copy of the test document + createTempCopy(u"updateall-objectreplacements.odt"); + + /* BASIC code that exhibits the problem: + + desktop = CreateUnoService("com.sun.star.frame.Desktop") + Dim props(0) as new com.sun.star.beans.PropertyValue + props(0).Name = "Hidden" + props(0).Value = true + component = desktop.loadComponentFromURL("file://.../test.odt", "_default", 0, props) + Wait 1000 ' workaround + dispatcher = createUnoService("com.sun.star.frame.DispatchHelper") + frame = component.CurrentController.Frame + dispatcher.executeDispatch(frame, ".uno:UpdateAll", "", 0, Array()) + component.storeSelf(Array()) + component.dispose() + */ + + uno::Reference<lang::XMultiServiceFactory> xFactory(comphelper::getProcessServiceFactory()); + + // Load the copy + uno::Reference<uno::XInterface> xInterface + = xFactory->createInstance("com.sun.star.frame.Desktop"); + uno::Reference<frame::XComponentLoader> xComponentLoader(xInterface, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aLoadArgs{ comphelper::makePropertyValue("Hidden", true) }; + mxComponent + = xComponentLoader->loadComponentFromURL(maTempFile.GetURL(), "_default", 0, aLoadArgs); + + // Perform the .uno:UpdateAll call and save + xInterface = xFactory->createInstance("com.sun.star.frame.DispatchHelper"); + uno::Reference<frame::XDispatchHelper> xDispatchHelper(xInterface, uno::UNO_QUERY); + uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); + uno::Reference<frame::XDispatchProvider> xDispatchProvider( + xModel->getCurrentController()->getFrame(), uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aNoArgs; + xDispatchHelper->executeDispatch(xDispatchProvider, ".uno:UpdateAll", OUString(), 0, aNoArgs); + uno::Reference<frame::XStorable2> xStorable(mxComponent, uno::UNO_QUERY); + xStorable->storeSelf(aNoArgs); + + // Check the contents of the updated copy and verify that ObjectReplacements are there + uno::Reference<packages::zip::XZipFileAccess2> xNameAccess + = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(xFactory), + maTempFile.GetURL()); + + CPPUNIT_ASSERT(xNameAccess->hasByName("ObjectReplacements/Components")); + CPPUNIT_ASSERT(xNameAccess->hasByName("ObjectReplacements/Components_1")); +} + +CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testUpdateReplacementNosetting) +{ + // Load a copy of the document in hidden mode. + OUString aSourceURL = createFileURL(u"update-replacement-nosetting.odt"); + CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, osl::File::copy(aSourceURL, maTempFile.GetURL())); + mxComponent = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument", + { comphelper::makePropertyValue("Hidden", true) }); + + // Update "everything" (including object replacements) and save it. + dispatchCommand(mxComponent, ".uno:UpdateAll", {}); + uno::Reference<frame::XStorable2> xStorable(mxComponent, uno::UNO_QUERY); + xStorable->storeSelf({}); + + // Check the contents of the updated copy. + uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext(); + uno::Reference<packages::zip::XZipFileAccess2> xNameAccess + = packages::zip::ZipFileAccess::createWithURL(xContext, maTempFile.GetURL()); + + // Without the accompanying fix in place, this test would have failed, because the embedded + // object replacement image was not generated. + CPPUNIT_ASSERT(xNameAccess->hasByName("ObjectReplacements/Components")); +} + +CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testKeepRatio) +{ + // Given a document with a custom KeepRatio: + OUString aURL = createFileURL(u"keep-ratio.fodt"); + + // When loading that document: + mxComponent = loadFromDesktop(aURL); + + // Then make sure we read the custom value: + auto pXTextDocument = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + SwWrtShell* pWrtShell = pXTextDocument->GetDocShell()->GetWrtShell(); + const SwViewOption* pViewOption = pWrtShell->GetViewOptions(); + comphelper::ScopeGuard g([pWrtShell, pViewOption] { + SwViewOption aViewOption(*pViewOption); + aViewOption.SetKeepRatio(false); + SW_MOD()->ApplyUsrPref(aViewOption, &pWrtShell->GetView()); + }); + // Without the accompanying fix in place, this test would have failed, because KeepRatio was not + // mapped to settings.xml + CPPUNIT_ASSERT(pViewOption->IsKeepRatio()); + + // Then export as well: + save("writer8"); + xmlDocUniquePtr pXmlDoc = parseExport("settings.xml"); + assertXPathContent(pXmlDoc, "//config:config-item[@config:name='KeepRatio']"_ostr, "true"); +} + +namespace +{ +/// Interception implementation that disables .uno:Zoom on Image1, but not on Image2. +struct ImageInterceptor : public cppu::WeakImplHelper<frame::XDispatchProviderInterceptor> +{ + uno::Reference<view::XSelectionSupplier> m_xSelectionSupplier; + uno::Reference<frame::XDispatchProvider> m_xMaster; + uno::Reference<frame::XDispatchProvider> m_xSlave; + int m_nEnabled = 0; + int m_nDisabled = 0; + +public: + ImageInterceptor(const uno::Reference<lang::XComponent>& xComponent); + + // XDispatchProviderInterceptor + uno::Reference<frame::XDispatchProvider> SAL_CALL getMasterDispatchProvider() override; + uno::Reference<frame::XDispatchProvider> SAL_CALL getSlaveDispatchProvider() override; + void SAL_CALL setMasterDispatchProvider( + const uno::Reference<frame::XDispatchProvider>& xNewSupplier) override; + void SAL_CALL + setSlaveDispatchProvider(const uno::Reference<frame::XDispatchProvider>& xNewSupplier) override; + + // XDispatchProvider + uno::Reference<frame::XDispatch> SAL_CALL queryDispatch(const util::URL& rURL, + const OUString& rTargetFrameName, + sal_Int32 SearchFlags) override; + uno::Sequence<uno::Reference<frame::XDispatch>> SAL_CALL + queryDispatches(const uno::Sequence<frame::DispatchDescriptor>& rRequests) override; +}; +} + +ImageInterceptor::ImageInterceptor(const uno::Reference<lang::XComponent>& xComponent) +{ + uno::Reference<frame::XModel2> xModel(xComponent, uno::UNO_QUERY); + CPPUNIT_ASSERT(xModel.is()); + m_xSelectionSupplier.set(xModel->getCurrentController(), uno::UNO_QUERY); + CPPUNIT_ASSERT(m_xSelectionSupplier.is()); +} + +uno::Reference<frame::XDispatchProvider> ImageInterceptor::getMasterDispatchProvider() +{ + return m_xMaster; +} + +uno::Reference<frame::XDispatchProvider> ImageInterceptor::getSlaveDispatchProvider() +{ + return m_xSlave; +} + +void ImageInterceptor::setMasterDispatchProvider( + const uno::Reference<frame::XDispatchProvider>& xNewSupplier) +{ + m_xMaster = xNewSupplier; +} + +void ImageInterceptor::setSlaveDispatchProvider( + const uno::Reference<frame::XDispatchProvider>& xNewSupplier) +{ + m_xSlave = xNewSupplier; +} + +uno::Reference<frame::XDispatch> ImageInterceptor::queryDispatch(const util::URL& rURL, + const OUString& rTargetFrameName, + sal_Int32 nSearchFlags) +{ + // Disable the UNO command based on the currently selected image, i.e. this can't be cached when + // a different image is selected. Originally this was .uno:SetBorderStyle, but let's pick a + // command which is active when running cppunit tests: + if (rURL.Complete == ".uno:Zoom") + { + uno::Reference<container::XNamed> xImage; + m_xSelectionSupplier->getSelection() >>= xImage; + if (xImage.is() && xImage->getName() == "Image1") + { + ++m_nDisabled; + return {}; + } + + ++m_nEnabled; + } + + return m_xSlave->queryDispatch(rURL, rTargetFrameName, nSearchFlags); +} + +uno::Sequence<uno::Reference<frame::XDispatch>> +ImageInterceptor::queryDispatches(const uno::Sequence<frame::DispatchDescriptor>& /*rRequests*/) +{ + return {}; +} + +CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testSwitchBetweenImages) +{ + // Given a document with 2 images, and an interceptor catching an UNO command that specific to + // the current selection: + createSwDoc(); + SwDoc* pDoc = getSwDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + for (int i = 0; i < 2; ++i) + { + uno::Reference<beans::XPropertySet> xTextGraphic( + xMSF->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY); + xTextGraphic->setPropertyValue("AnchorType", + uno::Any(text::TextContentAnchorType_AS_CHARACTER)); + xTextGraphic->setPropertyValue("Size", uno::Any(awt::Size(5000, 5000))); + uno::Reference<text::XTextContent> xTextContent(xTextGraphic, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xTextContent, false); + } + pWrtShell->SttEndDoc(/*bStt=*/false); + uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY); + uno::Reference<frame::XDispatchProviderInterception> xRegistration( + xModel->getCurrentController()->getFrame(), uno::UNO_QUERY); + rtl::Reference pInterceptor(new ImageInterceptor(mxComponent)); + + xRegistration->registerDispatchProviderInterceptor(pInterceptor); + pInterceptor->m_nEnabled = 0; + pInterceptor->m_nDisabled = 0; + + // When selecting the first image: + selectShape(1); + + // Then make sure the UNO command is disabled: + CPPUNIT_ASSERT_EQUAL(0, pInterceptor->m_nEnabled); + CPPUNIT_ASSERT_GREATEREQUAL(1, pInterceptor->m_nDisabled); + + // Given a clean state: + pInterceptor->m_nEnabled = 0; + pInterceptor->m_nDisabled = 0; + + // When selecting the second image: + selectShape(2); + + // Then make sure the UNO command is enabled: + CPPUNIT_ASSERT_GREATEREQUAL(1, pInterceptor->m_nEnabled); + CPPUNIT_ASSERT_EQUAL(0, pInterceptor->m_nDisabled); + + // Given a clean state: + pInterceptor->m_nEnabled = 0; + pInterceptor->m_nDisabled = 0; + + // When selecting the first image, again (this time not changing the selection type): + selectShape(1); + + // Then make sure the UNO command is disabled: + CPPUNIT_ASSERT_EQUAL(0, pInterceptor->m_nEnabled); + // Without the accompanying fix in place, this test would have failed with: + // - Expected greater or equal than: 1 + // - Actual : 0 + // i.e. selecting the first image didn't result in a disabled UNO command. + CPPUNIT_ASSERT_GREATEREQUAL(1, pInterceptor->m_nDisabled); +} + +CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testPrintPreview) +{ + // Given a normal Writer view, in half-destroyed state, similar to what + // SfxViewFrame::SwitchToViewShell_Impl() does in practice: + createSwDoc(); + SwDocShell* pDocShell = getSwDocShell(); + SwView* pView = pDocShell->GetView(); + FmFormShell* pFormShell = pView->GetFormShell(); + pView->SetFormShell(reinterpret_cast<FmFormShell*>(-1)); + pView->SetDying(); + + // When selecting a shell, similar to what happens the doc size changes: + // Then make sure we don't crash: + pView->SelectShell(); + + // Restore the state and shut down. + pView->SetFormShell(pFormShell); +} + +CPPUNIT_PLUGIN_IMPLEMENT(); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |