docthemes: Save themes def. to a file when added to ColorSets
[LibreOffice.git] / sw / qa / uibase / uiview / uiview.cxx
blob5f41aa920c02f4ab3bbe9ca4317a08cc86e6b7d8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
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>
17 #include <sfx2/viewfrm.hxx>
18 #include <sfx2/dispatch.hxx>
20 #include <com/sun/star/frame/XDispatchHelper.hpp>
21 #include <com/sun/star/frame/XDispatchProvider.hpp>
22 #include <com/sun/star/frame/XComponentLoader.hpp>
23 #include <com/sun/star/frame/XStorable2.hpp>
24 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
25 #include <com/sun/star/packages/zip/ZipFileAccess.hpp>
26 #include <com/sun/star/view/XSelectionSupplier.hpp>
27 #include <com/sun/star/text/XParagraphCursor.hpp>
29 #include <cmdid.h>
30 #include <unotxdoc.hxx>
31 #include <docsh.hxx>
32 #include <wrtsh.hxx>
33 #include <swmodule.hxx>
34 #include <view.hxx>
36 /// Covers sw/source/uibase/uiview/ fixes.
37 class SwUibaseUiviewTest : public SwModelTestBase
39 public:
40 SwUibaseUiviewTest()
41 : SwModelTestBase(u"/sw/qa/uibase/uiview/data/"_ustr)
46 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testUpdateAllObjectReplacements)
48 // Make a temporary copy of the test document
49 createTempCopy(u"updateall-objectreplacements.odt");
51 /* BASIC code that exhibits the problem:
53 desktop = CreateUnoService("com.sun.star.frame.Desktop")
54 Dim props(0) as new com.sun.star.beans.PropertyValue
55 props(0).Name = "Hidden"
56 props(0).Value = true
57 component = desktop.loadComponentFromURL("file://.../test.odt", "_default", 0, props)
58 Wait 1000 ' workaround
59 dispatcher = createUnoService("com.sun.star.frame.DispatchHelper")
60 frame = component.CurrentController.Frame
61 dispatcher.executeDispatch(frame, ".uno:UpdateAll", "", 0, Array())
62 component.storeSelf(Array())
63 component.dispose()
66 uno::Reference<lang::XMultiServiceFactory> xFactory(comphelper::getProcessServiceFactory());
68 // Load the copy
69 uno::Reference<uno::XInterface> xInterface
70 = xFactory->createInstance(u"com.sun.star.frame.Desktop"_ustr);
71 uno::Reference<frame::XComponentLoader> xComponentLoader(xInterface, uno::UNO_QUERY);
72 uno::Sequence<beans::PropertyValue> aLoadArgs{ comphelper::makePropertyValue(u"Hidden"_ustr,
73 true) };
74 mxComponent = xComponentLoader->loadComponentFromURL(maTempFile.GetURL(), u"_default"_ustr, 0,
75 aLoadArgs);
77 // Perform the .uno:UpdateAll call and save
78 xInterface = xFactory->createInstance(u"com.sun.star.frame.DispatchHelper"_ustr);
79 uno::Reference<frame::XDispatchHelper> xDispatchHelper(xInterface, uno::UNO_QUERY);
80 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
81 uno::Reference<frame::XDispatchProvider> xDispatchProvider(
82 xModel->getCurrentController()->getFrame(), uno::UNO_QUERY);
83 uno::Sequence<beans::PropertyValue> aNoArgs;
84 xDispatchHelper->executeDispatch(xDispatchProvider, u".uno:UpdateAll"_ustr, OUString(), 0,
85 aNoArgs);
86 uno::Reference<frame::XStorable2> xStorable(mxComponent, uno::UNO_QUERY);
87 xStorable->storeSelf(aNoArgs);
89 // Check the contents of the updated copy and verify that ObjectReplacements are there
90 uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
91 = packages::zip::ZipFileAccess::createWithURL(comphelper::getComponentContext(xFactory),
92 maTempFile.GetURL());
94 CPPUNIT_ASSERT(xNameAccess->hasByName(u"ObjectReplacements/Components"_ustr));
95 CPPUNIT_ASSERT(xNameAccess->hasByName(u"ObjectReplacements/Components_1"_ustr));
98 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testUpdateReplacementNosetting)
100 // Load a copy of the document in hidden mode.
101 OUString aSourceURL = createFileURL(u"update-replacement-nosetting.odt");
102 CPPUNIT_ASSERT_EQUAL(osl::FileBase::E_None, osl::File::copy(aSourceURL, maTempFile.GetURL()));
103 loadWithParams(maTempFile.GetURL(), { comphelper::makePropertyValue(u"Hidden"_ustr, true) });
105 // Update "everything" (including object replacements) and save it.
106 dispatchCommand(mxComponent, u".uno:UpdateAll"_ustr, {});
107 uno::Reference<frame::XStorable2> xStorable(mxComponent, uno::UNO_QUERY);
108 xStorable->storeSelf({});
110 // Check the contents of the updated copy.
111 uno::Reference<uno::XComponentContext> xContext = comphelper::getProcessComponentContext();
112 uno::Reference<packages::zip::XZipFileAccess2> xNameAccess
113 = packages::zip::ZipFileAccess::createWithURL(xContext, maTempFile.GetURL());
115 // Without the accompanying fix in place, this test would have failed, because the embedded
116 // object replacement image was not generated.
117 CPPUNIT_ASSERT(xNameAccess->hasByName(u"ObjectReplacements/Components"_ustr));
120 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testKeepRatio)
122 // Given a document with a custom KeepRatio:
123 createSwDoc("keep-ratio.fodt");
125 // Then make sure we read the custom value:
126 SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
127 const SwViewOption* pViewOption = pWrtShell->GetViewOptions();
128 comphelper::ScopeGuard g([pWrtShell, pViewOption] {
129 SwViewOption aViewOption(*pViewOption);
130 aViewOption.SetKeepRatio(false);
131 SwModule::get()->ApplyUsrPref(aViewOption, &pWrtShell->GetView());
133 // Without the accompanying fix in place, this test would have failed, because KeepRatio was not
134 // mapped to settings.xml
135 CPPUNIT_ASSERT(pViewOption->IsKeepRatio());
137 // Then export as well:
138 save(u"writer8"_ustr);
139 xmlDocUniquePtr pXmlDoc = parseExport(u"settings.xml"_ustr);
140 assertXPathContent(pXmlDoc, "//config:config-item[@config:name='KeepRatio']", u"true");
143 namespace
145 /// Interception implementation that disables .uno:Zoom on Image1, but not on Image2.
146 struct ImageInterceptor : public cppu::WeakImplHelper<frame::XDispatchProviderInterceptor>
148 uno::Reference<view::XSelectionSupplier> m_xSelectionSupplier;
149 uno::Reference<frame::XDispatchProvider> m_xMaster;
150 uno::Reference<frame::XDispatchProvider> m_xSlave;
151 int m_nEnabled = 0;
152 int m_nDisabled = 0;
154 public:
155 ImageInterceptor(const uno::Reference<lang::XComponent>& xComponent);
157 // XDispatchProviderInterceptor
158 uno::Reference<frame::XDispatchProvider> SAL_CALL getMasterDispatchProvider() override;
159 uno::Reference<frame::XDispatchProvider> SAL_CALL getSlaveDispatchProvider() override;
160 void SAL_CALL setMasterDispatchProvider(
161 const uno::Reference<frame::XDispatchProvider>& xNewSupplier) override;
162 void SAL_CALL
163 setSlaveDispatchProvider(const uno::Reference<frame::XDispatchProvider>& xNewSupplier) override;
165 // XDispatchProvider
166 uno::Reference<frame::XDispatch> SAL_CALL queryDispatch(const util::URL& rURL,
167 const OUString& rTargetFrameName,
168 sal_Int32 SearchFlags) override;
169 uno::Sequence<uno::Reference<frame::XDispatch>> SAL_CALL
170 queryDispatches(const uno::Sequence<frame::DispatchDescriptor>& rRequests) override;
174 ImageInterceptor::ImageInterceptor(const uno::Reference<lang::XComponent>& xComponent)
176 uno::Reference<frame::XModel2> xModel(xComponent, uno::UNO_QUERY);
177 CPPUNIT_ASSERT(xModel.is());
178 m_xSelectionSupplier.set(xModel->getCurrentController(), uno::UNO_QUERY);
179 CPPUNIT_ASSERT(m_xSelectionSupplier.is());
182 uno::Reference<frame::XDispatchProvider> ImageInterceptor::getMasterDispatchProvider()
184 return m_xMaster;
187 uno::Reference<frame::XDispatchProvider> ImageInterceptor::getSlaveDispatchProvider()
189 return m_xSlave;
192 void ImageInterceptor::setMasterDispatchProvider(
193 const uno::Reference<frame::XDispatchProvider>& xNewSupplier)
195 m_xMaster = xNewSupplier;
198 void ImageInterceptor::setSlaveDispatchProvider(
199 const uno::Reference<frame::XDispatchProvider>& xNewSupplier)
201 m_xSlave = xNewSupplier;
204 uno::Reference<frame::XDispatch> ImageInterceptor::queryDispatch(const util::URL& rURL,
205 const OUString& rTargetFrameName,
206 sal_Int32 nSearchFlags)
208 // Disable the UNO command based on the currently selected image, i.e. this can't be cached when
209 // a different image is selected. Originally this was .uno:SetBorderStyle, but let's pick a
210 // command which is active when running cppunit tests:
211 if (rURL.Complete == ".uno:Zoom")
213 uno::Reference<container::XNamed> xImage;
214 m_xSelectionSupplier->getSelection() >>= xImage;
215 if (xImage.is() && xImage->getName() == "Image1")
217 ++m_nDisabled;
218 return {};
221 ++m_nEnabled;
224 return m_xSlave->queryDispatch(rURL, rTargetFrameName, nSearchFlags);
227 uno::Sequence<uno::Reference<frame::XDispatch>>
228 ImageInterceptor::queryDispatches(const uno::Sequence<frame::DispatchDescriptor>& /*rRequests*/)
230 return {};
233 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testSwitchBetweenImages)
235 // Given a document with 2 images, and an interceptor catching an UNO command that specific to
236 // the current selection:
237 createSwDoc();
238 SwWrtShell* pWrtShell = getSwDocShell()->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(u"com.sun.star.text.TextGraphicObject"_ustr), uno::UNO_QUERY);
247 xTextGraphic->setPropertyValue(u"AnchorType"_ustr,
248 uno::Any(text::TextContentAnchorType_AS_CHARACTER));
249 xTextGraphic->setPropertyValue(u"Size"_ustr, 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:
264 selectShape(1);
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:
275 selectShape(2);
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):
286 selectShape(1);
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
292 // - Actual : 0
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_TEST_FIXTURE(SwUibaseUiviewTest, testPrintPreview)
299 // Given a normal Writer view, in half-destroyed state, similar to what
300 // SfxViewFrame::SwitchToViewShell_Impl() does in practice:
301 createSwDoc();
302 SwDocShell* pDocShell = getSwDocShell();
303 SwView* pView = pDocShell->GetView();
304 FmFormShell* pFormShell = pView->GetFormShell();
305 pView->SetFormShell(reinterpret_cast<FmFormShell*>(-1));
306 pView->SetDying();
308 // When selecting a shell, similar to what happens the doc size changes:
309 // Then make sure we don't crash:
310 pView->SelectShell();
312 // Restore the state and shut down.
313 pView->SetFormShell(pFormShell);
316 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, TestTdf152839_Formtext)
318 createSwDoc("tdf152839_formtext.rtf");
320 xmlDocUniquePtr pXmlDoc = parseLayoutDump();
321 sal_Int32 nHeight
322 = getXPath(pXmlDoc, "/root/page[1]/body/tab[1]/row[2]/cell[1]/txt/infos/bounds", "height")
323 .toInt32();
324 CPPUNIT_ASSERT_EQUAL(sal_Int32(723), nHeight);
327 CPPUNIT_TEST_FIXTURE(SwUibaseUiviewTest, testEditInReadonly)
329 createSwDoc("editinsection.odt");
331 SwDocShell* pDocShell = getSwDocShell();
332 SwView* pView = pDocShell->GetView();
334 pView->GetViewFrame().GetDispatcher()->Execute(SID_EDITDOC, SfxCallMode::SYNCHRON);
336 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
337 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
338 uno::Reference<text::XParagraphCursor> xParaCursor(xTextDocument->getText()->createTextCursor(),
339 uno::UNO_QUERY);
341 uno::Reference<view::XSelectionSupplier> xSelSupplier(xModel->getCurrentController(),
342 uno::UNO_QUERY_THROW);
344 xSelSupplier->select(css::uno::Any(xParaCursor));
345 std::unique_ptr<SfxPoolItem> pItem;
346 SfxItemState eState = pView->GetViewFrame().GetBindings().QueryState(FN_INSERT_TABLE, pItem);
347 //status disabled in read only content
348 CPPUNIT_ASSERT_EQUAL(SfxItemState::DISABLED, eState);
350 //move cursor to section
351 xParaCursor->gotoNextParagraph(false);
352 xSelSupplier->select(css::uno::Any(xParaCursor));
353 eState = pView->GetViewFrame().GetBindings().QueryState(FN_INSERT_TABLE, pItem);
354 //status default in editable section
355 CPPUNIT_ASSERT_EQUAL(SfxItemState::DEFAULT, eState);
357 CPPUNIT_PLUGIN_IMPLEMENT();
359 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */