use insert function instead of for loop
[LibreOffice.git] / sw / qa / unit / swmodeltestbase.cxx
blob69aab12a38ba00d7af431ca5da902b5e4c78ca7a
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 <com/sun/star/container/XContentEnumerationAccess.hpp>
13 #include <com/sun/star/document/XFilter.hpp>
14 #include <com/sun/star/document/XImporter.hpp>
15 #include <com/sun/star/text/XPageCursor.hpp>
16 #include <com/sun/star/view/XSelectionSupplier.hpp>
17 #include <com/sun/star/text/XTextTable.hpp>
18 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
20 #include <comphelper/propertyvalue.hxx>
21 #include <sfx2/docfile.hxx>
22 #include <rtl/ustrbuf.hxx>
23 #include <unotools/streamwrap.hxx>
24 #include <unotools/ucbstreamhelper.hxx>
25 #include <vcl/scheduler.hxx>
26 #include <comphelper/configuration.hxx>
27 #include <officecfg/Office/Writer.hxx>
28 #include <officecfg/Office/Common.hxx>
30 #include <IDocumentLayoutAccess.hxx>
31 #include <docsh.hxx>
32 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
33 #include <rootfrm.hxx>
34 #include <unotxdoc.hxx>
35 #include <view.hxx>
36 #include <viewsh.hxx>
38 using namespace css;
40 void SwModelTestBase::paste(std::u16string_view aFilename, const OUString& aInstance,
41 uno::Reference<text::XTextRange> const& xTextRange)
43 uno::Reference<document::XFilter> xFilter(m_xSFactory->createInstance(aInstance),
44 uno::UNO_QUERY_THROW);
45 uno::Reference<document::XImporter> xImporter(xFilter, uno::UNO_QUERY_THROW);
46 xImporter->setTargetDocument(mxComponent);
47 std::unique_ptr<SvStream> pStream = utl::UcbStreamHelper::CreateStream(
48 m_directories.getURLFromSrc(u"/sw/qa/extras/") + aFilename, StreamMode::STD_READ);
49 CPPUNIT_ASSERT_EQUAL(ERRCODE_NONE, pStream->GetError());
50 uno::Reference<io::XStream> xStream(new utl::OStreamWrapper(std::move(pStream)));
51 uno::Sequence aDescriptor{ comphelper::makePropertyValue(u"InputStream"_ustr, xStream),
52 comphelper::makePropertyValue(u"InsertMode"_ustr, true),
53 comphelper::makePropertyValue(u"TextInsertModeRange"_ustr,
54 xTextRange) };
55 CPPUNIT_ASSERT(xFilter->filter(aDescriptor));
58 SwModelTestBase::SwModelTestBase(const OUString& pTestDocumentPath, const OUString& pFilter)
59 : UnoApiXmlTest(pTestDocumentPath)
60 , mpXmlBuffer(nullptr)
61 , mpFilter(pFilter)
65 void SwModelTestBase::executeLoadVerifyReloadVerify(const char* filename, const char* pPassword)
67 maTempFile.EnableKillingFile(false);
68 header();
69 loadURL(createFileURL(OUString::createFromAscii(filename)), pPassword);
70 verify();
71 saveAndReload(mpFilter, pPassword);
72 verify();
73 maTempFile.EnableKillingFile();
76 void SwModelTestBase::dumpLayout(SwDoc* pDoc)
78 // create the xml writer
79 mpXmlBuffer = xmlBufferCreate();
80 xmlTextWriterPtr pXmlWriter = xmlNewTextWriterMemory(mpXmlBuffer, 0);
81 (void)xmlTextWriterStartDocument(pXmlWriter, nullptr, nullptr, nullptr);
83 // create the dump
84 SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
85 pLayout->dumpAsXml(pXmlWriter);
87 // delete xml writer
88 (void)xmlTextWriterEndDocument(pXmlWriter);
89 xmlFreeTextWriter(pXmlWriter);
92 void SwModelTestBase::calcLayout()
94 getSwDoc()->getIDocumentLayoutAccess().GetCurrentViewShell()->CalcLayout();
97 OUString SwModelTestBase::getBodyText() const
99 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
100 uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xTextDocument->getText(),
101 uno::UNO_QUERY);
102 uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
103 OUStringBuffer aBuf;
104 while (xParaEnum->hasMoreElements())
106 uno::Reference<container::XEnumerationAccess> xRangeEnumAccess(xParaEnum->nextElement(),
107 uno::UNO_QUERY);
108 uno::Reference<container::XEnumeration> xRangeEnum = xRangeEnumAccess->createEnumeration();
109 while (xRangeEnum->hasMoreElements())
111 uno::Reference<text::XTextRange> xRange(xRangeEnum->nextElement(), uno::UNO_QUERY);
112 aBuf.append(xRange->getString());
115 return aBuf.makeStringAndClear();
118 uno::Reference<container::XNameAccess> SwModelTestBase::getStyles(const OUString& aFamily)
120 uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(mxComponent,
121 uno::UNO_QUERY);
122 uno::Reference<container::XNameAccess> xStyleFamilies
123 = xStyleFamiliesSupplier->getStyleFamilies();
124 uno::Reference<container::XNameAccess> xStyleFamily(xStyleFamilies->getByName(aFamily),
125 uno::UNO_QUERY);
126 return xStyleFamily;
129 uno::Reference<style::XAutoStyleFamily> SwModelTestBase::getAutoStyles(const OUString& aFamily)
131 uno::Reference<style::XAutoStylesSupplier> xAutoStylesSupplier(mxComponent, uno::UNO_QUERY);
132 uno::Reference<style::XAutoStyles> xAutoStyles(xAutoStylesSupplier->getAutoStyles());
133 uno::Reference<style::XAutoStyleFamily> xAutoStyleFamily(xAutoStyles->getByName(aFamily),
134 uno::UNO_QUERY);
135 return xAutoStyleFamily;
138 xmlDocUniquePtr SwModelTestBase::parseLayoutDump(const uno::Reference<lang::XComponent>& xComponent)
140 if (xComponent)
142 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(xComponent.get());
143 CPPUNIT_ASSERT(pTextDoc);
144 dumpLayout(pTextDoc->GetDocShell()->GetDoc());
146 else
147 dumpLayout(getSwDoc());
149 auto pBuffer = reinterpret_cast<const char*>(xmlBufferContent(mpXmlBuffer));
150 SAL_INFO("sw.qa", "SwModelTestBase::parseLayoutDump: pBuffer is '" << pBuffer << "'");
151 xmlDocUniquePtr pXmlDoc(xmlParseMemory(pBuffer, xmlBufferLength(mpXmlBuffer)));
153 // Discard dumped layout
154 xmlBufferFree(mpXmlBuffer);
155 mpXmlBuffer = nullptr;
157 return pXmlDoc;
160 bool SwModelTestBase::hasProperty(const uno::Reference<uno::XInterface>& obj,
161 const OUString& name) const
163 uno::Reference<beans::XPropertySet> properties(obj, uno::UNO_QUERY_THROW);
164 return properties->getPropertySetInfo()->hasPropertyByName(name);
167 xml::AttributeData SwModelTestBase::getUserDefineAttribute(const uno::Any& obj,
168 const OUString& name,
169 const OUString& rValue) const
171 uno::Reference<container::XNameContainer> attrsCnt(
172 getProperty<uno::Any>(obj, u"UserDefinedAttributes"_ustr), uno::UNO_QUERY_THROW);
174 xml::AttributeData aValue;
175 attrsCnt->getByName(name) >>= aValue;
176 if (!rValue.isEmpty())
177 CPPUNIT_ASSERT_EQUAL_MESSAGE("attribute of cell does not contain expected value", rValue,
178 aValue.Value);
180 return aValue;
183 int SwModelTestBase::getParagraphs(uno::Reference<text::XText> const& xText)
185 int nRet = 0;
186 if (!xText.is())
187 return nRet;
189 uno::Reference<container::XEnumerationAccess> xParaEnumAccess(xText->getText(), uno::UNO_QUERY);
190 uno::Reference<container::XEnumeration> xParaEnum = xParaEnumAccess->createEnumeration();
191 while (xParaEnum->hasMoreElements())
193 xParaEnum->nextElement();
194 nRet++;
196 return nRet;
199 int SwModelTestBase::getParagraphs()
201 uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
202 return getParagraphs(xTextDocument->getText());
205 uno::Reference<text::XTextContent>
206 SwModelTestBase::getParagraphOrTable(int number, uno::Reference<text::XText> const& xText) const
208 assert(number != 0); // this thing is 1-based
209 uno::Reference<container::XEnumerationAccess> paraEnumAccess;
210 if (xText.is())
211 paraEnumAccess.set(xText, uno::UNO_QUERY);
212 else
214 uno::Reference<text::XTextDocument> textDocument(mxComponent, uno::UNO_QUERY);
215 paraEnumAccess.set(textDocument->getText(), uno::UNO_QUERY);
217 uno::Reference<container::XEnumeration> paraEnum = paraEnumAccess->createEnumeration();
218 for (int i = 1; i < number; ++i)
219 paraEnum->nextElement();
220 uno::Reference<text::XTextContent> const xElem(paraEnum->nextElement(), uno::UNO_QUERY_THROW);
221 return xElem;
224 uno::Reference<text::XTextRange> SwModelTestBase::getParagraph(int number,
225 const OUString& content) const
227 uno::Reference<text::XTextRange> const xParagraph(getParagraphOrTable(number),
228 uno::UNO_QUERY_THROW);
229 if (!content.isEmpty())
230 CPPUNIT_ASSERT_EQUAL_MESSAGE("paragraph does not have expected content", content,
231 xParagraph->getString());
232 return xParagraph;
235 sal_Int16 SwModelTestBase::getNumberingTypeOfParagraph(int nPara)
237 sal_Int16 nNumberingType = -1;
238 uno::Reference<text::XTextRange> xPara(getParagraph(nPara));
239 uno::Reference<beans::XPropertySet> properties(xPara, uno::UNO_QUERY);
240 bool isNumber = false;
241 properties->getPropertyValue(u"NumberingIsNumber"_ustr) >>= isNumber;
242 if (isNumber)
244 uno::Reference<container::XIndexAccess> xLevels(
245 properties->getPropertyValue(u"NumberingRules"_ustr), uno::UNO_QUERY);
246 sal_Int16 nNumberingLevel = -1;
247 properties->getPropertyValue(u"NumberingLevel"_ustr) >>= nNumberingLevel;
248 if (nNumberingLevel >= 0 && nNumberingLevel < xLevels->getCount())
250 uno::Sequence<beans::PropertyValue> aPropertyValue;
251 xLevels->getByIndex(nNumberingLevel) >>= aPropertyValue;
252 auto pProp = std::find_if(
253 std::cbegin(aPropertyValue), std::cend(aPropertyValue),
254 [](const beans::PropertyValue& rProp) { return rProp.Name == "NumberingType"; });
255 if (pProp != std::cend(aPropertyValue))
256 nNumberingType = pProp->Value.get<sal_Int16>();
259 return nNumberingType;
262 uno::Reference<text::XTextRange>
263 SwModelTestBase::getParagraphOfText(int number, uno::Reference<text::XText> const& xText,
264 const OUString& content) const
266 uno::Reference<text::XTextRange> const xParagraph(getParagraphOrTable(number, xText),
267 uno::UNO_QUERY);
268 CPPUNIT_ASSERT(xParagraph.is());
269 if (!content.isEmpty())
270 CPPUNIT_ASSERT_EQUAL_MESSAGE("paragraph does not contain expected content", content,
271 xParagraph->getString());
272 return xParagraph;
275 uno::Reference<beans::XPropertySet>
276 SwModelTestBase::getParagraphAnchoredObject(int const index,
277 uno::Reference<text::XTextRange> const& xPara) const
279 uno::Reference<container::XContentEnumerationAccess> xContentEnumAccess(xPara, uno::UNO_QUERY);
280 uno::Reference<container::XEnumeration> xContentEnum
281 = xContentEnumAccess->createContentEnumeration(u"com.sun.star.text.TextContent"_ustr);
282 for (int i = 1; i < index; ++i)
284 xContentEnum->nextElement();
286 return uno::Reference<beans::XPropertySet>(xContentEnum->nextElement(), uno::UNO_QUERY);
289 uno::Reference<text::XTextRange>
290 SwModelTestBase::getRun(uno::Reference<text::XTextRange> const& xParagraph, int number,
291 const OUString& content) const
293 uno::Reference<container::XEnumerationAccess> xRunEnumAccess(xParagraph, uno::UNO_QUERY);
294 uno::Reference<container::XEnumeration> xRunEnum = xRunEnumAccess->createEnumeration();
295 for (int i = 1; i < number; ++i)
296 xRunEnum->nextElement();
297 uno::Reference<text::XTextRange> xRun(xRunEnum->nextElement(), uno::UNO_QUERY);
298 if (!content.isEmpty())
299 CPPUNIT_ASSERT_EQUAL_MESSAGE("run does not contain expected content", content,
300 xRun->getString());
301 return xRun;
304 OUString SwModelTestBase::getFormula(uno::Reference<text::XTextRange> const& xRun) const
306 uno::Reference<container::XContentEnumerationAccess> xContentEnumAccess(xRun, uno::UNO_QUERY);
307 uno::Reference<container::XEnumeration> xContentEnum
308 = xContentEnumAccess->createContentEnumeration(u""_ustr);
309 uno::Reference<beans::XPropertySet> xFormula(xContentEnum->nextElement(), uno::UNO_QUERY);
310 return getProperty<OUString>(
311 getProperty<uno::Reference<beans::XPropertySet>>(xFormula, u"Model"_ustr), u"Formula"_ustr);
314 uno::Reference<table::XCell>
315 SwModelTestBase::getCell(uno::Reference<uno::XInterface> const& xTableIfc, OUString const& rCell,
316 OUString const& rContent)
318 uno::Reference<text::XTextTable> const xTable(xTableIfc, uno::UNO_QUERY_THROW);
319 uno::Reference<table::XCell> const xCell(xTable->getCellByName(rCell), uno::UNO_SET_THROW);
320 if (!rContent.isEmpty())
322 uno::Reference<text::XText> const xCellText(xCell, uno::UNO_QUERY_THROW);
323 CPPUNIT_ASSERT_EQUAL_MESSAGE("cell does not contain expected content", rContent,
324 xCellText->getString());
326 return xCell;
329 uno::Reference<drawing::XShape> SwModelTestBase::getShape(int number)
331 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
332 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
333 uno::Reference<drawing::XShape> xShape(xDrawPage->getByIndex(number - 1), uno::UNO_QUERY);
334 return xShape;
337 void SwModelTestBase::selectShape(int number)
339 uno::Reference<view::XSelectionSupplier> xSelectionSupplier(
340 getSwTextDoc()->getCurrentController(), uno::UNO_QUERY);
341 xSelectionSupplier->select(uno::Any(getShape(number)));
342 CPPUNIT_ASSERT(xSelectionSupplier->getSelection().hasValue());
344 SwView* pView = getSwDocShell()->GetView();
345 // Make sure SwTextShell is replaced with SwDrawShell right now, not after 120 ms, as set in the
346 // SwView ctor.
347 pView->StopShellTimer();
350 uno::Reference<drawing::XShape> SwModelTestBase::getShapeByName(std::u16string_view aName)
352 uno::Reference<drawing::XShape> xRet;
354 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
355 uno::Reference<drawing::XDrawPage> xDrawPage = xDrawPageSupplier->getDrawPage();
356 for (sal_Int32 i = 0; i < xDrawPage->getCount(); ++i)
358 uno::Reference<container::XNamed> xShape(xDrawPage->getByIndex(i), uno::UNO_QUERY);
359 if (xShape->getName() == aName)
361 xRet.set(xShape, uno::UNO_QUERY);
362 break;
366 return xRet;
369 uno::Reference<drawing::XShape> SwModelTestBase::getTextFrameByName(const OUString& aName)
371 uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
372 uno::Reference<container::XNameAccess> xNameAccess = xTextFramesSupplier->getTextFrames();
373 uno::Reference<drawing::XShape> xShape(xNameAccess->getByName(aName), uno::UNO_QUERY);
374 return xShape;
377 void SwModelTestBase::header() {}
379 void SwModelTestBase::loadURL(OUString const& rURL, const char* pPassword)
381 // Output name at load time, so in the case of a hang, the name of the hanging input file is visible.
382 std::cout << rURL << ":\n";
384 loadFromURL(rURL, pPassword);
386 CPPUNIT_ASSERT(!getSwDocShell()->GetMedium()->GetWarningError());
388 calcLayout();
391 void SwModelTestBase::saveAndReload(const OUString& pFilter, const char* pPassword)
393 save(pFilter, pPassword);
395 loadURL(maTempFile.GetURL(), pPassword);
398 void SwModelTestBase::loadAndSave(const char* pName, const char* pPassword)
400 loadURL(createFileURL(OUString::createFromAscii(pName)), pPassword);
401 save(mpFilter);
404 void SwModelTestBase::loadAndReload(const char* pName)
406 loadURL(createFileURL(OUString::createFromAscii(pName)));
407 saveAndReload(mpFilter);
410 int SwModelTestBase::getPages() const
412 uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
413 uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
414 xModel->getCurrentController(), uno::UNO_QUERY);
415 uno::Reference<text::XPageCursor> xCursor(xTextViewCursorSupplier->getViewCursor(),
416 uno::UNO_QUERY);
417 xCursor->jumpToLastPage();
418 return xCursor->getPage();
421 int SwModelTestBase::getShapes() const
423 uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, uno::UNO_QUERY);
424 uno::Reference<container::XIndexAccess> xDraws = xDrawPageSupplier->getDrawPage();
425 return xDraws->getCount();
428 void SwModelTestBase::createSwDoc(const char* pName, const char* pPassword)
430 if (!pName)
431 loadURL(u"private:factory/swriter"_ustr);
432 else
433 loadURL(createFileURL(OUString::createFromAscii(pName)), pPassword);
435 uno::Reference<lang::XServiceInfo> xServiceInfo(mxComponent, uno::UNO_QUERY_THROW);
436 CPPUNIT_ASSERT(xServiceInfo->supportsService(u"com.sun.star.text.TextDocument"_ustr));
439 void SwModelTestBase::createSwWebDoc(const char* pName)
441 if (!pName)
442 loadURL(u"private:factory/swriter/web"_ustr);
443 else
444 loadURL(createFileURL(OUString::createFromAscii(pName)));
446 uno::Reference<lang::XServiceInfo> xServiceInfo(mxComponent, uno::UNO_QUERY_THROW);
447 CPPUNIT_ASSERT(xServiceInfo->supportsService(u"com.sun.star.text.WebDocument"_ustr));
450 void SwModelTestBase::createSwGlobalDoc(const char* pName)
452 if (!pName)
453 loadURL(u"private:factory/swriter/GlobalDocument"_ustr);
454 else
455 loadURL(createFileURL(OUString::createFromAscii(pName)));
457 uno::Reference<lang::XServiceInfo> xServiceInfo(mxComponent, uno::UNO_QUERY_THROW);
458 CPPUNIT_ASSERT(xServiceInfo->supportsService(u"com.sun.star.text.GlobalDocument"_ustr));
461 SwDoc* SwModelTestBase::getSwDoc()
463 SwDoc* pDoc = getSwDocShell()->GetDoc();
464 CPPUNIT_ASSERT(pDoc);
465 return pDoc;
468 SwDocShell* SwModelTestBase::getSwDocShell() { return getSwTextDoc()->GetDocShell(); }
470 SwXTextDocument* SwModelTestBase::getSwTextDoc()
472 SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
473 CPPUNIT_ASSERT(pTextDoc);
474 return pTextDoc;
477 xmlDocUniquePtr SwModelTestBase::WrapReqifFromTempFile()
479 SvMemoryStream aStream;
480 aStream.WriteOString("<reqif-xhtml:html xmlns:reqif-xhtml=\"http://www.w3.org/1999/xhtml\">\n");
481 SvFileStream aFileStream(maTempFile.GetURL(), StreamMode::READ);
482 aStream.WriteStream(aFileStream);
483 aStream.WriteOString("</reqif-xhtml:html>\n");
484 aStream.Seek(0);
485 xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
486 // Make sure the output is well-formed.
487 CPPUNIT_ASSERT(pXmlDoc);
488 return pXmlDoc;
491 void SwModelTestBase::emulateTyping(std::u16string_view rStr)
493 SwXTextDocument* pTextDoc = getSwTextDoc();
494 for (const char16_t c : rStr)
496 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYINPUT, c, 0);
497 pTextDoc->postKeyEvent(LOK_KEYEVENT_KEYUP, c, 0);
498 Scheduler::ProcessEventsToIdle();
502 SwExportFormFieldsGuard::SwExportFormFieldsGuard()
504 m_pBatch = comphelper::ConfigurationChanges::create();
505 m_bValue = officecfg::Office::Common::Filter::PDF::Export::ExportFormFields::get();
506 officecfg::Office::Common::Filter::PDF::Export::ExportFormFields::set(true, m_pBatch);
507 m_pBatch->commit();
510 SwExportFormFieldsGuard::~SwExportFormFieldsGuard()
512 officecfg::Office::Common::Filter::PDF::Export::ExportFormFields::set(m_bValue, m_pBatch);
513 m_pBatch->commit();
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */