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 <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>
32 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
33 #include <rootfrm.hxx>
34 #include <unotxdoc.hxx>
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
,
55 CPPUNIT_ASSERT(xFilter
->filter(aDescriptor
));
58 SwModelTestBase::SwModelTestBase(const OUString
& pTestDocumentPath
, const OUString
& pFilter
)
59 : UnoApiXmlTest(pTestDocumentPath
)
60 , mpXmlBuffer(nullptr)
65 void SwModelTestBase::executeLoadVerifyReloadVerify(const char* filename
, const char* pPassword
)
67 maTempFile
.EnableKillingFile(false);
69 loadURL(createFileURL(OUString::createFromAscii(filename
)), pPassword
);
71 saveAndReload(mpFilter
, pPassword
);
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);
84 SwRootFrame
* pLayout
= pDoc
->getIDocumentLayoutAccess().GetCurrentLayout();
85 pLayout
->dumpAsXml(pXmlWriter
);
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(),
102 uno::Reference
<container::XEnumeration
> xParaEnum
= xParaEnumAccess
->createEnumeration();
104 while (xParaEnum
->hasMoreElements())
106 uno::Reference
<container::XEnumerationAccess
> xRangeEnumAccess(xParaEnum
->nextElement(),
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
,
122 uno::Reference
<container::XNameAccess
> xStyleFamilies
123 = xStyleFamiliesSupplier
->getStyleFamilies();
124 uno::Reference
<container::XNameAccess
> xStyleFamily(xStyleFamilies
->getByName(aFamily
),
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
),
135 return xAutoStyleFamily
;
138 xmlDocUniquePtr
SwModelTestBase::parseLayoutDump(const uno::Reference
<lang::XComponent
>& xComponent
)
142 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(xComponent
.get());
143 CPPUNIT_ASSERT(pTextDoc
);
144 dumpLayout(pTextDoc
->GetDocShell()->GetDoc());
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;
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
,
183 int SwModelTestBase::getParagraphs(uno::Reference
<text::XText
> const& xText
)
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();
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
;
211 paraEnumAccess
.set(xText
, uno::UNO_QUERY
);
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
);
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());
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
;
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
),
268 CPPUNIT_ASSERT(xParagraph
.is());
269 if (!content
.isEmpty())
270 CPPUNIT_ASSERT_EQUAL_MESSAGE("paragraph does not contain expected content", content
,
271 xParagraph
->getString());
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
,
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());
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
);
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
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
);
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
);
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());
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
);
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(),
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
)
431 loadURL(u
"private:factory/swriter"_ustr
);
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
)
442 loadURL(u
"private:factory/swriter/web"_ustr
);
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
)
453 loadURL(u
"private:factory/swriter/GlobalDocument"_ustr
);
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
);
468 SwDocShell
* SwModelTestBase::getSwDocShell() { return getSwTextDoc()->GetDocShell(); }
470 SwXTextDocument
* SwModelTestBase::getSwTextDoc()
472 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
473 CPPUNIT_ASSERT(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");
485 xmlDocUniquePtr pXmlDoc
= parseXmlStream(&aStream
);
486 // Make sure the output is well-formed.
487 CPPUNIT_ASSERT(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
);
510 SwExportFormFieldsGuard::~SwExportFormFieldsGuard()
512 officecfg::Office::Common::Filter::PDF::Export::ExportFormFields::set(m_bValue
, m_pBatch
);
516 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */