1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <swmodeltestbase.hxx>
12 #include <comphelper/processfactory.hxx>
13 #include <osl/file.hxx>
14 #include <comphelper/propertyvalue.hxx>
15 #include <comphelper/scopeguard.hxx>
16 #include <vcl/scheduler.hxx>
18 #include <com/sun/star/frame/XDispatchHelper.hpp>
19 #include <com/sun/star/frame/XDispatchProvider.hpp>
20 #include <com/sun/star/frame/XComponentLoader.hpp>
21 #include <com/sun/star/frame/XStorable2.hpp>
22 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
23 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
24 #include <com/sun/star/view/XSelectionSupplier.hpp>
26 #include <unotxdoc.hxx>
29 #include <swmodule.hxx>
32 /// Covers sw/source/uibase/uiview/ fixes.
33 class SwUibaseUiviewTest
: public SwModelTestBase
37 : SwModelTestBase("/sw/qa/uibase/uiview/data/")
42 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest
, testUpdateAllObjectReplacements
)
44 // Make a temporary copy of the test document
45 createTempCopy(u
"updateall-objectreplacements.odt");
47 /* BASIC code that exhibits the problem:
49 desktop = CreateUnoService("com.sun.star.frame.Desktop")
50 Dim props(0) as new com.sun.star.beans.PropertyValue
51 props(0).Name = "Hidden"
53 component = desktop.loadComponentFromURL("file://.../test.odt", "_default", 0, props)
54 Wait 1000 ' workaround
55 dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
56 frame = component.CurrentController.Frame
57 dispatcher.executeDispatch(frame, ".uno:UpdateAll", "", 0, Array())
58 component.storeSelf(Array())
62 uno::Reference
<lang::XMultiServiceFactory
> xFactory(comphelper::getProcessServiceFactory());
65 uno::Reference
<uno::XInterface
> xInterface
66 = xFactory
->createInstance("com.sun.star.frame.Desktop");
67 uno::Reference
<frame::XComponentLoader
> xComponentLoader(xInterface
, uno::UNO_QUERY
);
68 uno::Sequence
<beans::PropertyValue
> aLoadArgs
{ comphelper::makePropertyValue("Hidden", true) };
70 = xComponentLoader
->loadComponentFromURL(maTempFile
.GetURL(), "_default", 0, aLoadArgs
);
72 // Perform the .uno:UpdateAll call and save
73 xInterface
= xFactory
->createInstance("com.sun.star.frame.DispatchHelper");
74 uno::Reference
<frame::XDispatchHelper
> xDispatchHelper(xInterface
, uno::UNO_QUERY
);
75 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
76 uno::Reference
<frame::XDispatchProvider
> xDispatchProvider(
77 xModel
->getCurrentController()->getFrame(), uno::UNO_QUERY
);
78 uno::Sequence
<beans::PropertyValue
> aNoArgs
;
79 xDispatchHelper
->executeDispatch(xDispatchProvider
, ".uno:UpdateAll", OUString(), 0, aNoArgs
);
80 uno::Reference
<frame::XStorable2
> xStorable(mxComponent
, uno::UNO_QUERY
);
81 xStorable
->storeSelf(aNoArgs
);
83 // Check the contents of the updated copy and verify that ObjectReplacements are there
84 uno::Reference
<packages::zip::XZipFileAccess2
> xNameAccess
85 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(xFactory
),
88 CPPUNIT_ASSERT(xNameAccess
->hasByName("ObjectReplacements/Components"));
89 CPPUNIT_ASSERT(xNameAccess
->hasByName("ObjectReplacements/Components_1"));
92 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest
, testUpdateReplacementNosetting
)
94 // Load a copy of the document in hidden mode.
95 OUString aSourceURL
= createFileURL(u
"update-replacement-nosetting.odt");
96 CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None
, osl::File::copy(aSourceURL
, maTempFile
.GetURL()));
97 mxComponent
= loadFromDesktop(maTempFile
.GetURL(), "com.sun.star.text.TextDocument",
98 { comphelper::makePropertyValue("Hidden", true) });
100 // Update "everything" (including object replacements) and save it.
101 dispatchCommand(mxComponent
, ".uno:UpdateAll", {});
102 uno::Reference
<frame::XStorable2
> xStorable(mxComponent
, uno::UNO_QUERY
);
103 xStorable
->storeSelf({});
105 // Check the contents of the updated copy.
106 uno::Reference
<uno::XComponentContext
> xContext
= comphelper::getProcessComponentContext();
107 uno::Reference
<packages::zip::XZipFileAccess2
> xNameAccess
108 = packages::zip::ZipFileAccess::createWithURL(xContext
, maTempFile
.GetURL());
110 // Without the accompanying fix in place, this test would have failed, because the embedded
111 // object replacement image was not generated.
112 CPPUNIT_ASSERT(xNameAccess
->hasByName("ObjectReplacements/Components"));
115 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest
, testKeepRatio
)
117 // Given a document with a custom KeepRatio:
118 OUString aURL
= createFileURL(u
"keep-ratio.fodt");
120 // When loading that document:
121 mxComponent
= loadFromDesktop(aURL
);
123 // Then make sure we read the custom value:
124 auto pXTextDocument
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
125 SwWrtShell
* pWrtShell
= pXTextDocument
->GetDocShell()->GetWrtShell();
126 const SwViewOption
* pViewOption
= pWrtShell
->GetViewOptions();
127 comphelper::ScopeGuard
g([pWrtShell
, pViewOption
] {
128 SwViewOption
aViewOption(*pViewOption
);
129 aViewOption
.SetKeepRatio(false);
130 SW_MOD()->ApplyUsrPref(aViewOption
, &pWrtShell
->GetView());
132 // Without the accompanying fix in place, this test would have failed, because KeepRatio was not
133 // mapped to settings.xml
134 CPPUNIT_ASSERT(pViewOption
->IsKeepRatio());
136 // Then export as well:
138 xmlDocUniquePtr pXmlDoc
= parseExport("settings.xml");
139 assertXPathContent(pXmlDoc
, "//config:config-item[@config:name='KeepRatio']", "true");
144 /// Interception implementation that disables .uno:Zoom on Image1, but not on Image2.
145 struct ImageInterceptor
: public cppu::WeakImplHelper
<frame::XDispatchProviderInterceptor
>
147 uno::Reference
<view::XSelectionSupplier
> m_xSelectionSupplier
;
148 uno::Reference
<frame::XDispatchProvider
> m_xMaster
;
149 uno::Reference
<frame::XDispatchProvider
> m_xSlave
;
154 ImageInterceptor(const uno::Reference
<lang::XComponent
>& xComponent
);
156 // XDispatchProviderInterceptor
157 uno::Reference
<frame::XDispatchProvider
> SAL_CALL
getMasterDispatchProvider() override
;
158 uno::Reference
<frame::XDispatchProvider
> SAL_CALL
getSlaveDispatchProvider() override
;
159 void SAL_CALL
setMasterDispatchProvider(
160 const uno::Reference
<frame::XDispatchProvider
>& xNewSupplier
) override
;
162 setSlaveDispatchProvider(const uno::Reference
<frame::XDispatchProvider
>& xNewSupplier
) override
;
165 uno::Reference
<frame::XDispatch
> SAL_CALL
queryDispatch(const util::URL
& rURL
,
166 const OUString
& rTargetFrameName
,
167 sal_Int32 SearchFlags
) override
;
168 uno::Sequence
<uno::Reference
<frame::XDispatch
>> SAL_CALL
169 queryDispatches(const uno::Sequence
<frame::DispatchDescriptor
>& rRequests
) override
;
173 ImageInterceptor::ImageInterceptor(const uno::Reference
<lang::XComponent
>& xComponent
)
175 uno::Reference
<frame::XModel2
> xModel(xComponent
, uno::UNO_QUERY
);
176 CPPUNIT_ASSERT(xModel
.is());
177 m_xSelectionSupplier
.set(xModel
->getCurrentController(), uno::UNO_QUERY
);
178 CPPUNIT_ASSERT(m_xSelectionSupplier
.is());
181 uno::Reference
<frame::XDispatchProvider
> ImageInterceptor::getMasterDispatchProvider()
186 uno::Reference
<frame::XDispatchProvider
> ImageInterceptor::getSlaveDispatchProvider()
191 void ImageInterceptor::setMasterDispatchProvider(
192 const uno::Reference
<frame::XDispatchProvider
>& xNewSupplier
)
194 m_xMaster
= xNewSupplier
;
197 void ImageInterceptor::setSlaveDispatchProvider(
198 const uno::Reference
<frame::XDispatchProvider
>& xNewSupplier
)
200 m_xSlave
= xNewSupplier
;
203 uno::Reference
<frame::XDispatch
> ImageInterceptor::queryDispatch(const util::URL
& rURL
,
204 const OUString
& rTargetFrameName
,
205 sal_Int32 nSearchFlags
)
207 // Disable the UNO command based on the currently selected image, i.e. this can't be cached when
208 // a different image is selected. Originally this was .uno:SetBorderStyle, but let's pick a
209 // command which is active when running cppunit tests:
210 if (rURL
.Complete
== ".uno:Zoom")
212 uno::Reference
<container::XNamed
> xImage
;
213 m_xSelectionSupplier
->getSelection() >>= xImage
;
214 if (xImage
.is() && xImage
->getName() == "Image1")
223 return m_xSlave
->queryDispatch(rURL
, rTargetFrameName
, nSearchFlags
);
226 uno::Sequence
<uno::Reference
<frame::XDispatch
>>
227 ImageInterceptor::queryDispatches(const uno::Sequence
<frame::DispatchDescriptor
>& /*rRequests*/)
232 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest
, testSwitchBetweenImages
)
234 // Given a document with 2 images, and an interceptor catching an UNO command that specific to
235 // the current selection:
237 SwDoc
* pDoc
= getSwDoc();
238 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
239 uno::Reference
<lang::XMultiServiceFactory
> xMSF(mxComponent
, uno::UNO_QUERY
);
240 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
241 uno::Reference
<text::XText
> xText
= xTextDocument
->getText();
242 uno::Reference
<text::XTextCursor
> xCursor
= xText
->createTextCursor();
243 for (int i
= 0; i
< 2; ++i
)
245 uno::Reference
<beans::XPropertySet
> xTextGraphic(
246 xMSF
->createInstance("com.sun.star.text.TextGraphicObject"), uno::UNO_QUERY
);
247 xTextGraphic
->setPropertyValue("AnchorType",
248 uno::Any(text::TextContentAnchorType_AS_CHARACTER
));
249 xTextGraphic
->setPropertyValue("Size", uno::Any(awt::Size(5000, 5000)));
250 uno::Reference
<text::XTextContent
> xTextContent(xTextGraphic
, uno::UNO_QUERY
);
251 xText
->insertTextContent(xCursor
, xTextContent
, false);
253 pWrtShell
->SttEndDoc(/*bStt=*/false);
254 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
255 uno::Reference
<frame::XDispatchProviderInterception
> xRegistration(
256 xModel
->getCurrentController()->getFrame(), uno::UNO_QUERY
);
257 rtl::Reference
pInterceptor(new ImageInterceptor(mxComponent
));
259 xRegistration
->registerDispatchProviderInterceptor(pInterceptor
);
260 pInterceptor
->m_nEnabled
= 0;
261 pInterceptor
->m_nDisabled
= 0;
263 // When selecting the first image:
266 // Then make sure the UNO command is disabled:
267 CPPUNIT_ASSERT_EQUAL(0, pInterceptor
->m_nEnabled
);
268 CPPUNIT_ASSERT_GREATEREQUAL(1, pInterceptor
->m_nDisabled
);
270 // Given a clean state:
271 pInterceptor
->m_nEnabled
= 0;
272 pInterceptor
->m_nDisabled
= 0;
274 // When selecting the second image:
277 // Then make sure the UNO command is enabled:
278 CPPUNIT_ASSERT_GREATEREQUAL(1, pInterceptor
->m_nEnabled
);
279 CPPUNIT_ASSERT_EQUAL(0, pInterceptor
->m_nDisabled
);
281 // Given a clean state:
282 pInterceptor
->m_nEnabled
= 0;
283 pInterceptor
->m_nDisabled
= 0;
285 // When selecting the first image, again (this time not changing the selection type):
288 // Then make sure the UNO command is disabled:
289 CPPUNIT_ASSERT_EQUAL(0, pInterceptor
->m_nEnabled
);
290 // Without the accompanying fix in place, this test would have failed with:
291 // - Expected greater or equal than: 1
293 // i.e. selecting the first image didn't result in a disabled UNO command.
294 CPPUNIT_ASSERT_GREATEREQUAL(1, pInterceptor
->m_nDisabled
);
297 CPPUNIT_PLUGIN_IMPLEMENT();
299 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */