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/awt/XBitmap.hpp>
13 #include <com/sun/star/graphic/XGraphic.hpp>
14 #include <com/sun/star/graphic/GraphicType.hpp>
15 #include <com/sun/star/text/ControlCharacter.hpp>
16 #include <com/sun/star/text/XText.hpp>
17 #include <com/sun/star/text/XDocumentIndex.hpp>
18 #include <o3tl/safeint.hxx>
19 #include <o3tl/string_view.hxx>
20 #include <officecfg/Office/Common.hxx>
21 #include <tools/zcodec.hxx>
22 #include <vcl/filter/pdfdocument.hxx>
23 #include <sfx2/linkmgr.hxx>
24 #include <comphelper/propertysequence.hxx>
25 #include <unotxdoc.hxx>
28 #include <IDocumentRedlineAccess.hxx>
29 #include <IDocumentContentOperations.hxx>
33 #include <ndindex.hxx>
35 #include <unotools/fltrcfg.hxx>
36 #include <xmloff/odffields.hxx>
37 #include <IDocumentMarkAccess.hxx>
39 #include <com/sun/star/awt/FontWeight.hpp>
40 #include <unotools/mediadescriptor.hxx>
42 class Test
: public SwModelTestBase
45 Test() : SwModelTestBase("/sw/qa/extras/globalfilter/data/") {}
47 void testEmbeddedGraphicRoundtrip();
48 void testLinkedGraphicRT();
49 void testImageWithSpecialID();
50 void testGraphicShape();
51 void testMultipleIdenticalGraphics();
52 void testCharHighlight();
53 void testCharHighlightODF();
54 void testCharHighlightBody();
55 void testCharStyleHighlight();
56 void testMSCharBackgroundEditing();
57 void testCharBackgroundToHighlighting();
59 void testSkipImages();
61 void testNestedFieldmark();
62 void verifyText13(char const*);
64 void testRedlineFlags();
65 void testBulletAsImage();
66 void testTextFormField();
67 void testCheckBoxFormField();
68 void testDropDownFormField();
69 void testDateFormField();
70 void testDateFormFieldCharacterFormatting();
72 CPPUNIT_TEST_SUITE(Test
);
73 CPPUNIT_TEST(testEmbeddedGraphicRoundtrip
);
74 CPPUNIT_TEST(testLinkedGraphicRT
);
75 CPPUNIT_TEST(testImageWithSpecialID
);
76 CPPUNIT_TEST(testGraphicShape
);
77 CPPUNIT_TEST(testMultipleIdenticalGraphics
);
78 CPPUNIT_TEST(testCharHighlight
);
79 CPPUNIT_TEST(testCharHighlightODF
);
80 CPPUNIT_TEST(testMSCharBackgroundEditing
);
81 CPPUNIT_TEST(testCharBackgroundToHighlighting
);
83 CPPUNIT_TEST(testSkipImages
);
85 CPPUNIT_TEST(testNestedFieldmark
);
86 CPPUNIT_TEST(testODF13
);
87 CPPUNIT_TEST(testRedlineFlags
);
88 CPPUNIT_TEST(testBulletAsImage
);
89 CPPUNIT_TEST(testTextFormField
);
90 CPPUNIT_TEST(testCheckBoxFormField
);
91 CPPUNIT_TEST(testDropDownFormField
);
92 CPPUNIT_TEST(testDateFormField
);
93 CPPUNIT_TEST(testDateFormFieldCharacterFormatting
);
94 CPPUNIT_TEST_SUITE_END();
97 void Test::testEmbeddedGraphicRoundtrip()
99 OUString aFilterNames
[] = {
103 "Office Open XML Text",
106 for (OUString
const & rFilterName
: aFilterNames
)
108 // Check whether the export code swaps in the image which was swapped out before by auto mechanism
110 createSwDoc("document_with_two_images.odt");
112 // Export the document and import again for a check
113 saveAndReload(rFilterName
);
115 // Check whether graphic exported well after it was swapped out
116 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
117 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), 2, getShapes());
120 uno::Reference
<drawing::XShape
> xImage(getShape(1), uno::UNO_QUERY
);
121 uno::Reference
< beans::XPropertySet
> XPropSet( xImage
, uno::UNO_QUERY_THROW
);
123 // Check graphic, size
125 uno::Reference
<graphic::XGraphic
> xGraphic
;
126 XPropSet
->getPropertyValue("Graphic") >>= xGraphic
;
127 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xGraphic
.is());
128 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), graphic::GraphicType::PIXEL
, xGraphic
->getType());
129 uno::Reference
<awt::XBitmap
> xBitmap(xGraphic
, uno::UNO_QUERY
);
130 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
131 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(610), xBitmap
->getSize().Width
);
132 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(381), xBitmap
->getSize().Height
);
136 xImage
.set(getShape(2), uno::UNO_QUERY
);
137 XPropSet
.set( xImage
, uno::UNO_QUERY_THROW
);
139 // Check graphic, size
141 uno::Reference
<graphic::XGraphic
> xGraphic
;
142 XPropSet
->getPropertyValue("Graphic") >>= xGraphic
;
143 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xGraphic
.is());
144 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), graphic::GraphicType::PIXEL
, xGraphic
->getType());
145 uno::Reference
<awt::XBitmap
> xBitmap(xGraphic
, uno::UNO_QUERY
);
146 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
147 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(900), xBitmap
->getSize().Width
);
148 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(600), xBitmap
->getSize().Height
);
153 void Test::testLinkedGraphicRT()
155 const OUString aFilterNames
[] = {
157 // "Rich Text Format", Note: picture is there, but SwGrfNode is not found?
159 "Office Open XML Text",
162 for (OUString
const & rFilterName
: aFilterNames
)
164 createSwDoc("document_with_linked_graphic.odt");
166 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
168 // Export the document and import again for a check
169 saveAndReload(rFilterName
);
171 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
172 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pTextDoc
);
173 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
174 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pDoc
);
175 SwNodes
& aNodes
= pDoc
->GetNodes();
178 bool bImageFound
= false;
180 for (SwNodeOffset
nIndex(0); nIndex
< aNodes
.Count(); ++nIndex
)
182 if (aNodes
[nIndex
]->IsGrfNode())
184 SwGrfNode
* pGrfNode
= aNodes
[nIndex
]->GetGrfNode();
185 CPPUNIT_ASSERT(pGrfNode
);
187 const GraphicObject
& rGraphicObj
= pGrfNode
->GetGrfObj(true);
188 aGraphic
= rGraphicObj
.GetGraphic();
193 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), bImageFound
);
195 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), GraphicType::Bitmap
, aGraphic
.GetType());
196 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_uLong(864900), aGraphic
.GetSizeBytes());
198 // Check if linked graphic is registered in LinkManager
199 sfx2::LinkManager
& rLinkManager
= pTextDoc
->GetDocShell()->GetDoc()->GetEditShell()->GetLinkManager();
200 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), size_t(1), rLinkManager
.GetLinks().size());
201 const tools::SvRef
<sfx2::SvBaseLink
> & rLink
= rLinkManager
.GetLinks()[0];
202 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), rLink
->GetLinkSourceName().indexOf("linked_graphic.jpg") >= 0);
206 void Test::testImageWithSpecialID()
208 // Check how LO handles when the imported graphic's ID is different from that one
209 // which is generated by LO.
211 const OUString aFilterNames
[] = {
215 "Office Open XML Text",
218 for (OUString
const & rFilterName
: aFilterNames
)
220 createSwDoc("images_with_special_IDs.odt");
222 // Export the document and import again for a check
223 saveAndReload(rFilterName
);
225 // Check whether graphic exported well
226 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
227 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), 2, getShapes());
229 uno::Reference
<drawing::XShape
> xImage
= getShape(1);
230 uno::Reference
< beans::XPropertySet
> XPropSet( xImage
, uno::UNO_QUERY_THROW
);
232 // Check graphic, size
234 uno::Reference
<graphic::XGraphic
> xGraphic
;
235 XPropSet
->getPropertyValue("Graphic") >>= xGraphic
;
236 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xGraphic
.is());
237 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), graphic::GraphicType::PIXEL
, xGraphic
->getType());
238 uno::Reference
<awt::XBitmap
> xBitmap(xGraphic
, uno::UNO_QUERY
);
239 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
240 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(610), xBitmap
->getSize().Width
);
241 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(381), xBitmap
->getSize().Height
);
245 xImage
.set(getShape(2), uno::UNO_QUERY
);
246 XPropSet
.set( xImage
, uno::UNO_QUERY_THROW
);
248 // Check graphic, size
250 uno::Reference
<graphic::XGraphic
> xGraphic
;
251 XPropSet
->getPropertyValue("Graphic") >>= xGraphic
;
252 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xGraphic
.is());
253 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), graphic::GraphicType::PIXEL
, xGraphic
->getType());
254 uno::Reference
<awt::XBitmap
> xBitmap(xGraphic
, uno::UNO_QUERY
);
255 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
256 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(900), xBitmap
->getSize().Width
);
257 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(600), xBitmap
->getSize().Height
);
262 /// Gives the first embedded or linked image in a document.
263 static uno::Reference
<drawing::XShape
> lcl_getShape(const uno::Reference
<lang::XComponent
>& xComponent
, bool bEmbedded
)
265 uno::Reference
<drawing::XShape
> xShape
;
267 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(xComponent
, uno::UNO_QUERY
);
268 uno::Reference
<drawing::XDrawPage
> xDrawPage
= xDrawPageSupplier
->getDrawPage();
269 for (sal_Int32 i
= 0; i
< xDrawPage
->getCount(); ++i
)
271 uno::Reference
<beans::XPropertySet
> xShapeProperties(xDrawPage
->getByIndex(i
), uno::UNO_QUERY
);
272 uno::Reference
<graphic::XGraphic
> xGraphic
;
273 xShapeProperties
->getPropertyValue("Graphic") >>= xGraphic
;
276 Graphic
aGraphic(xGraphic
);
278 if (bEmbedded
== aGraphic
.getOriginURL().isEmpty())
280 xShape
.set(xShapeProperties
, uno::UNO_QUERY
);
289 void Test::testGraphicShape()
291 // There are two kind of images in Writer: 1) Writer specific handled by SwGrfNode and
292 // 2) graphic shape handled by SdrGrafObj (e.g. after copy&paste from Impress).
294 const OUString aFilterNames
[] = {
298 "Office Open XML Text",
301 for (OUString
const & rFilterName
: aFilterNames
)
303 createSwDoc("graphic_shape.odt");
305 // Export the document and import again for a check
306 saveAndReload(rFilterName
);
308 // Check whether graphic exported well
309 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
310 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), 2, getShapes());
312 uno::Reference
<drawing::XShape
> xImage
= lcl_getShape(mxComponent
, true);
313 CPPUNIT_ASSERT_MESSAGE("Couldn't load the shape/image", xImage
.is());
314 uno::Reference
< beans::XPropertySet
> XPropSet( xImage
, uno::UNO_QUERY
);
315 // First image is embedded
318 uno::Reference
<graphic::XGraphic
> xGraphic
;
319 XPropSet
->getPropertyValue("Graphic") >>= xGraphic
;
320 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xGraphic
.is());
321 uno::Reference
<awt::XBitmap
> xBitmap(xGraphic
, uno::UNO_QUERY
);
322 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
323 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(610), xBitmap
->getSize().Width
);
324 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(381), xBitmap
->getSize().Height
);
327 // MS filters make this kind of linked images broken !?
328 if (rFilterName
!= "writer8")
331 // Second image is a linked one
332 xImage
= lcl_getShape(mxComponent
, false);
333 XPropSet
.set(xImage
, uno::UNO_QUERY
);
334 const OString sFailedImageLoad
= OString::Concat("Couldn't load the shape/image for ") + rFilterName
.toUtf8();
335 CPPUNIT_ASSERT_MESSAGE(sFailedImageLoad
.getStr(), xImage
.is());
339 uno::Reference
<graphic::XGraphic
> xGraphic
;
340 XPropSet
->getPropertyValue("Graphic") >>= xGraphic
;
341 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xGraphic
.is());
343 Graphic
aGraphic(xGraphic
);
344 OUString sURL
= aGraphic
.getOriginURL();
345 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), sURL
.endsWith("linked_graphic.jpg"));
347 uno::Reference
<awt::XBitmap
> xBitmap(xGraphic
, uno::UNO_QUERY
);
348 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
349 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(620), xBitmap
->getSize().Width
);
350 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(465), xBitmap
->getSize().Height
);
358 std::vector
<uno::Reference
<graphic::XGraphic
>>
359 lcl_getGraphics(const uno::Reference
<lang::XComponent
>& xComponent
)
361 std::vector
<uno::Reference
<graphic::XGraphic
>> aGraphics
;
363 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(xComponent
, uno::UNO_QUERY
);
364 uno::Reference
<drawing::XDrawPage
> xDrawPage
= xDrawPageSupplier
->getDrawPage();
365 for (sal_Int32 i
= 0; i
< xDrawPage
->getCount(); ++i
)
367 uno::Reference
<beans::XPropertySet
> xShapeProperties(xDrawPage
->getByIndex(i
), uno::UNO_QUERY
);
368 uno::Reference
<graphic::XGraphic
> xGraphic
;
369 xShapeProperties
->getPropertyValue("Graphic") >>= xGraphic
;
372 aGraphics
.push_back(xGraphic
);
381 void Test::testMultipleIdenticalGraphics()
383 // We have multiple identical graphics. When we save them we want
384 // them to be saved de-duplicated and the same should still be true
385 // after loading them again. This test check that the de-duplication
386 // works as expected.
388 const OUString aFilterNames
[] {
390 //"Rich Text Format", // doesn't work correctly for now
392 "Office Open XML Text",
395 for (OUString
const & rFilterName
: aFilterNames
)
397 createSwDoc("multiple_identical_graphics.odt");
399 // Export the document and import again for a check
400 saveAndReload(rFilterName
);
402 // Check whether graphic exported well
403 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
404 auto aGraphics
= lcl_getGraphics(mxComponent
);
406 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), size_t(5), aGraphics
.size());
408 // Get all GfxLink addresses, we expect all of them to be the same
409 // indicating we use the same graphic instance for all shapes
410 std::vector
<sal_Int64
> aGfxLinkAddresses
;
411 for (auto const & rxGraphic
: aGraphics
)
413 GfxLink
* pLink
= Graphic(rxGraphic
).GetSharedGfxLink().get();
414 aGfxLinkAddresses
.emplace_back(reinterpret_cast<sal_Int64
>(pLink
));
417 // Check all addresses are the same
418 bool bResult
= std::equal(aGfxLinkAddresses
.begin() + 1, aGfxLinkAddresses
.end(), aGfxLinkAddresses
.begin());
419 const OString sGraphicNotTheSameFailedMessage
= OString::Concat("Graphics not the same for filter: '") +
420 rFilterName
.toUtf8() + OString::Concat("'");
421 CPPUNIT_ASSERT_EQUAL_MESSAGE(sGraphicNotTheSameFailedMessage
.getStr(), true, bResult
);
425 void Test::testCharHighlightBody()
427 // MS Word has two kind of character backgrounds called character shading and highlighting
428 // MS filters handle these attributes separately, but ODF export merges them into one background attribute
430 const OUString aFilterNames
[] = {
434 "Office Open XML Text",
437 for (OUString
const & rFilterName
: aFilterNames
)
439 createSwDoc("char_highlight.docx");
441 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
443 // Export the document and import again for a check
444 saveAndReload(rFilterName
);
446 const uno::Reference
< text::XTextRange
> xPara
= getParagraph(1);
447 // Both highlight and background
448 const Color
nBackColor(0x4F81BD);
449 for( int nRun
= 1; nRun
<= 16; ++nRun
)
451 const uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,nRun
), uno::UNO_QUERY
);
452 Color nHighlightColor
;
455 case 1: nHighlightColor
= COL_BLACK
; break; //black 0x000000
456 case 2: nHighlightColor
= COL_LIGHTBLUE
; break; //light blue 0x0000ff
457 case 3: nHighlightColor
= COL_LIGHTCYAN
; break; //light cyan 0x00ffff
458 case 4: nHighlightColor
= COL_LIGHTGREEN
; break; //light green 0x00ff00
459 case 5: nHighlightColor
= COL_LIGHTMAGENTA
; break; //light magenta 0xff00ff
460 case 6: nHighlightColor
= COL_LIGHTRED
; break; //light red 0xff0000
461 case 7: nHighlightColor
= COL_YELLOW
; break; //yellow 0xffff00
462 case 8: nHighlightColor
= COL_WHITE
; break; //white 0xffffff
463 case 9: nHighlightColor
= COL_BLUE
; break;//blue 0x000080
464 case 10: nHighlightColor
= COL_CYAN
; break; //cyan 0x008080
465 case 11: nHighlightColor
= COL_GREEN
; break; //green 0x008000
466 case 12: nHighlightColor
= COL_MAGENTA
; break; //magenta 0x800080
467 case 13: nHighlightColor
= COL_RED
; break; //red 0x800000
468 case 14: nHighlightColor
= COL_BROWN
; break; //brown 0x808000
469 case 15: nHighlightColor
= COL_GRAY
; break; //dark gray 0x808080
470 case 16: nHighlightColor
= COL_LIGHTGRAY
; break; //light gray 0xC0C0C0
473 if (rFilterName
== "writer8")
475 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharHighlight"));
476 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), nHighlightColor
, getProperty
<Color
>(xRun
,"CharBackColor"));
480 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), nHighlightColor
, getProperty
<Color
>(xRun
,"CharHighlight"));
481 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), nBackColor
, getProperty
<Color
>(xRun
,"CharBackColor"));
487 const uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,18), uno::UNO_QUERY
);
488 if (rFilterName
== "writer8")
490 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharHighlight"));
491 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_LIGHTRED
, getProperty
<Color
>(xRun
,"CharBackColor"));
495 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_LIGHTRED
, getProperty
<Color
>(xRun
,"CharHighlight"));
496 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharBackColor"));
502 const uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,19), uno::UNO_QUERY
);
503 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharHighlight"));
504 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_LIGHTBLUE
, getProperty
<Color
>(xRun
,"CharBackColor"));
509 void Test::testCharStyleHighlight()
511 // MS Word has two kind of character backgrounds called character shading and highlighting.
512 // However, their character style can only accept shading. It ignores the highlighting value.
514 const OUString aFilterNames
[] = {
517 "Office Open XML Text",
520 for (OUString
const & rFilterName
: aFilterNames
)
522 createSwDoc("tdf138345_charstyle_highlight.odt");
524 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
526 // Export the document and import again for a check
527 saveAndReload(rFilterName
);
529 uno::Reference
<beans::XPropertySet
> xCharStyle
;
530 getStyles("CharacterStyles")->getByName("charBackground") >>= xCharStyle
;
531 const Color
nBackColor(0xFFDBB6); //orange-y
533 // Always export character style's background colour as shading, never as highlighting.
534 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xCharStyle
,"CharHighlight"));
535 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), nBackColor
, getProperty
<Color
>(xCharStyle
,"CharBackColor"));
539 void Test::testCharHighlight()
541 SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
542 rOpt
.SetCharBackground2Shading();
544 testCharHighlightBody();
545 testCharStyleHighlight();
547 rOpt
.SetCharBackground2Highlighting();
549 testCharHighlightBody();
550 testCharStyleHighlight();
553 void Test::testCharHighlightODF()
555 createSwDoc("char_background_editing.docx");
557 // don't check import, testMSCharBackgroundEditing already does that
559 uno::Reference
<text::XTextRange
> xPara
= getParagraph(1);
560 for (int i
= 1; i
<= 4; ++i
)
562 uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,i
), uno::UNO_QUERY
);
565 case 1: // non-transparent highlight
566 xRun
->setPropertyValue("CharBackColor", uno::Any(static_cast<sal_Int32
>(128)));
567 xRun
->setPropertyValue("CharBackTransparent", uno::Any(true));
568 xRun
->setPropertyValue("CharHighlight", uno::Any(static_cast<sal_Int32
>(64)));
571 case 2: // transparent backcolor
572 xRun
->setPropertyValue("CharBackColor", uno::Any(static_cast<sal_Int32
>(128)));
573 xRun
->setPropertyValue("CharBackTransparent", uno::Any(true));
574 xRun
->setPropertyValue("CharHighlight", uno::Any(static_cast<sal_Int32
>(COL_TRANSPARENT
)));
577 case 3: // non-transparent backcolor
578 xRun
->setPropertyValue("CharBackColor", uno::Any(static_cast<sal_Int32
>(128)));
579 xRun
->setPropertyValue("CharBackTransparent", uno::Any(false));
580 xRun
->setPropertyValue("CharHighlight", uno::Any(static_cast<sal_Int32
>(COL_TRANSPARENT
)));
583 case 4: // non-transparent highlight again
584 xRun
->setPropertyValue("CharBackColor", uno::Any(static_cast<sal_Int32
>(128)));
585 xRun
->setPropertyValue("CharBackTransparent", uno::Any(false));
586 xRun
->setPropertyValue("CharHighlight", uno::Any(static_cast<sal_Int32
>(64)));
591 saveAndReload("writer8");
593 xPara
.set(getParagraph(1));
594 for (int i
= 1; i
<= 4; ++i
)
596 uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,i
), uno::UNO_QUERY
);
597 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(COL_TRANSPARENT
), getProperty
<sal_Int32
>(xRun
, "CharHighlight"));
600 case 1: // non-transparent highlight
601 CPPUNIT_ASSERT_EQUAL(Color(0x000040), getProperty
<Color
>(xRun
, "CharBackColor"));
602 CPPUNIT_ASSERT_EQUAL(false, getProperty
<bool>(xRun
, "CharBackTransparent"));
604 case 2: // transparent backcolor
605 CPPUNIT_ASSERT_EQUAL(COL_TRANSPARENT
, getProperty
<Color
>(xRun
, "CharBackColor"));
606 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(xRun
, "CharBackTransparent"));
608 case 3: // non-transparent backcolor
609 CPPUNIT_ASSERT_EQUAL(COL_BLUE
, getProperty
<Color
>(xRun
, "CharBackColor"));
610 CPPUNIT_ASSERT_EQUAL(false, getProperty
<bool>(xRun
, "CharBackTransparent"));
612 case 4: // non-transparent highlight again
613 CPPUNIT_ASSERT_EQUAL(Color(0x000040), getProperty
<Color
>(xRun
, "CharBackColor"));
614 CPPUNIT_ASSERT_EQUAL(false, getProperty
<bool>(xRun
, "CharBackTransparent"));
620 void Test::testMSCharBackgroundEditing()
622 // Simulate the editing process of imported MSO character background attributes
623 // and check how export behaves.
625 const OUString aFilterNames
[] = {
629 "Office Open XML Text",
632 for (OUString
const & rFilterName
: aFilterNames
)
634 createSwDoc("char_background_editing.docx");
636 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
638 // Check whether import was done on the right way
639 uno::Reference
< text::XTextRange
> xPara
= getParagraph(1);
641 uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,1), uno::UNO_QUERY
);
642 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharHighlight"));
643 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_LIGHTRED
, getProperty
<Color
>(xRun
,"CharBackColor"));
645 xRun
.set(getRun(xPara
,2), uno::UNO_QUERY
);
646 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_LIGHTBLUE
, getProperty
<Color
>(xRun
,"CharHighlight"));
647 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharBackColor"));
649 xRun
.set(getRun(xPara
,3), uno::UNO_QUERY
);
650 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_LIGHTBLUE
, getProperty
<Color
>(xRun
,"CharHighlight"));
651 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_LIGHTRED
, getProperty
<Color
>(xRun
,"CharBackColor"));
653 xRun
.set(getRun(xPara
,4), uno::UNO_QUERY
);
654 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharHighlight"));
655 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharBackColor"));
659 for( int i
= 1; i
<= 4; ++i
)
661 uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,i
), uno::UNO_QUERY
);
666 case 1: nBackColor
= COL_BLACK
; break; //black 0x000000
667 case 2: nBackColor
= COL_LIGHTCYAN
; break; //cyan 0x00ffff
668 case 3: nBackColor
= COL_LIGHTGREEN
; break; //green 0x00ff00
669 case 4: nBackColor
= COL_LIGHTMAGENTA
; break; //magenta 0xff00ff
671 xRun
->setPropertyValue("CharBackColor", uno::Any(nBackColor
));
672 // Remove highlighting
673 xRun
->setPropertyValue("CharHighlight", uno::Any(COL_TRANSPARENT
));
674 // Remove shading marker
675 uno::Sequence
<beans::PropertyValue
> aGrabBag
= getProperty
<uno::Sequence
<beans::PropertyValue
> >(xRun
,"CharInteropGrabBag");
676 for (beans::PropertyValue
& rProp
: asNonConstRange(aGrabBag
))
678 if (rProp
.Name
== "CharShadingMarker")
680 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), true, rProp
.Value
.get
<bool>());
681 rProp
.Value
<<= false;
684 xRun
->setPropertyValue("CharInteropGrabBag", uno::Any(aGrabBag
));
687 SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
688 rOpt
.SetCharBackground2Highlighting();
690 // Export the document and import again for a check
691 saveAndReload(rFilterName
);
693 // Check whether background was exported as highlighting
694 xPara
.set(getParagraph(1));
695 for( int i
= 1; i
<= 4; ++i
)
700 case 1: nBackColor
= COL_BLACK
; break; //black 0x000000
701 case 2: nBackColor
= COL_LIGHTCYAN
; break; //light cyan 0x00ffff
702 case 3: nBackColor
= COL_LIGHTGREEN
; break; //light green 0x00ff00
703 case 4: nBackColor
= COL_LIGHTMAGENTA
; break; //light magenta 0xff00ff
705 const uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,i
), uno::UNO_QUERY
);
706 if (rFilterName
== "writer8")
708 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharHighlight"));
709 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), nBackColor
, getProperty
<Color
>(xRun
,"CharBackColor"));
713 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), nBackColor
, getProperty
<Color
>(xRun
,"CharHighlight"));
714 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_TRANSPARENT
, getProperty
<Color
>(xRun
,"CharBackColor"));
720 void Test::testCharBackgroundToHighlighting()
722 // MSO highlighting has less kind of values so let's see how LO character background is converted
725 const OUString aFilterNames
[] = {
728 "Office Open XML Text",
731 for (OUString
const & rFilterName
: aFilterNames
)
733 createSwDoc("char_background.odt");
735 OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
738 SvtFilterOptions
& rOpt
= SvtFilterOptions::Get();
739 rOpt
.SetCharBackground2Highlighting();
741 // Export the document and import again for a check
742 saveAndReload(rFilterName
);
744 // Check highlight color
745 const uno::Reference
< text::XTextRange
> xPara
= getParagraph(1);
746 for( int nRun
= 1; nRun
<= 19; ++nRun
)
748 const uno::Reference
<beans::XPropertySet
> xRun(getRun(xPara
,nRun
), uno::UNO_QUERY
);
749 Color nHighlightColor
;
752 case 1: nHighlightColor
= COL_BLACK
; break; //black 0x000000
753 case 2: nHighlightColor
= COL_YELLOW
; break; //yellow 0xffff00
754 case 3: nHighlightColor
= COL_LIGHTMAGENTA
; break; //light magenta 0xff00ff
755 case 4: nHighlightColor
= COL_LIGHTCYAN
; break; //light cyan 0x00ffff
756 case 5: nHighlightColor
= COL_YELLOW
; break; //yellow 0xffff00
757 case 6: nHighlightColor
= COL_LIGHTRED
; break; //light red 0xff0000
758 case 7: nHighlightColor
= COL_LIGHTBLUE
; break; //light blue 0x0000ff
759 case 8: nHighlightColor
= COL_LIGHTGREEN
; break; //light green 0x00ff00
760 case 9: nHighlightColor
= COL_GREEN
; break; //dark green 0x008000
761 case 10: nHighlightColor
= COL_MAGENTA
; break; //dark magenta 0x800080
762 case 11: nHighlightColor
= COL_BLUE
; break; //dark blue 0x000080
763 case 12: nHighlightColor
= COL_BROWN
; break; //brown 0x808000
764 case 13: nHighlightColor
= COL_GRAY
; break; //dark gray 0x808080
765 case 14: nHighlightColor
= COL_BLACK
; break; //black 0x000000
766 case 15: nHighlightColor
= COL_LIGHTRED
; break; //light red 0xff0000
767 case 16: nHighlightColor
= COL_LIGHTGRAY
; break; //light gray 0xC0C0C0
768 case 17: nHighlightColor
= COL_RED
; break; //dark red 0x800000
769 case 18: nHighlightColor
= COL_GRAY
; break; //dark gray 0x808080
770 case 19: nHighlightColor
= COL_YELLOW
; break; //yellow 0xffff00
772 const OString sMessage
= sFailedMessage
+". Index of run with unmatched color: " + OString::number(nRun
);
773 CPPUNIT_ASSERT_EQUAL_MESSAGE(sMessage
.getStr(), nHighlightColor
, getProperty
<Color
>(xRun
,"CharHighlight"));
779 void Test::testSkipImages()
781 // Check how LO skips image loading (but not texts of textboxes and custom shapes)
782 // during DOC and DOCX import, using the "SkipImages" FilterOptions.
784 std::pair
<OUString
, OUString
> aFilterNames
[] = {
785 { "skipimages.doc", "" },
786 { "skipimages.doc", "SkipImages" },
787 { "skipimages.docx", "" },
788 { "skipimages.docx", "SkipImages" }
791 for (auto const & rFilterNamePair
: aFilterNames
)
793 bool bSkipImages
= !rFilterNamePair
.second
.isEmpty();
794 OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterNamePair
.first
.toUtf8();
796 setImportFilterOptions(rFilterNamePair
.second
);
797 createSwDoc(rFilterNamePair
.first
.toUtf8().getStr());
798 sFailedMessage
+= " - " + rFilterNamePair
.second
.toUtf8();
800 // Check shapes (images, textboxes, custom shapes)
801 uno::Reference
<drawing::XShape
> xShape
;
802 uno::Reference
<graphic::XGraphic
> xGraphic
;
803 uno::Reference
< beans::XPropertySet
> XPropSet
;
804 uno::Reference
<awt::XBitmap
> xBitmap
;
806 bool bHasTextboxText
= false;
807 bool bHasCustomShapeText
= false;
808 sal_Int32 nImageCount
= 0;
810 for (int i
= 1; i
<= getShapes(); i
++)
812 xShape
= getShape(i
);
813 XPropSet
.set( xShape
, uno::UNO_QUERY_THROW
);
816 XPropSet
->getPropertyValue("Graphic") >>= xGraphic
;
817 xBitmap
.set(xGraphic
, uno::UNO_QUERY
);
821 catch (beans::UnknownPropertyException
&)
824 uno::Reference
<text::XTextRange
> xText(xShape
, uno::UNO_QUERY
);
827 OUString shapeText
= xText
->getString();
828 if (shapeText
.startsWith("Lorem ipsum"))
829 bHasTextboxText
= true;
830 else if (shapeText
.startsWith("Nam pretium"))
831 bHasCustomShapeText
= true;
835 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), bHasTextboxText
);
836 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), bHasCustomShapeText
);
837 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), static_cast<sal_Int32
>(bSkipImages
? 0 : 3), nImageCount
);
842 static auto verifyNestedFieldmark(OUString
const& rTestName
,
843 uno::Reference
<lang::XComponent
> const& xComponent
) -> void
845 SwDoc
const*const pDoc(dynamic_cast<SwXTextDocument
&>(*xComponent
).GetDocShell()->GetDoc());
846 IDocumentMarkAccess
const& rIDMA(*pDoc
->getIDocumentMarkAccess());
848 // no spurious bookmarks have been created
849 CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName
.toUtf8().getStr(),
850 sal_Int32(0), rIDMA
.getBookmarksCount());
852 // check inner fieldmark
853 SwNodeIndex
const node1(*pDoc
->GetNodes().GetEndOfContent().StartOfSectionNode(), +2);
854 SwPosition
const innerPos(*node1
.GetNode().GetTextNode(),
855 node1
.GetNode().GetTextNode()->GetText().indexOf(CH_TXT_ATR_FIELDSTART
));
856 CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName
.toUtf8().getStr(),
857 sal_Int32(1), innerPos
.GetContentIndex());
858 ::sw::mark::IFieldmark
*const pInner(rIDMA
.getFieldmarkAt(innerPos
));
859 CPPUNIT_ASSERT_MESSAGE(rTestName
.toUtf8().getStr(), pInner
);
860 OUString
const innerString(SwPaM(pInner
->GetMarkPos(), pInner
->GetOtherMarkPos()).GetText());
861 CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName
.toUtf8().getStr(), OUString(
862 OUStringChar(CH_TXT_ATR_FIELDSTART
) + u
" QUOTE \"foo " + OUStringChar(CH_TXTATR_NEWLINE
)
863 + u
" bar " + OUStringChar(CH_TXTATR_NEWLINE
)
864 + u
"baz\" " + OUStringChar(CH_TXT_ATR_FIELDSEP
) + u
"foo " + OUStringChar(CH_TXTATR_NEWLINE
)
865 + u
" bar " + OUStringChar(CH_TXTATR_NEWLINE
)
866 + u
"baz" + OUStringChar(CH_TXT_ATR_FIELDEND
)), innerString
);
868 // check outer fieldmark
869 SwNodeIndex
const node2(node1
, -1);
870 SwPosition
const outerPos(*node2
.GetNode().GetTextNode(),
871 node2
.GetNode().GetTextNode()->GetText().indexOf(CH_TXT_ATR_FIELDSTART
));
872 CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName
.toUtf8().getStr(),
873 sal_Int32(0), outerPos
.GetContentIndex());
874 ::sw::mark::IFieldmark
const*const pOuter(rIDMA
.getFieldmarkAt(outerPos
));
875 CPPUNIT_ASSERT_MESSAGE(rTestName
.toUtf8().getStr(), pOuter
);
876 OUString
const outerString(SwPaM(pOuter
->GetMarkPos(), pOuter
->GetOtherMarkPos()).GetText());
877 CPPUNIT_ASSERT_EQUAL_MESSAGE(rTestName
.toUtf8().getStr(), OUString(
878 OUStringChar(CH_TXT_ATR_FIELDSTART
) + u
" QUOTE \"foo " + OUStringChar(CH_TXTATR_NEWLINE
)
879 + u
" " + OUStringChar(CH_TXT_ATR_FIELDSTART
) + u
" QUOTE \"foo " + OUStringChar(CH_TXTATR_NEWLINE
)
880 + u
" bar " + OUStringChar(CH_TXTATR_NEWLINE
)
881 + u
"baz\" " + OUStringChar(CH_TXT_ATR_FIELDSEP
) + u
"foo " + OUStringChar(CH_TXTATR_NEWLINE
)
882 + u
" bar " + OUStringChar(CH_TXTATR_NEWLINE
)
883 + u
"baz" + OUStringChar(CH_TXT_ATR_FIELDEND
) + OUStringChar(CH_TXTATR_NEWLINE
)
884 + u
"bar " + OUStringChar(CH_TXTATR_NEWLINE
)
885 + u
"baz\" " + OUStringChar(CH_TXT_ATR_FIELDSEP
) + u
"foo " + OUStringChar(CH_TXTATR_NEWLINE
)
886 + u
" foo " + OUStringChar(CH_TXTATR_NEWLINE
)
887 + u
" bar " + OUStringChar(CH_TXTATR_NEWLINE
)
888 + u
"baz" + OUStringChar(CH_TXTATR_NEWLINE
)
889 + u
"bar " + OUStringChar(CH_TXTATR_NEWLINE
)
890 + u
"baz" + OUStringChar(CH_TXT_ATR_FIELDEND
)), outerString
);
892 // must return innermost mark
893 CPPUNIT_ASSERT_EQUAL(pInner
, rIDMA
.getInnerFieldmarkFor(innerPos
));
896 void Test::testNestedFieldmark()
898 // experimental config setting
901 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
902 comphelper::ConfigurationChanges::create());
903 officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::set(false, pBatch
);
904 return pBatch
->commit();
906 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(comphelper::ConfigurationChanges::create());
907 officecfg::Office::Common::Filter::Microsoft::Import::ForceImportWWFieldsAsGenericFields::set(true, pBatch
);
910 std::pair
<OUString
, OUString
> const aFilterNames
[] = {
911 {"writer8", "fieldmark_QUOTE_nest.fodt"},
912 {"Office Open XML Text", "fieldmark_QUOTE_nest.docx"},
913 {"Rich Text Format", "fieldmark_QUOTE_nest.rtf"},
916 for (auto const & rFilterName
: aFilterNames
)
918 createSwDoc(rFilterName
.second
.toUtf8().getStr());
920 verifyNestedFieldmark(rFilterName
.first
+ ", load", mxComponent
);
922 // Export the document and import again
923 saveAndReload(rFilterName
.first
);
925 verifyNestedFieldmark(rFilterName
.first
+ " exported-reload", mxComponent
);
929 auto Test::verifyText13(char const*const pTestName
) -> void
931 // OFFICE-3789 style:header-first/style:footer-first
932 uno::Reference
<beans::XPropertySet
> xPageStyle
;
933 getStyles("PageStyles")->getByName("Standard") >>= xPageStyle
;
934 uno::Reference
<text::XText
> xHF(getProperty
<uno::Reference
<text::XText
>>(xPageStyle
, "HeaderTextFirst"));
935 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("Header first"), xHF
->getString());
936 uno::Reference
<text::XText
> xFF(getProperty
<uno::Reference
<text::XText
>>(xPageStyle
, "FooterTextFirst"));
937 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("Footer first"), xFF
->getString());
938 // OFFICE-3767 text:contextual-spacing
939 uno::Reference
<text::XTextRange
> xPara(getParagraph(1));
940 CPPUNIT_ASSERT_MESSAGE(pTestName
, getProperty
<bool>(xPara
, "ParaContextMargin"));
941 // OFFICE-3776 meta:creator-initials
942 uno::Reference
<text::XTextRange
> xRun(getRun(xPara
, 1));
943 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("Annotation"), getProperty
<OUString
>(xRun
, "TextPortionType"));
944 uno::Reference
<beans::XPropertySet
> xComment(getProperty
<uno::Reference
<beans::XPropertySet
>>(xRun
, "TextField"));
945 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("dj"), getProperty
<OUString
>(xComment
, "Initials"));
946 // OFFICE-3941 text:index-entry-link-start/text:index-entry-link-end
947 uno::Reference
<text::XDocumentIndexesSupplier
> xDIS(mxComponent
, uno::UNO_QUERY
);
948 uno::Reference
<container::XIndexAccess
> xIndexes(xDIS
->getDocumentIndexes());
949 uno::Reference
<text::XDocumentIndex
> xIndex(xIndexes
->getByIndex(0), uno::UNO_QUERY
);
950 uno::Reference
<container::XIndexReplace
> xLevels(getProperty
<uno::Reference
<container::XIndexReplace
>>(xIndex
, "LevelFormat"));
951 uno::Sequence
<beans::PropertyValues
> format
;
952 xLevels
->getByIndex(1) >>= format
; // 1-based?
953 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("TokenType"), format
[0][0].Name
);
954 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("TokenHyperlinkStart"), format
[0][0].Value
.get
<OUString
>());
955 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("TokenType"), format
[4][0].Name
);
956 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, OUString("TokenHyperlinkEnd"), format
[4][0].Value
.get
<OUString
>());
959 // test ODF 1.3 new text document features
960 void Test::testODF13()
963 createSwDoc("text13e.odt");
966 verifyText13("import");
969 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
970 comphelper::ConfigurationChanges::create());
971 officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch
);
972 return pBatch
->commit();
977 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
978 comphelper::ConfigurationChanges::create());
979 officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch
);
982 saveAndReload("writer8");
985 xmlDocUniquePtr pContentXml
= parseExport("content.xml");
986 assertXPath(pContentXml
, "/office:document-content/office:automatic-styles/style:style/style:paragraph-properties[@style:contextual-spacing='true']");
987 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:p/office:annotation/meta:creator-initials");
988 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:p/office:annotation/loext:sender-initials", 0);
989 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-start");
990 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-start", 0);
991 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-end");
992 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-end", 0);
993 xmlDocUniquePtr pStylesXml
= parseExport("styles.xml");
994 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/style:header-first");
995 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/loext:header-first", 0);
996 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/style:footer-first");
997 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/loext:footer-first", 0);
1000 verifyText13("1.3 reload");
1003 // export ODF 1.2 extended
1004 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
1005 comphelper::ConfigurationChanges::create());
1006 officecfg::Office::Common::Save::ODF::DefaultVersion::set(9, pBatch
);
1009 // FIXME: it's not possible to use 'reload' here because the validation fails with
1010 // Error: unexpected attribute "loext:contextual-spacing"
1011 utl::MediaDescriptor aMediaDescriptor
;
1012 aMediaDescriptor
["FilterName"] <<= OUString("writer8");
1014 uno::Reference
<frame::XStorable
> const xStorable(mxComponent
, uno::UNO_QUERY
);
1015 xStorable
->storeToURL(maTempFile
.GetURL(), aMediaDescriptor
.getAsConstPropertyValueList());
1018 xmlDocUniquePtr pContentXml
= parseExport("content.xml");
1019 assertXPath(pContentXml
, "/office:document-content/office:automatic-styles/style:style/style:paragraph-properties[@loext:contextual-spacing='true']");
1020 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:p/office:annotation/loext:sender-initials");
1021 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:p/office:annotation/meta:creator-initials", 0);
1022 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-start");
1023 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-start", 0);
1024 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-end");
1025 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-end", 0);
1026 xmlDocUniquePtr pStylesXml
= parseExport("styles.xml");
1027 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/loext:header-first");
1028 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/style:header-first", 0);
1029 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/loext:footer-first");
1030 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/style:footer-first", 0);
1033 mxComponent
->dispose();
1034 mxComponent
= loadFromDesktop(maTempFile
.GetURL(), "com.sun.star.text.TextDocument");
1037 verifyText13("1.2 Extended reload");
1041 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
1042 comphelper::ConfigurationChanges::create());
1043 officecfg::Office::Common::Save::ODF::DefaultVersion::set(4, pBatch
);
1046 // don't reload - no point
1050 xmlDocUniquePtr pContentXml
= parseExport("content.xml");
1051 assertXPathNoAttribute(pContentXml
, "/office:document-content/office:automatic-styles/style:style/style:paragraph-properties", "contextual-spacing");
1052 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:p/office:annotation/meta:creator-initials", 0);
1053 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:p/office:annotation/loext:sender-initials", 0);
1054 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-start", 0);
1055 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-start", 0);
1056 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/text:index-entry-link-end", 0);
1057 assertXPath(pContentXml
, "/office:document-content/office:body/office:text/text:illustration-index/text:illustration-index-source/text:illustration-index-entry-template/loext:index-entry-link-end", 0);
1058 xmlDocUniquePtr pStylesXml
= parseExport("styles.xml");
1059 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/style:header-first", 0);
1060 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/loext:header-first", 0);
1061 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/style:footer-first", 0);
1062 assertXPath(pStylesXml
, "/office:document-styles/office:master-styles/style:master-page/loext:footer-first", 0);
1066 void Test::testRedlineFlags()
1068 const OUString aFilterNames
[] = {
1072 "Office Open XML Text",
1076 SwDoc
* pDoc
= getSwDoc();
1078 SwPaM
pam(SwPosition(pDoc
->GetNodes().GetEndOfContent(), SwNodeOffset(-1)));
1079 pDoc
->getIDocumentContentOperations().InsertString(pam
, "foo bar baz");
1081 IDocumentRedlineAccess
& rIDRA(pDoc
->getIDocumentRedlineAccess());
1082 // enable change tracking
1083 rIDRA
.SetRedlineFlags(rIDRA
.GetRedlineFlags()
1084 | RedlineFlags::On
| RedlineFlags::ShowDelete
);
1086 // need a delete redline to trigger mode switching
1087 pam
.Move(fnMoveForward
, GoInDoc
);
1089 pam
.Move(fnMoveBackward
, GoInDoc
);
1090 pDoc
->getIDocumentContentOperations().DeleteAndJoin(pam
);
1092 // hide delete redlines
1093 RedlineFlags
const nRedlineFlags
=
1094 rIDRA
.GetRedlineFlags() & ~RedlineFlags::ShowDelete
;
1095 rIDRA
.SetRedlineFlags(nRedlineFlags
);
1097 for (OUString
const & rFilterName
: aFilterNames
)
1099 // export the document
1102 // tdf#97103 check that redline mode is properly restored
1103 CPPUNIT_ASSERT_EQUAL_MESSAGE(
1104 OString(OString::Concat("redline mode not restored in ") + rFilterName
.toUtf8()).getStr(),
1105 static_cast<int>(nRedlineFlags
), static_cast<int>(rIDRA
.GetRedlineFlags()));
1109 void Test::testBulletAsImage()
1111 OUString aFilterNames
[] = {
1114 "Office Open XML Text",
1118 for (OUString
const & rFilterName
: aFilterNames
)
1120 OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
1122 createSwDoc("BulletAsImage.odt");
1124 // Check if import was successful
1126 uno::Reference
<text::XTextRange
> xPara(getParagraph(1));
1127 uno::Reference
<beans::XPropertySet
> xPropertySet(xPara
, uno::UNO_QUERY
);
1128 uno::Reference
<container::XIndexAccess
> xLevels
;
1129 xLevels
.set(xPropertySet
->getPropertyValue("NumberingRules"), uno::UNO_QUERY
);
1130 uno::Sequence
<beans::PropertyValue
> aProperties
;
1131 xLevels
->getByIndex(0) >>= aProperties
;
1132 uno::Reference
<awt::XBitmap
> xBitmap
;
1134 sal_Int16 nNumberingType
= -1;
1136 for (beans::PropertyValue
const & rProperty
: std::as_const(aProperties
))
1138 if (rProperty
.Name
== "NumberingType")
1140 nNumberingType
= rProperty
.Value
.get
<sal_Int16
>();
1142 else if (rProperty
.Name
== "GraphicBitmap")
1144 if (rProperty
.Value
.has
<uno::Reference
<awt::XBitmap
>>())
1146 xBitmap
= rProperty
.Value
.get
<uno::Reference
<awt::XBitmap
>>();
1149 else if (rProperty
.Name
== "GraphicSize")
1151 aSize
= rProperty
.Value
.get
<awt::Size
>();
1155 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), style::NumberingType::BITMAP
, nNumberingType
);
1158 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
1159 Graphic
aGraphic(uno::Reference
<graphic::XGraphic
>(xBitmap
, uno::UNO_QUERY
));
1160 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), GraphicType::Bitmap
, aGraphic
.GetType());
1161 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), aGraphic
.GetSizeBytes() > o3tl::make_unsigned(0));
1162 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), tools::Long(16), aGraphic
.GetSizePixel().Width());
1163 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), tools::Long(16), aGraphic
.GetSizePixel().Height());
1166 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(400), aSize
.Width
);
1167 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(400), aSize
.Height
);
1170 // Export the document and import again for a check
1171 saveAndReload(rFilterName
);
1174 uno::Reference
<text::XTextRange
> xPara(getParagraph(1));
1175 uno::Reference
<beans::XPropertySet
> xPropertySet(xPara
, uno::UNO_QUERY
);
1176 uno::Reference
<container::XIndexAccess
> xLevels
;
1177 xLevels
.set(xPropertySet
->getPropertyValue("NumberingRules"), uno::UNO_QUERY
);
1178 uno::Sequence
<beans::PropertyValue
> aProperties
;
1179 xLevels
->getByIndex(0) >>= aProperties
;
1180 uno::Reference
<awt::XBitmap
> xBitmap
;
1182 sal_Int16 nNumberingType
= -1;
1184 for (beans::PropertyValue
const & rProperty
: std::as_const(aProperties
))
1186 if (rProperty
.Name
== "NumberingType")
1188 nNumberingType
= rProperty
.Value
.get
<sal_Int16
>();
1190 else if (rProperty
.Name
== "GraphicBitmap")
1192 if (rProperty
.Value
.has
<uno::Reference
<awt::XBitmap
>>())
1194 xBitmap
= rProperty
.Value
.get
<uno::Reference
<awt::XBitmap
>>();
1197 else if (rProperty
.Name
== "GraphicSize")
1199 aSize
= rProperty
.Value
.get
<awt::Size
>();
1203 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), style::NumberingType::BITMAP
, nNumberingType
);
1206 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), xBitmap
.is());
1207 Graphic
aGraphic(uno::Reference
<graphic::XGraphic
>(xBitmap
, uno::UNO_QUERY
));
1208 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), GraphicType::Bitmap
, aGraphic
.GetType());
1209 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), aGraphic
.GetSizeBytes() > o3tl::make_unsigned(0));
1210 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), tools::Long(16), aGraphic
.GetSizePixel().Width());
1211 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), tools::Long(16), aGraphic
.GetSizePixel().Height());
1214 if (rFilterName
== "write8") // ODT is correct
1216 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(400), aSize
.Width
);
1217 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(400), aSize
.Height
);
1219 // FIXME: MS Filters don't work correctly for graphic bullet size
1220 else if (rFilterName
== "Office Open XML Text" || rFilterName
== "Rich Text Format")
1222 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(279), aSize
.Width
);
1223 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(279), aSize
.Height
);
1225 else if (rFilterName
== "MS Word 97")
1227 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(296), aSize
.Width
);
1228 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(296), aSize
.Height
);
1234 CPPUNIT_TEST_FIXTURE(Test
, testListLabelPDFExport
)
1238 uno::Reference
<text::XTextDocument
> xDoc(mxComponent
, uno::UNO_QUERY_THROW
);
1239 uno::Reference
<text::XText
> xText(xDoc
->getText());
1240 uno::Reference
<lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY_THROW
);
1241 uno::Reference
<container::XIndexReplace
> xNumRule(
1242 xFactory
->createInstance("com.sun.star.text.NumberingRules"),
1243 uno::UNO_QUERY_THROW
);
1244 OUString listFormat
;
1245 for (sal_Int32 i
= 0; i
< xNumRule
->getCount(); ++i
)
1247 uno::Sequence
<beans::PropertyValue
> format
;
1249 xNumRule
->getByIndex(i
) >>= format
;
1251 auto it(::std::find_if(format
.begin(), format
.end(),
1252 [](auto const& r
) { return r
.Name
== "NumberingType"; }));
1253 // need something RTL
1254 const_cast<uno::Any
&>(it
->Value
) <<= style::NumberingType::CHARS_ARABIC
;
1258 // this doesn't work any more
1259 auto it(::std::find_if(format
.begin(), format
.end(),
1260 [](auto const& r
) { return r
.Name
== "ParentNumbering"; }));
1261 const_cast<uno::Any
&>(it
->Value
) <<= sal_Int16(i
+ 1);
1263 listFormat
+= "%" + OUString::number(i
+1) + "%.";
1264 auto it(::std::find_if(format
.begin(), format
.end(),
1265 [](auto const& r
) { return r
.Name
== "ListFormat"; }));
1266 const_cast<uno::Any
&>(it
->Value
) <<= listFormat
;
1268 xNumRule
->replaceByIndex(i
, uno::Any(format
));
1270 uno::Reference
<beans::XPropertySet
>(getParagraph(1), uno::UNO_QUERY_THROW
)->setPropertyValue("NumberingRules", uno::Any(xNumRule
));
1271 xText
->insertControlCharacter(xText
->getEnd(), text::ControlCharacter::PARAGRAPH_BREAK
, false);
1272 uno::Reference
<beans::XPropertySet
>(getParagraph(2), uno::UNO_QUERY_THROW
)->setPropertyValue("NumberingLevel", uno::Any(sal_Int16(1)));
1273 xText
->insertControlCharacter(xText
->getEnd(), text::ControlCharacter::PARAGRAPH_BREAK
, false);
1274 uno::Reference
<beans::XPropertySet
>(getParagraph(3), uno::UNO_QUERY_THROW
)->setPropertyValue("NumberingLevel", uno::Any(sal_Int16(2)));
1276 // check PDF export of the list items (label in particular)
1277 utl::MediaDescriptor aMediaDescriptor
;
1278 aMediaDescriptor
["FilterName"] <<= OUString("writer_pdf_Export");
1280 uno::Sequence
<beans::PropertyValue
> aFilterData(
1281 comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } }));
1282 aMediaDescriptor
["FilterData"] <<= aFilterData
;
1283 css::uno::Reference
<frame::XStorable
> xStorable(mxComponent
, css::uno::UNO_QUERY_THROW
);
1284 xStorable
->storeToURL(maTempFile
.GetURL(), aMediaDescriptor
.getAsConstPropertyValueList());
1286 vcl::filter::PDFDocument aDocument
;
1287 SvFileStream
aStream(maTempFile
.GetURL(), StreamMode::READ
);
1288 CPPUNIT_ASSERT(aDocument
.Read(aStream
));
1290 // The document has one page.
1291 std::vector
<vcl::filter::PDFObjectElement
*> aPages
= aDocument
.GetPages();
1292 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages
.size());
1294 vcl::filter::PDFObjectElement
* pContents
= aPages
[0]->LookupObject("Contents");
1295 CPPUNIT_ASSERT(pContents
);
1296 vcl::filter::PDFStreamElement
* pStream
= pContents
->GetStream();
1297 CPPUNIT_ASSERT(pStream
);
1298 SvMemoryStream
& rObjectStream
= pStream
->GetMemory();
1300 SvMemoryStream aUncompressed
;
1302 aZCodec
.BeginCompression();
1303 rObjectStream
.Seek(0);
1304 aZCodec
.Decompress(rObjectStream
, aUncompressed
);
1305 CPPUNIT_ASSERT(aZCodec
.EndCompression());
1307 auto pStart
= static_cast<const char*>(aUncompressed
.GetData());
1308 const char* const pEnd
= pStart
+ aUncompressed
.GetSize();
1322 std::vector
<int> mcids
;
1326 auto const pLine
= ::std::find(pStart
, pEnd
, '\n');
1331 std::string_view
const line(pStart
, pLine
- pStart
);
1333 if (!line
.empty() && line
[0] != '%')
1335 ::std::cerr
<< nLine
<< ": " << line
<< "\n";
1336 if (o3tl::starts_with(line
, "/Lbl<</MCID") && o3tl::ends_with(line
, ">>BDC"))
1338 CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default
, state
);
1339 mcids
.push_back(o3tl::toInt32(line
.substr(12)));
1343 else if (state
== Lbl
)
1345 auto const endj(line
.find(">Tj"));
1346 if (endj
!= ::std::string_view::npos
)
1348 auto const start(line
.rfind("<", endj
) + 1);
1349 // for these, expected length is 1 glyphs, each 2 digits
1350 // would be better to check the content but it depends on CMap
1351 CPPUNIT_ASSERT_EQUAL(static_cast<decltype(endj
- start
)>(1 * 2), endj
- start
);
1352 state
= LblFoundText
;
1357 auto const endJ(line
.find("]TJ"));
1358 if (endJ
!= ::std::string_view::npos
)
1360 auto const start(line
.rfind("[", endJ
) + 1);
1361 auto i(line
.find("<", start
));
1363 while (i
!= ::std::string_view::npos
&& i
< endJ
)
1365 auto const j(line
.find(">", i
));
1366 digits
+= j
- (i
+1);
1367 i
= line
.find("<", j
);
1369 // these have list-level numbers + one less ".", each 2 digits
1370 CPPUNIT_ASSERT_EQUAL(static_cast<decltype(digits
)>((((nLbl
/2 + 1) * 2) - 1) * 2), digits
);
1371 state
= LblFoundText
;
1376 else if (state
!= Default
&& line
== "EMC")
1378 CPPUNIT_ASSERT_EQUAL_MESSAGE("missing text", LblFoundText
, state
);
1383 CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default
, state
);
1384 // ideally there should be 3 but apparently every text portion gets its own
1385 // tag - this should not be a problem if these are grouped in the structure
1387 CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nLbl
)>(6), nLbl
);
1388 // these are quite arbitrary?
1389 CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nLbl
)>(2), nLblTJ
);
1390 CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nLbl
)>(4), nLblTj
);
1393 for (const auto& rDocElement
: aDocument
.GetElements())
1395 auto pObject0
= dynamic_cast<vcl::filter::PDFObjectElement
*>(rDocElement
.get());
1398 auto pType0
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject0
->Lookup("Type"));
1399 if (!pType0
|| pType0
->GetValue() != "StructElem")
1403 auto pS0
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject0
->Lookup("S"));
1404 if (!pS0
|| pS0
->GetValue() != "Document")
1408 auto pKids0
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject0
->Lookup("K"));
1409 CPPUNIT_ASSERT(pKids0
);
1411 for (const auto& pKid0
: pKids0
->GetElements())
1413 auto pRefKid0
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKid0
);
1414 CPPUNIT_ASSERT(pRefKid0
);
1415 auto pObject1
= pRefKid0
->LookupObject();
1416 CPPUNIT_ASSERT(pObject1
);
1417 auto pType1
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1
->Lookup("Type"));
1418 CPPUNIT_ASSERT(pType1
);
1420 if (pType1
&& pType1
->GetValue() == "StructElem")
1422 auto pS1
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1
->Lookup("S"));
1423 if (pS1
&& pS1
->GetValue() == "L")
1426 auto pKids1
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject1
->Lookup("K"));
1427 CPPUNIT_ASSERT(pKids1
);
1428 // this is purely structural so there should be 1 child
1429 CPPUNIT_ASSERT_EQUAL(size_t(1), pKids1
->GetElements().size());
1431 auto pRefKid11
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids1
->GetElements()[0]);
1432 CPPUNIT_ASSERT(pRefKid11
);
1433 auto pObject11
= pRefKid11
->LookupObject();
1434 CPPUNIT_ASSERT(pObject11
);
1435 auto pType11
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject11
->Lookup("Type"));
1436 CPPUNIT_ASSERT(pType11
);
1437 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType11
->GetValue());
1438 auto pS11
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject11
->Lookup("S"));
1439 CPPUNIT_ASSERT(pS11
);
1440 CPPUNIT_ASSERT_EQUAL(OString("LI"), pS11
->GetValue());
1441 // LI has 2 children: Lbl and LBody
1442 auto pKids11
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject11
->Lookup("K"));
1443 CPPUNIT_ASSERT(pKids11
);
1444 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids11
->GetElements().size());
1446 auto pRefKid111
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids11
->GetElements()[0]);
1447 CPPUNIT_ASSERT(pRefKid111
);
1448 auto pObject111
= pRefKid111
->LookupObject();
1449 CPPUNIT_ASSERT(pObject111
);
1450 auto pType111
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject111
->Lookup("Type"));
1451 CPPUNIT_ASSERT(pType111
);
1452 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType111
->GetValue());
1453 auto pS111
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject111
->Lookup("S"));
1454 CPPUNIT_ASSERT(pS111
);
1455 CPPUNIT_ASSERT_EQUAL(OString("Lbl"), pS111
->GetValue());
1456 // Lbl has 2 children: the first 2 mcids (in order)
1457 auto pKids111
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject111
->Lookup("K"));
1458 CPPUNIT_ASSERT(pKids111
);
1459 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids111
->GetElements().size());
1461 auto pRefKid1111
= dynamic_cast<vcl::filter::PDFNumberElement
*>(pKids111
->GetElements()[0]);
1462 CPPUNIT_ASSERT(pRefKid1111
);
1463 CPPUNIT_ASSERT_EQUAL(mcids
[0], int(pRefKid1111
->GetValue()));
1464 auto pRefKid1112
= dynamic_cast<vcl::filter::PDFNumberElement
*>(pKids111
->GetElements()[1]);
1465 CPPUNIT_ASSERT(pRefKid1112
);
1466 CPPUNIT_ASSERT_EQUAL(mcids
[1], int(pRefKid1112
->GetValue()));
1468 auto pRefKid112
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids11
->GetElements()[1]);
1469 CPPUNIT_ASSERT(pRefKid112
);
1470 auto pObject112
= pRefKid112
->LookupObject();
1471 CPPUNIT_ASSERT(pObject112
);
1472 auto pType112
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112
->Lookup("Type"));
1473 CPPUNIT_ASSERT(pType112
);
1474 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType112
->GetValue());
1475 auto pS112
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112
->Lookup("S"));
1476 CPPUNIT_ASSERT(pS112
);
1477 CPPUNIT_ASSERT_EQUAL(OString("LBody"), pS112
->GetValue());
1478 // LBody has 2 children: paragraph and nested L (in order)
1479 auto pKids112
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject112
->Lookup("K"));
1480 CPPUNIT_ASSERT(pKids112
);
1481 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112
->GetElements().size());
1483 auto pRefKid1121
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids112
->GetElements()[0]);
1484 CPPUNIT_ASSERT(pRefKid1121
);
1485 auto pObject1121
= pRefKid1121
->LookupObject();
1486 CPPUNIT_ASSERT(pObject1121
);
1487 auto pType1121
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1121
->Lookup("Type"));
1488 CPPUNIT_ASSERT(pType1121
);
1489 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1121
->GetValue());
1490 auto pS1121
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1121
->Lookup("S"));
1491 CPPUNIT_ASSERT(pS1121
);
1492 CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS1121
->GetValue());
1494 auto pRefKid1122
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids112
->GetElements()[1]);
1495 CPPUNIT_ASSERT(pRefKid1122
);
1496 auto pObject1122
= pRefKid1122
->LookupObject();
1497 CPPUNIT_ASSERT(pObject1122
);
1498 auto pType1122
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122
->Lookup("Type"));
1499 CPPUNIT_ASSERT(pType1122
);
1500 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1122
->GetValue());
1501 auto pS1122
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122
->Lookup("S"));
1502 CPPUNIT_ASSERT(pS1122
);
1503 CPPUNIT_ASSERT_EQUAL(OString("L"), pS1122
->GetValue());
1504 auto pKids1122
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject1122
->Lookup("K"));
1505 CPPUNIT_ASSERT(pKids1122
);
1506 // this is purely structural so there should be 1 child
1507 CPPUNIT_ASSERT_EQUAL(size_t(1), pKids1122
->GetElements().size());
1509 auto pRefKid11221
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids1122
->GetElements()[0]);
1510 CPPUNIT_ASSERT(pRefKid11221
);
1511 auto pObject11221
= pRefKid11221
->LookupObject();
1512 CPPUNIT_ASSERT(pObject11221
);
1513 auto pType11221
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject11221
->Lookup("Type"));
1514 CPPUNIT_ASSERT(pType11221
);
1515 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType11221
->GetValue());
1516 auto pS11221
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject11221
->Lookup("S"));
1517 CPPUNIT_ASSERT(pS11221
);
1518 CPPUNIT_ASSERT_EQUAL(OString("LI"), pS11221
->GetValue());
1519 // LI has 2 children: Lbl and LBody
1520 auto pKids11221
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject11221
->Lookup("K"));
1521 CPPUNIT_ASSERT(pKids11221
);
1522 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids11221
->GetElements().size());
1524 auto pRefKid112211
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids11221
->GetElements()[0]);
1525 CPPUNIT_ASSERT(pRefKid112211
);
1526 auto pObject112211
= pRefKid112211
->LookupObject();
1527 CPPUNIT_ASSERT(pObject112211
);
1528 auto pType112211
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112211
->Lookup("Type"));
1529 CPPUNIT_ASSERT(pType112211
);
1530 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType112211
->GetValue());
1531 auto pS112211
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112211
->Lookup("S"));
1532 CPPUNIT_ASSERT(pS112211
);
1533 CPPUNIT_ASSERT_EQUAL(OString("Lbl"), pS112211
->GetValue());
1534 // Lbl has 2 children: the first 2 mcids (in order)
1535 auto pKids112211
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject112211
->Lookup("K"));
1536 CPPUNIT_ASSERT(pKids112211
);
1537 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112211
->GetElements().size());
1539 auto pRefKid1122111
= dynamic_cast<vcl::filter::PDFNumberElement
*>(pKids112211
->GetElements()[0]);
1540 CPPUNIT_ASSERT(pRefKid1122111
);
1541 CPPUNIT_ASSERT_EQUAL(mcids
[2], int(pRefKid1122111
->GetValue()));
1542 auto pRefKid1122112
= dynamic_cast<vcl::filter::PDFNumberElement
*>(pKids112211
->GetElements()[1]);
1543 CPPUNIT_ASSERT(pRefKid1122112
);
1544 CPPUNIT_ASSERT_EQUAL(mcids
[3], int(pRefKid1122112
->GetValue()));
1546 auto pRefKid112212
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids11221
->GetElements()[1]);
1547 CPPUNIT_ASSERT(pRefKid112212
);
1548 auto pObject112212
= pRefKid112212
->LookupObject();
1549 CPPUNIT_ASSERT(pObject112212
);
1550 auto pType112212
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112212
->Lookup("Type"));
1551 CPPUNIT_ASSERT(pType112212
);
1552 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType112212
->GetValue());
1553 auto pS112212
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112212
->Lookup("S"));
1554 CPPUNIT_ASSERT(pS112212
);
1555 CPPUNIT_ASSERT_EQUAL(OString("LBody"), pS112212
->GetValue());
1556 // LBody has 2 children: paragraph and nested L (in order)
1557 auto pKids112212
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject112212
->Lookup("K"));
1558 CPPUNIT_ASSERT(pKids112212
);
1559 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112212
->GetElements().size());
1561 auto pRefKid1122121
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids112212
->GetElements()[0]);
1562 CPPUNIT_ASSERT(pRefKid1122121
);
1563 auto pObject1122121
= pRefKid1122121
->LookupObject();
1564 CPPUNIT_ASSERT(pObject1122121
);
1565 auto pType1122121
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122121
->Lookup("Type"));
1566 CPPUNIT_ASSERT(pType1122121
);
1567 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1122121
->GetValue());
1568 auto pS1122121
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122121
->Lookup("S"));
1569 CPPUNIT_ASSERT(pS1122121
);
1570 CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS1122121
->GetValue());
1572 auto pRefKid1122122
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids112212
->GetElements()[1]);
1573 CPPUNIT_ASSERT(pRefKid1122122
);
1574 auto pObject1122122
= pRefKid1122122
->LookupObject();
1575 CPPUNIT_ASSERT(pObject1122122
);
1576 auto pType1122122
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122122
->Lookup("Type"));
1577 CPPUNIT_ASSERT(pType1122122
);
1578 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1122122
->GetValue());
1579 auto pS1122122
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122122
->Lookup("S"));
1580 CPPUNIT_ASSERT(pS1122122
);
1581 CPPUNIT_ASSERT_EQUAL(OString("L"), pS1122122
->GetValue());
1582 auto pKids1122122
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject1122122
->Lookup("K"));
1583 CPPUNIT_ASSERT(pKids1122122
);
1584 // this is purely structural so there should be 1 child
1585 CPPUNIT_ASSERT_EQUAL(size_t(1), pKids1122122
->GetElements().size());
1587 auto pRefKid11221221
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids1122122
->GetElements()[0]);
1588 CPPUNIT_ASSERT(pRefKid11221221
);
1589 auto pObject11221221
= pRefKid11221221
->LookupObject();
1590 CPPUNIT_ASSERT(pObject11221221
);
1591 auto pType11221221
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject11221221
->Lookup("Type"));
1592 CPPUNIT_ASSERT(pType11221221
);
1593 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType11221221
->GetValue());
1594 auto pS11221221
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject11221221
->Lookup("S"));
1595 CPPUNIT_ASSERT(pS11221221
);
1596 CPPUNIT_ASSERT_EQUAL(OString("LI"), pS11221221
->GetValue());
1597 // LI has 2 children: Lbl and LBody
1598 auto pKids11221221
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject11221221
->Lookup("K"));
1599 CPPUNIT_ASSERT(pKids11221221
);
1600 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids11221221
->GetElements().size());
1602 auto pRefKid112212211
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids11221221
->GetElements()[0]);
1603 CPPUNIT_ASSERT(pRefKid112212211
);
1604 auto pObject112212211
= pRefKid112212211
->LookupObject();
1605 CPPUNIT_ASSERT(pObject112212211
);
1606 auto pType112212211
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112212211
->Lookup("Type"));
1607 CPPUNIT_ASSERT(pType112212211
);
1608 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType112212211
->GetValue());
1609 auto pS112212211
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112212211
->Lookup("S"));
1610 CPPUNIT_ASSERT(pS112212211
);
1611 CPPUNIT_ASSERT_EQUAL(OString("Lbl"), pS112212211
->GetValue());
1612 // Lbl has 2 children: the first 2 mcids (in order)
1613 auto pKids112212211
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject112212211
->Lookup("K"));
1614 CPPUNIT_ASSERT(pKids112212211
);
1615 CPPUNIT_ASSERT_EQUAL(size_t(2), pKids112212211
->GetElements().size());
1617 auto pRefKid1122122111
= dynamic_cast<vcl::filter::PDFNumberElement
*>(pKids112212211
->GetElements()[0]);
1618 CPPUNIT_ASSERT(pRefKid1122122111
);
1619 CPPUNIT_ASSERT_EQUAL(mcids
[4], int(pRefKid1122122111
->GetValue()));
1620 auto pRefKid1122122112
= dynamic_cast<vcl::filter::PDFNumberElement
*>(pKids112212211
->GetElements()[1]);
1621 CPPUNIT_ASSERT(pRefKid1122122112
);
1622 CPPUNIT_ASSERT_EQUAL(mcids
[5], int(pRefKid1122122112
->GetValue()));
1624 auto pRefKid112212212
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids11221221
->GetElements()[1]);
1625 CPPUNIT_ASSERT(pRefKid112212212
);
1626 auto pObject112212212
= pRefKid112212212
->LookupObject();
1627 CPPUNIT_ASSERT(pObject112212212
);
1628 auto pType112212212
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112212212
->Lookup("Type"));
1629 CPPUNIT_ASSERT(pType112212212
);
1630 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType112212212
->GetValue());
1631 auto pS112212212
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject112212212
->Lookup("S"));
1632 CPPUNIT_ASSERT(pS112212212
);
1633 CPPUNIT_ASSERT_EQUAL(OString("LBody"), pS112212212
->GetValue());
1634 // inner LBody has 1 children: paragraph
1635 auto pKids112212212
= dynamic_cast<vcl::filter::PDFArrayElement
*>(pObject112212212
->Lookup("K"));
1636 CPPUNIT_ASSERT(pKids112212212
);
1637 CPPUNIT_ASSERT_EQUAL(size_t(1), pKids112212212
->GetElements().size());
1639 auto pRefKid1122122121
= dynamic_cast<vcl::filter::PDFReferenceElement
*>(pKids112212212
->GetElements()[0]);
1640 CPPUNIT_ASSERT(pRefKid1122122121
);
1641 auto pObject1122122121
= pRefKid1122122121
->LookupObject();
1642 CPPUNIT_ASSERT(pObject1122122121
);
1643 auto pType1122122121
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122122121
->Lookup("Type"));
1644 CPPUNIT_ASSERT(pType1122122121
);
1645 CPPUNIT_ASSERT_EQUAL(OString("StructElem"), pType1122122121
->GetValue());
1646 auto pS1122122121
= dynamic_cast<vcl::filter::PDFNameElement
*>(pObject1122122121
->Lookup("S"));
1647 CPPUNIT_ASSERT(pS1122122121
);
1648 CPPUNIT_ASSERT_EQUAL(OString("Standard"), pS1122122121
->GetValue());
1653 CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nL
)>(1), nL
);
1656 CPPUNIT_TEST_FIXTURE(Test
, testTdf143311
)
1658 createSwDoc("tdf143311-1.docx");
1659 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(getShape(1), "Decorative"));
1661 // add another one that's a SdrObject
1662 uno::Reference
<css::lang::XMultiServiceFactory
> xFactory(mxComponent
, uno::UNO_QUERY
);
1663 uno::Reference
<drawing::XShape
> xShape(
1664 xFactory
->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY
);
1665 uno::Reference
<beans::XPropertySet
> xShapeProps(xShape
, uno::UNO_QUERY
);
1666 xShapeProps
->setPropertyValue("Decorative", uno::Any(true));
1667 uno::Reference
<drawing::XDrawPageSupplier
> xDrawPageSupplier(mxComponent
, uno::UNO_QUERY
);
1668 uno::Reference
<drawing::XDrawPage
> xDrawPage(xDrawPageSupplier
->getDrawPage());
1669 xDrawPage
->add(xShape
);
1671 // check DOCX filters
1672 saveAndReload("Office Open XML Text");
1673 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(getShape(1), "Decorative"));
1674 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(getShape(2), "Decorative"));
1676 // tdf#153925 not imported - check default and set it to test ODF filters
1677 uno::Reference
<beans::XPropertySet
> const xStyle(getStyles("FrameStyles")->getByName("Formula"), uno::UNO_QUERY_THROW
);
1678 CPPUNIT_ASSERT_EQUAL(false, getProperty
<bool>(xStyle
, "Decorative"));
1679 xStyle
->setPropertyValue("Decorative", uno::Any(true));
1681 // check ODF filters
1682 saveAndReload("writer8");
1683 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(getShape(1), "Decorative"));
1684 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(getShape(2), "Decorative"));
1685 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(getStyles("FrameStyles")->getByName("Formula"), "Decorative"));
1688 utl::MediaDescriptor aMediaDescriptor
;
1689 aMediaDescriptor
["FilterName"] <<= OUString("writer_pdf_Export");
1691 uno::Sequence
<beans::PropertyValue
> aFilterData(
1692 comphelper::InitPropertySequence({ { "PDFUACompliance", uno::Any(true) } }));
1693 aMediaDescriptor
["FilterData"] <<= aFilterData
;
1694 css::uno::Reference
<frame::XStorable
> xStorable(mxComponent
, css::uno::UNO_QUERY_THROW
);
1695 xStorable
->storeToURL(maTempFile
.GetURL(), aMediaDescriptor
.getAsConstPropertyValueList());
1697 vcl::filter::PDFDocument aDocument
;
1698 SvFileStream
aStream(maTempFile
.GetURL(), StreamMode::READ
);
1699 CPPUNIT_ASSERT(aDocument
.Read(aStream
));
1701 // The document has one page.
1702 std::vector
<vcl::filter::PDFObjectElement
*> aPages
= aDocument
.GetPages();
1703 CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), aPages
.size());
1705 vcl::filter::PDFObjectElement
* pContents
= aPages
[0]->LookupObject("Contents");
1706 CPPUNIT_ASSERT(pContents
);
1707 vcl::filter::PDFStreamElement
* pStream
= pContents
->GetStream();
1708 CPPUNIT_ASSERT(pStream
);
1709 SvMemoryStream
& rObjectStream
= pStream
->GetMemory();
1711 SvMemoryStream aUncompressed
;
1713 aZCodec
.BeginCompression();
1714 rObjectStream
.Seek(0);
1715 aZCodec
.Decompress(rObjectStream
, aUncompressed
);
1716 CPPUNIT_ASSERT(aZCodec
.EndCompression());
1718 auto pStart
= static_cast<const char*>(aUncompressed
.GetData());
1719 const char* const pEnd
= pStart
+ aUncompressed
.GetSize();
1735 auto const pLine
= ::std::find(pStart
, pEnd
, '\n');
1740 std::string_view
const line(pStart
, pLine
- pStart
);
1742 if (!line
.empty() && line
[0] != '%')
1744 ::std::cerr
<< nLine
<< ": " << line
<< "\n";
1745 if (line
== "/Artifact BMC")
1747 CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default
, state
);
1751 else if (o3tl::starts_with(line
, "/Standard<</MCID") && o3tl::ends_with(line
, ">>BDC"))
1753 CPPUNIT_ASSERT_EQUAL_MESSAGE("unexpected nesting", Default
, state
);
1757 else if (line
== "EMC")
1759 CPPUNIT_ASSERT_MESSAGE("unexpected end", state
!= Default
);
1762 else if (nLine
> 1) // first line is expected "0.1 w"
1764 CPPUNIT_ASSERT_MESSAGE("unexpected content outside MCS", state
!= Default
);
1768 CPPUNIT_ASSERT_EQUAL_MESSAGE("unclosed MCS", Default
, state
);
1769 CPPUNIT_ASSERT_EQUAL(static_cast<decltype(nTagged
)>(25), nTagged
); // text in body
1770 // 1 decorative image + 1 decorative shape + 1 pre-existing rectangle border or something
1771 CPPUNIT_ASSERT(nArtifacts
>= 3);
1774 void Test::testTextFormField()
1776 const OUString aFilterNames
[] = {
1779 "Office Open XML Text",
1782 for (const OUString
& rFilterName
: aFilterNames
)
1784 createSwDoc("text_form_field.odt");
1786 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
1788 // Export the document and import again for a check
1789 saveAndReload(rFilterName
);
1791 // Check the document after round trip
1792 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1793 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pTextDoc
);
1794 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
1795 IDocumentMarkAccess
* pMarkAccess
= pDoc
->getIDocumentMarkAccess();
1797 // We have two text form fields
1798 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(2), pMarkAccess
->getAllMarksCount());
1800 // Check whether all fieldmarks are text form fields
1801 for(auto aIter
= pMarkAccess
->getAllMarksBegin(); aIter
!= pMarkAccess
->getAllMarksEnd(); ++aIter
)
1803 ::sw::mark::IFieldmark
* pFieldmark
= dynamic_cast<::sw::mark::IFieldmark
*>(*aIter
);
1804 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pFieldmark
);
1805 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(ODF_FORMTEXT
), pFieldmark
->GetFieldname());
1808 // In the first paragraph we have an empty text form field with the placeholder spaces
1809 const uno::Reference
< text::XTextRange
> xPara
= getParagraph(1);
1810 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("TextFieldStart"), getProperty
<OUString
>(getRun(xPara
, 1), "TextPortionType"));
1811 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("TextFieldSeparator"), getProperty
<OUString
>(getRun(xPara
, 2), "TextPortionType"));
1812 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("Text"), getProperty
<OUString
>(getRun(xPara
, 3), "TextPortionType"));
1813 sal_Unicode vEnSpaces
[5] = {8194, 8194, 8194, 8194, 8194};
1814 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(vEnSpaces
, 5), getRun(xPara
, 3)->getString());
1815 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("TextFieldEnd"), getProperty
<OUString
>(getRun(xPara
, 4), "TextPortionType"));
1817 // In the second paragraph we have a set text
1818 const uno::Reference
< text::XTextRange
> xPara2
= getParagraph(2);
1819 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("TextFieldStart"), getProperty
<OUString
>(getRun(xPara2
, 1), "TextPortionType"));
1820 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("TextFieldSeparator"), getProperty
<OUString
>(getRun(xPara2
, 2), "TextPortionType"));
1821 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("Text"), getProperty
<OUString
>(getRun(xPara2
, 3), "TextPortionType"));
1822 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("xxxxx"), getRun(xPara2
, 3)->getString());
1823 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("TextFieldEnd"), getProperty
<OUString
>(getRun(xPara2
, 4), "TextPortionType"));
1827 void Test::testCheckBoxFormField()
1829 const OUString aFilterNames
[] = {
1832 "Office Open XML Text",
1835 for (const OUString
& rFilterName
: aFilterNames
)
1837 createSwDoc("checkbox_form_field.odt");
1839 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
1841 // Export the document and import again for a check
1842 saveAndReload(rFilterName
);
1844 // Check the document after round trip
1845 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1846 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pTextDoc
);
1847 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
1848 IDocumentMarkAccess
* pMarkAccess
= pDoc
->getIDocumentMarkAccess();
1850 // We have two check box form fields
1851 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(2), pMarkAccess
->getAllMarksCount());
1854 for(auto aIter
= pMarkAccess
->getAllMarksBegin(); aIter
!= pMarkAccess
->getAllMarksEnd(); ++aIter
)
1856 ::sw::mark::IFieldmark
* pFieldmark
= dynamic_cast<::sw::mark::IFieldmark
*>(*aIter
);
1858 if(rFilterName
== "Office Open XML Text") // OOXML import also generates bookmarks
1864 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pFieldmark
);
1865 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(ODF_FORMCHECKBOX
), pFieldmark
->GetFieldname());
1866 ::sw::mark::ICheckboxFieldmark
* pCheckBox
= dynamic_cast< ::sw::mark::ICheckboxFieldmark
* >(pFieldmark
);
1867 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pCheckBox
);
1869 // The first one is unchecked, the other one is checked
1871 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), !pCheckBox
->IsChecked());
1873 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pCheckBox
->IsChecked());
1876 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), int(2), nIndex
);
1880 void Test::testDropDownFormField()
1882 const OUString aFilterNames
[] = {
1885 "Office Open XML Text",
1888 for (const OUString
& rFilterName
: aFilterNames
)
1890 createSwDoc("dropdown_form_field.odt");
1892 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
1894 // Export the document and import again for a check
1895 saveAndReload(rFilterName
);
1897 // Check the document after round trip
1898 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1899 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pTextDoc
);
1900 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
1901 IDocumentMarkAccess
* pMarkAccess
= pDoc
->getIDocumentMarkAccess();
1903 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(2), pMarkAccess
->getAllMarksCount());
1906 for(auto aIter
= pMarkAccess
->getAllMarksBegin(); aIter
!= pMarkAccess
->getAllMarksEnd(); ++aIter
)
1908 ::sw::mark::IFieldmark
* pFieldmark
= dynamic_cast<::sw::mark::IFieldmark
*>(*aIter
);
1913 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pFieldmark
);
1914 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(ODF_FORMDROPDOWN
), pFieldmark
->GetFieldname());
1916 // Check drop down field's parameters.
1917 const sw::mark::IFieldmark::parameter_map_t
* const pParameters
= pFieldmark
->GetParameters();
1918 css::uno::Sequence
<OUString
> vListEntries
;
1919 sal_Int32 nSelection
= -1;
1920 auto pListEntries
= pParameters
->find(ODF_FORMDROPDOWN_LISTENTRY
);
1921 if (pListEntries
!= pParameters
->end())
1923 pListEntries
->second
>>= vListEntries
;
1925 if(vListEntries
.hasElements())
1927 auto pResult
= pParameters
->find(ODF_FORMDROPDOWN_RESULT
);
1928 if (pResult
!= pParameters
->end())
1930 pResult
->second
>>= nSelection
;
1935 // The first one is empty
1938 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), !vListEntries
.hasElements());
1939 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(-1), nSelection
);
1941 else // The second one has list and also a selected item
1943 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(4), vListEntries
.getLength());
1944 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(1), nSelection
);
1945 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("1000"), vListEntries
[0]);
1946 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("2000"), vListEntries
[1]);
1947 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("3000"), vListEntries
[2]);
1948 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("4000"), vListEntries
[3]);
1952 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), int(2), nIndex
);
1956 void Test::testDateFormField()
1958 const OUString aFilterNames
[] = {
1960 "Office Open XML Text",
1963 for (const OUString
& rFilterName
: aFilterNames
)
1965 createSwDoc("date_form_field.odt");
1967 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
1969 // Export the document and import again for a check
1970 saveAndReload(rFilterName
);
1972 // Check the document after round trip
1973 if (rFilterName
== "writer8")
1975 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1976 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pTextDoc
);
1977 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
1978 IDocumentMarkAccess
* pMarkAccess
= pDoc
->getIDocumentMarkAccess();
1980 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(5), pMarkAccess
->getAllMarksCount());
1983 for(auto aIter
= pMarkAccess
->getAllMarksBegin(); aIter
!= pMarkAccess
->getAllMarksEnd(); ++aIter
)
1985 ::sw::mark::IDateFieldmark
* pFieldmark
= dynamic_cast<::sw::mark::IDateFieldmark
*>(*aIter
);
1986 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pFieldmark
);
1987 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(ODF_FORMDATE
), pFieldmark
->GetFieldname());
1989 // Check date form field's parameters.
1990 const sw::mark::IFieldmark::parameter_map_t
* const pParameters
= pFieldmark
->GetParameters();
1991 OUString sDateFormat
;
1992 auto pResult
= pParameters
->find(ODF_FORMDATE_DATEFORMAT
);
1993 if (pResult
!= pParameters
->end())
1995 pResult
->second
>>= sDateFormat
;
1999 pResult
= pParameters
->find(ODF_FORMDATE_DATEFORMAT_LANGUAGE
);
2000 if (pResult
!= pParameters
->end())
2002 pResult
->second
>>= sLang
;
2005 OUString sCurrentDate
= pFieldmark
->GetContent();
2007 // The first one has the default field content
2011 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("MM/DD/YY"), sDateFormat
);
2012 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("en-US"), sLang
);
2013 sal_Unicode vEnSpaces
[ODF_FORMFIELD_DEFAULT_LENGTH
] = {8194, 8194, 8194, 8194, 8194};
2014 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(vEnSpaces
, 5), sCurrentDate
);
2016 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), SwNodeOffset(9), pFieldmark
->GetMarkStart().GetNodeIndex());
2017 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(5), pFieldmark
->GetMarkStart().GetContentIndex());
2019 else if (nIndex
== 1) // The second has the default format
2021 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("MM/DD/YY"), sDateFormat
);
2022 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("en-US"), sLang
);
2023 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("06/12/19"), sCurrentDate
);
2025 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), SwNodeOffset(9), pFieldmark
->GetMarkStart().GetNodeIndex());
2026 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(20), pFieldmark
->GetMarkStart().GetContentIndex());
2028 else if (nIndex
== 2) // The third one has special format
2030 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("[NatNum12 MMMM=abbreviation]YYYY\". \"MMMM D."), sDateFormat
);
2031 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("hu-HU"), sLang
);
2032 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("2019. febr. 12."), sCurrentDate
);
2034 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), SwNodeOffset(9), pFieldmark
->GetMarkStart().GetNodeIndex());
2035 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(40), pFieldmark
->GetMarkStart().GetContentIndex());
2038 else if (nIndex
== 3) // The fourth one has placeholder text
2040 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("D, MMM YY"), sDateFormat
);
2041 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("bm-ML"), sLang
);
2042 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("[select date]"), sCurrentDate
);
2044 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), SwNodeOffset(9), pFieldmark
->GetMarkStart().GetNodeIndex());
2045 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(62), pFieldmark
->GetMarkStart().GetContentIndex());
2048 else // The last one is really empty
2050 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("MM/DD/YY"), sDateFormat
);
2051 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("en-US"), sLang
);
2052 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(""), sCurrentDate
);
2054 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), SwNodeOffset(9), pFieldmark
->GetMarkStart().GetNodeIndex());
2055 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(82), pFieldmark
->GetMarkStart().GetContentIndex());
2060 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), int(5), nIndex
);
2064 // Import from DOCX, so the fieldmark is now a content control.
2065 uno::Reference
<container::XEnumerationAccess
> xEnumAccess(getParagraph(1), uno::UNO_QUERY
);
2066 uno::Reference
<container::XEnumeration
> xTextPortions
= xEnumAccess
->createEnumeration();
2069 while (xTextPortions
->hasMoreElements())
2071 uno::Reference
<beans::XPropertySet
> xTextPortion(xTextPortions
->nextElement(), uno::UNO_QUERY
);
2072 OUString aPortionType
;
2073 xTextPortion
->getPropertyValue("TextPortionType") >>= aPortionType
;
2074 if (aPortionType
!= "ContentControl")
2079 uno::Reference
<text::XTextContent
> xContentControl
;
2080 xTextPortion
->getPropertyValue("ContentControl") >>= xContentControl
;
2081 uno::Reference
<beans::XPropertySet
> xContentControlProps(xContentControl
, uno::UNO_QUERY
);
2084 xContentControlProps
->getPropertyValue("Date") >>= bDate
;
2085 CPPUNIT_ASSERT(bDate
);
2087 // Check date form field's parameters.
2088 OUString sDateFormat
;
2089 xContentControlProps
->getPropertyValue("DateFormat") >>= sDateFormat
;
2092 xContentControlProps
->getPropertyValue("DateLanguage") >>= sLang
;
2094 uno::Reference
<container::XEnumerationAccess
> xContentControlEnumAccess(xContentControl
,
2096 uno::Reference
<container::XEnumeration
> xContentControlEnum
2097 = xContentControlEnumAccess
->createEnumeration();
2098 uno::Reference
<text::XTextRange
> xContentControlTextPortion(xContentControlEnum
->nextElement(), uno::UNO_QUERY
);
2099 OUString sCurrentDate
= xContentControlTextPortion
->getString();
2101 // The first one has the default field content
2104 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("MM/DD/YY"), sDateFormat
);
2105 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("en-US"), sLang
);
2106 sal_Unicode vEnSpaces
[ODF_FORMFIELD_DEFAULT_LENGTH
] = {8194, 8194, 8194, 8194, 8194};
2107 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(vEnSpaces
, 5), sCurrentDate
);
2109 else if (nIndex
== 1) // The second has the default format
2111 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("MM/DD/YY"), sDateFormat
);
2112 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("en-US"), sLang
);
2113 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("06/12/19"), sCurrentDate
);
2115 else if (nIndex
== 2) // The third one has special format
2117 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("[NatNum12 MMMM=abbreviation]YYYY\". \"MMMM D."), sDateFormat
);
2118 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("hu-HU"), sLang
);
2119 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("2019. febr. 12."), sCurrentDate
);
2121 else if (nIndex
== 3) // The fourth one has placeholder text
2123 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("D, MMM YY"), sDateFormat
);
2124 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("bm-ML"), sLang
);
2125 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("[select date]"), sCurrentDate
);
2127 else // The last one is really empty
2129 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("MM/DD/YY"), sDateFormat
);
2130 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString("en-US"), sLang
);
2131 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(""), sCurrentDate
);
2135 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), int(5), nIndex
);
2140 void Test::testDateFormFieldCharacterFormatting()
2142 const OUString aFilterNames
[] = {
2144 "Office Open XML Text",
2147 for (const OUString
& rFilterName
: aFilterNames
)
2149 createSwDoc("date_form_field_char_formatting.odt");
2151 const OString sFailedMessage
= OString::Concat("Failed on filter: ") + rFilterName
.toUtf8();
2153 // Export the document and import again for a check
2154 saveAndReload(rFilterName
);
2156 // Check the document after round trip
2157 if (rFilterName
== "writer8")
2159 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
2160 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pTextDoc
);
2161 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
2162 IDocumentMarkAccess
* pMarkAccess
= pDoc
->getIDocumentMarkAccess();
2164 // Check that we have the field at the right place
2165 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(1), pMarkAccess
->getAllMarksCount());
2166 ::sw::mark::IDateFieldmark
* pFieldmark
= dynamic_cast<::sw::mark::IDateFieldmark
*>(*pMarkAccess
->getAllMarksBegin());
2167 CPPUNIT_ASSERT_MESSAGE(sFailedMessage
.getStr(), pFieldmark
);
2168 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), OUString(ODF_FORMDATE
), pFieldmark
->GetFieldname());
2169 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(0), pFieldmark
->GetMarkStart().GetContentIndex());
2170 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), sal_Int32(11), pFieldmark
->GetMarkEnd().GetContentIndex());
2172 // We have one date field, first half of the field has bold character weight and second part has red character color
2173 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), awt::FontWeight::BOLD
, getProperty
<float>(getRun(getParagraph(1), 3), "CharWeight"));
2174 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_AUTO
, getProperty
<Color
>(getRun(getParagraph(1), 3), "CharColor"));
2175 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), awt::FontWeight::NORMAL
, getProperty
<float>(getRun(getParagraph(1), 4), "CharWeight"));
2176 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), Color(0xff0000), getProperty
<Color
>(getRun(getParagraph(1), 4), "CharColor"));
2180 uno::Reference
<beans::XPropertySet
> xTextPortion(getRun(getParagraph(1), 1), uno::UNO_QUERY
);
2181 OUString aPortionType
;
2182 xTextPortion
->getPropertyValue("TextPortionType") >>= aPortionType
;
2183 CPPUNIT_ASSERT_EQUAL(OUString("ContentControl"), aPortionType
);
2185 uno::Reference
<text::XTextContent
> xContentControl
;
2186 xTextPortion
->getPropertyValue("ContentControl") >>= xContentControl
;
2187 uno::Reference
<beans::XPropertySet
> xContentControlProps(xContentControl
, uno::UNO_QUERY
);
2189 xContentControlProps
->getPropertyValue("Date") >>= bDate
;
2190 CPPUNIT_ASSERT(bDate
);
2192 uno::Reference
<container::XEnumerationAccess
> xContentControlEnumAccess(xContentControl
,
2194 uno::Reference
<container::XEnumeration
> xContentControlEnum
2195 = xContentControlEnumAccess
->createEnumeration();
2196 xTextPortion
.set(xContentControlEnum
->nextElement(), uno::UNO_QUERY
);
2197 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), awt::FontWeight::BOLD
, getProperty
<float>(xTextPortion
, "CharWeight"));
2198 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), COL_AUTO
, getProperty
<Color
>(xTextPortion
, "CharColor"));
2199 xTextPortion
.set(xContentControlEnum
->nextElement(), uno::UNO_QUERY
);
2200 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), awt::FontWeight::NORMAL
, getProperty
<float>(xTextPortion
, "CharWeight"));
2201 CPPUNIT_ASSERT_EQUAL_MESSAGE(sFailedMessage
.getStr(), Color(0xff0000), getProperty
<Color
>(xTextPortion
, "CharColor"));
2206 CPPUNIT_TEST_SUITE_REGISTRATION(Test
);
2208 CPPUNIT_PLUGIN_IMPLEMENT();
2210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */