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 <sal/config.h>
12 #include <string_view>
14 #include <swmodeltestbase.hxx>
16 #include <com/sun/star/awt/FontWeight.hpp>
17 #include <com/sun/star/awt/Size.hpp>
18 #include <com/sun/star/beans/XPropertyState.hpp>
19 #include <com/sun/star/form/validation/XValidatableFormComponent.hpp>
20 #include <com/sun/star/frame/XStorable.hpp>
21 #include <com/sun/star/graphic/XGraphic.hpp>
22 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
23 #include <com/sun/star/drawing/XControlShape.hpp>
24 #include <com/sun/star/beans/XPropertySet.hpp>
25 #include <com/sun/star/view/XViewSettingsSupplier.hpp>
26 #include <com/sun/star/table/BorderLine2.hpp>
27 #include <com/sun/star/table/ShadowFormat.hpp>
28 #include <com/sun/star/table/TableBorder.hpp>
29 #include <com/sun/star/table/TableBorder2.hpp>
30 #include <com/sun/star/text/GraphicCrop.hpp>
31 #include <com/sun/star/text/WrapTextMode.hpp>
32 #include <com/sun/star/text/XFormField.hpp>
33 #include <com/sun/star/text/XTextField.hpp>
34 #include <com/sun/star/text/XTextFieldsSupplier.hpp>
35 #include <com/sun/star/text/XTextFramesSupplier.hpp>
36 #include <com/sun/star/text/XTextTablesSupplier.hpp>
37 #include <com/sun/star/view/DocumentZoomType.hpp>
38 #include <com/sun/star/rdf/URI.hpp>
39 #include <com/sun/star/rdf/Statement.hpp>
40 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
41 #include <com/sun/star/text/XPageCursor.hpp>
43 #include <config_fonts.h>
44 #include <editeng/ulspitem.hxx>
45 #include <sfx2/bindings.hxx>
46 #include <sfx2/request.hxx>
47 #include <comphelper/processfactory.hxx>
48 #include <tools/UnitConversion.hxx>
52 #include <swmodule.hxx>
55 #include <fmtsrnd.hxx>
56 #include <frameformats.hxx>
58 #include <pagedesc.hxx>
60 #include <bordertest.hxx>
61 #include <IDocumentSettingAccess.hxx>
63 #include <unotxdoc.hxx>
64 #include <o3tl/string_view.hxx>
66 class Test
: public SwModelTestBase
69 Test() : SwModelTestBase("/sw/qa/extras/ww8export/data/", "MS Word 97") {}
72 DECLARE_WW8EXPORT_TEST(testN757910
, "n757910.doc")
74 // The internal margin was larger than 0.28cm
75 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
76 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
77 uno::Reference
<beans::XPropertySet
> xPropertySet(xIndexAccess
->getByIndex(0), uno::UNO_QUERY
);
79 xPropertySet
->getPropertyValue("LeftBorderDistance") >>= nValue
;
80 CPPUNIT_ASSERT_EQUAL(sal_Int32(280), nValue
);
82 // The border width was zero
83 table::BorderLine2 aBorder
;
84 xPropertySet
->getPropertyValue("LeftBorder") >>= aBorder
;
85 CPPUNIT_ASSERT(aBorder
.LineWidth
> 0);
88 DECLARE_WW8EXPORT_TEST(testN760294
, "n760294.doc")
90 uno::Reference
<text::XTextTablesSupplier
> xTextTablesSupplier(mxComponent
, uno::UNO_QUERY
);
91 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextTablesSupplier
->getTextTables(), uno::UNO_QUERY
);
92 uno::Reference
<beans::XPropertySet
> xTable(xIndexAccess
->getByIndex(0), uno::UNO_QUERY
);
93 table::TableBorder aTableBorder
;
94 xTable
->getPropertyValue("TableBorder") >>= aTableBorder
;
95 CPPUNIT_ASSERT_EQUAL(aTableBorder
.TopLine
.InnerLineWidth
, aTableBorder
.TopLine
.OuterLineWidth
);
96 CPPUNIT_ASSERT_EQUAL(aTableBorder
.TopLine
.InnerLineWidth
, aTableBorder
.TopLine
.LineDistance
);
99 DECLARE_WW8EXPORT_TEST(testN750255
, "n750255.doc")
102 Column break without columns on the page is a page break, so check those paragraphs
103 are on page 2 (page style 'Convert 1') and page 3 (page style 'Convert 2')
104 enum = ThisComponent.Text.createEnumeration
106 para1 = enum.nextElement
108 xray para1.PageStyleName
109 para2 = enum.nextElement
111 xray para2.PageStyleName
113 uno::Reference
<text::XTextDocument
> textDocument(mxComponent
, uno::UNO_QUERY
);
114 uno::Reference
<container::XEnumerationAccess
> paraEnumAccess(textDocument
->getText(), uno::UNO_QUERY
);
115 // list of paragraphs
116 uno::Reference
<container::XEnumeration
> paraEnum
= paraEnumAccess
->createEnumeration();
117 // go to 1st paragraph
118 (void) paraEnum
->nextElement();
119 // get the 2nd and 3rd paragraph
120 uno::Reference
<uno::XInterface
> paragraph1(paraEnum
->nextElement(), uno::UNO_QUERY
);
121 uno::Reference
<uno::XInterface
> paragraph2(paraEnum
->nextElement(), uno::UNO_QUERY
);
122 uno::Reference
<text::XTextRange
> text1(paragraph1
, uno::UNO_QUERY
);
123 uno::Reference
<text::XTextRange
> text2(paragraph2
, uno::UNO_QUERY
);
124 CPPUNIT_ASSERT_EQUAL( OUString( "one" ), text1
->getString());
125 CPPUNIT_ASSERT_EQUAL( OUString( "two" ), text2
->getString());
126 uno::Reference
<beans::XPropertySet
> paragraphProperties1(paragraph1
, uno::UNO_QUERY
);
127 uno::Reference
<beans::XPropertySet
> paragraphProperties2(paragraph2
, uno::UNO_QUERY
);
128 OUString pageStyle1
, pageStyle2
;
129 paragraphProperties1
->getPropertyValue( "PageStyleName" ) >>= pageStyle1
;
130 paragraphProperties2
->getPropertyValue( "PageStyleName" ) >>= pageStyle2
;
131 CPPUNIT_ASSERT_EQUAL( OUString( "Convert 1" ), pageStyle1
);
132 CPPUNIT_ASSERT_EQUAL( OUString( "Convert 2" ), pageStyle2
);
136 DECLARE_WW8EXPORT_TEST(testN652364
, "n652364.doc")
139 Related to 750255 above, column break with columns on the page however should be a column break.
140 enum = ThisComponent.Text.createEnumeration
142 para1 = enum.nextElement
144 xray para1.PageStyleName
146 para2 = enum.nextElement
148 xray para2.PageStyleName
150 uno::Reference
<text::XTextDocument
> textDocument(mxComponent
, uno::UNO_QUERY
);
151 uno::Reference
<container::XEnumerationAccess
> paraEnumAccess(textDocument
->getText(), uno::UNO_QUERY
);
152 // list of paragraphs
153 uno::Reference
<container::XEnumeration
> paraEnum
= paraEnumAccess
->createEnumeration();
154 // get the 2nd and 4th paragraph
155 (void) paraEnum
->nextElement();
156 uno::Reference
<uno::XInterface
> paragraph1(paraEnum
->nextElement(), uno::UNO_QUERY
);
157 (void) paraEnum
->nextElement();
158 uno::Reference
<uno::XInterface
> paragraph2(paraEnum
->nextElement(), uno::UNO_QUERY
);
159 uno::Reference
<text::XTextRange
> text1(paragraph1
, uno::UNO_QUERY
);
160 uno::Reference
<text::XTextRange
> text2(paragraph2
, uno::UNO_QUERY
);
161 CPPUNIT_ASSERT_EQUAL( OUString( "text1" ), text1
->getString());
162 CPPUNIT_ASSERT_EQUAL( OUString( "text2" ), text2
->getString());
163 uno::Reference
<beans::XPropertySet
> paragraphProperties1(paragraph1
, uno::UNO_QUERY
);
164 uno::Reference
<beans::XPropertySet
> paragraphProperties2(paragraph2
, uno::UNO_QUERY
);
165 OUString pageStyle1
, pageStyle2
;
166 paragraphProperties1
->getPropertyValue( "PageStyleName" ) >>= pageStyle1
;
167 paragraphProperties2
->getPropertyValue( "PageStyleName" ) >>= pageStyle2
;
168 // "Standard" is the style for the first page (2nd is "Convert 1").
169 CPPUNIT_ASSERT_EQUAL( OUString( "Standard" ), pageStyle1
);
170 CPPUNIT_ASSERT_EQUAL( OUString( "Standard" ), pageStyle2
);
173 DECLARE_WW8EXPORT_TEST(testN757118
, "n757118.doc")
176 Two pairs of horizontal rules (one absolute width, one relative width)
177 have the same width (full page width, half page width).
178 xray ThisComponent.DrawPage.getByIndex(0).BoundRect
180 uno::Reference
<drawing::XShape
> rule1
= getShape(1), rule2
= getShape(2), rule3
= getShape(3), rule4
= getShape(4);
181 uno::Reference
<beans::XPropertySet
> ruleProperties1(rule1
, uno::UNO_QUERY
);
182 uno::Reference
<beans::XPropertySet
> ruleProperties2(rule2
, uno::UNO_QUERY
);
183 uno::Reference
<beans::XPropertySet
> ruleProperties3(rule3
, uno::UNO_QUERY
);
184 uno::Reference
<beans::XPropertySet
> ruleProperties4(rule4
, uno::UNO_QUERY
);
185 awt::Rectangle boundRect1
, boundRect2
, boundRect3
, boundRect4
;
186 ruleProperties1
->getPropertyValue( "BoundRect" ) >>= boundRect1
;
187 ruleProperties2
->getPropertyValue( "BoundRect" ) >>= boundRect2
;
188 ruleProperties3
->getPropertyValue( "BoundRect" ) >>= boundRect3
;
189 ruleProperties4
->getPropertyValue( "BoundRect" ) >>= boundRect4
;
190 // compare, allow for < 5 differences because of rounding errors
191 CPPUNIT_ASSERT( abs( boundRect1
.Width
- boundRect3
.Width
) < 5 );
192 CPPUNIT_ASSERT( abs( boundRect2
.Width
- boundRect4
.Width
) < 5 );
195 DECLARE_WW8EXPORT_TEST(testTdf75539_relativeWidth
, "tdf75539_relativeWidth.doc")
197 //divide everything by 10 to give a margin of error for rounding etc.
198 sal_Int32 pageWidth
= parseDump("/root/page[1]/body/infos/bounds", "width").toInt32()/10;
199 CPPUNIT_ASSERT_EQUAL_MESSAGE("Page width", sal_Int32(9354/10), pageWidth
);
200 CPPUNIT_ASSERT_EQUAL_MESSAGE("100% width line", pageWidth
, parseDump("/root/page[1]/body/txt[2]/SwParaPortion/SwLineLayout/SwLinePortion", "width").toInt32()/10);
201 CPPUNIT_ASSERT_EQUAL_MESSAGE("50% width line", pageWidth
/2, parseDump("/root/page[1]/body/txt[4]/SwParaPortion/SwLineLayout/SwLinePortion", "width").toInt32()/10);
202 CPPUNIT_ASSERT_EQUAL_MESSAGE("25% width line", pageWidth
/4, parseDump("/root/page[1]/body/txt[6]/SwParaPortion/SwLineLayout/SwLinePortion", "width").toInt32()/10);
203 CPPUNIT_ASSERT_EQUAL_MESSAGE("10% width line", pageWidth
/10, parseDump("/root/page[1]/body/txt[8]/SwParaPortion/SwLineLayout/SwLinePortion", "width").toInt32()/10);
206 DECLARE_WW8EXPORT_TEST(testN757905
, "n757905.doc")
208 // The problem was that the paragraph had only a single fly
209 // (as-character-anchored), and the height of that was smaller than the
210 // paragraph height. When in Word-compat mode, we should take the max of
211 // the two, not just the height of the fly.
213 OUString aHeight
= parseDump("/root/page/body/txt/infos/bounds", "height");
214 CPPUNIT_ASSERT(sal_Int32(31) < aHeight
.toInt32());
217 DECLARE_WW8EXPORT_TEST(testAllGapsWord
, "all_gaps_word.doc")
219 BorderTest borderTest
;
220 BorderTest::testTheBorders(mxComponent
, true);
223 DECLARE_WW8EXPORT_TEST(testI120158
, "i120158.doc")
225 // See https://bz.apache.org/ooo/show_bug.cgi?id=120158
226 uno::Reference
<text::XTextDocument
> textDocument(mxComponent
, uno::UNO_QUERY
);
227 uno::Reference
<container::XEnumerationAccess
> paraEnumAccess(textDocument
->getText(), uno::UNO_QUERY
);
228 // list of paragraphs
229 uno::Reference
<container::XEnumeration
> paraEnum
= paraEnumAccess
->createEnumeration();
230 // get contents of 1st paragraph as text
231 uno::Reference
<uno::XInterface
> paragraph0(paraEnum
->nextElement(), uno::UNO_QUERY
);
232 uno::Reference
<text::XTextRange
> text0(paragraph0
, uno::UNO_QUERY
);
233 OUString sFieldResult
= text0
->getString();
234 CPPUNIT_ASSERT(sFieldResult
.endsWith("AM") || sFieldResult
.endsWith("PM"));
237 DECLARE_WW8EXPORT_TEST(testN816603
, "n816603.doc")
239 // Bugdoc was 5 pages in Word, 1 in Writer due to pointlessly wrapping the
240 // table in a frame. Exact layout may depend on fonts available, etc. --
241 // but at least make sure that our table spans over multiple pages now.
242 CPPUNIT_ASSERT(getPages() > 1);
245 DECLARE_WW8EXPORT_TEST(testPageBorder
, "page-border.doc")
247 // Page border was missing (LineWidth was 0), due to wrong interpretation of pgbApplyTo.
248 table::BorderLine2 aBorder
= getProperty
<table::BorderLine2
>(getStyles("PageStyles")->getByName("Standard"), "TopBorder");
249 CPPUNIT_ASSERT_EQUAL(sal_uInt32(convertTwipToMm100(6 * 20)), aBorder
.LineWidth
);
252 DECLARE_WW8EXPORT_TEST(testN823651
, "n823651.doc")
254 // Character height was 10pt instead of 7.5pt in the header.
255 uno::Reference
<beans::XPropertySet
> xStyle(getStyles("PageStyles")->getByName("Standard"), uno::UNO_QUERY
);
256 uno::Reference
<text::XText
> xText
= getProperty
< uno::Reference
<text::XTextRange
> >(xStyle
, "HeaderTextFirst")->getText();
257 CPPUNIT_ASSERT_EQUAL(7.5f
, getProperty
<float>(getParagraphOfText(1, xText
), "CharHeight"));
260 DECLARE_WW8EXPORT_TEST(testFdo36868
, "fdo36868.doc")
262 OUString aText
= parseDump("/root/page/body/txt[3]/SwParaPortion/SwLineLayout/child::*[@type='PortionType::Number']", "expand");
264 CPPUNIT_ASSERT_EQUAL(OUString("2.1"), aText
);
267 DECLARE_WW8EXPORT_TEST(testListNolevel
, "list-nolevel.doc")
269 // Similar to fdo#36868, numbering portions had wrong values.
270 OUString aText
= parseDump("/root/page/body/txt[1]/SwParaPortion/SwLineLayout/child::*[@type='PortionType::Number']", "expand");
271 // PortionType::Number was completely missing.
272 CPPUNIT_ASSERT_EQUAL(OUString("1."), aText
);
275 DECLARE_WW8EXPORT_TEST(testHeaderApoTable
, "ooo92948-1.doc")
277 // the problem was that a table anchored in the header was split across
278 // 3 text frames and quite messed up
280 uno::Reference
<text::XTextFramesSupplier
> xTextFramesSupplier(mxComponent
, uno::UNO_QUERY
);
281 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextFramesSupplier
->getTextFrames(), uno::UNO_QUERY
);
282 uno::Reference
<text::XText
> xFrame(xIndexAccess
->getByIndex(1), uno::UNO_QUERY
);
284 // uno::Reference<text::XText> xHeaderText = getProperty<uno::Reference<text::XText>>(getStyles("PageStyles")->getByName("Standard"), "HeaderTextFirst");
285 // uno::Reference<text::XTextRange> xPara(getParagraphOfText(9, xHeaderText));
286 //TODO why does this not work
287 // uno::Reference<beans::XPropertySet> xFrame(getParagraphAnchoredObject(1, xPara));
289 uno::Reference
<text::XTextContent
> xTable(getParagraphOrTable(1, xFrame
));
290 getCell(xTable
, "A1", "Aan" SAL_NEWLINE_STRING
"Recipient" SAL_NEWLINE_STRING
"Recipient" SAL_NEWLINE_STRING
);
291 getCell(xTable
, "A2", "Kopie aan" SAL_NEWLINE_STRING
);
292 getCell(xTable
, "A3", "Datum" SAL_NEWLINE_STRING
"31 juli 2008");
293 getCell(xTable
, "A4", "Locatie" SAL_NEWLINE_STRING
"Locationr");
294 getCell(xTable
, "A5", "Van" SAL_NEWLINE_STRING
"Sender ");
295 getCell(xTable
, "A6", "Directie" SAL_NEWLINE_STRING
"Department");
296 getCell(xTable
, "A7", "Telefoon" SAL_NEWLINE_STRING
"Phone");
299 DECLARE_WW8EXPORT_TEST(testBnc821208
, "bnc821208.doc")
301 // WW8Num1z0 earned a Symbol font, turning numbers into rectangles.
302 uno::Reference
<beans::XPropertyState
> xPropertyState(getStyles("CharacterStyles")->getByName("WW8Num1z0"), uno::UNO_QUERY
);
303 beans::PropertyState ePropertyState
= xPropertyState
->getPropertyState("CharFontName");
304 // This was beans::PropertyState_DIRECT_VALUE.
305 CPPUNIT_ASSERT_EQUAL(beans::PropertyState_DEFAULT_VALUE
, ePropertyState
);
307 // Background of the numbering itself should have been the default, was yellow (0xffff00).
308 CPPUNIT_ASSERT_EQUAL(sal_Int32(-1), getProperty
<sal_Int32
>(xPropertyState
, "CharBackColor"));
311 DECLARE_WW8EXPORT_TEST(testCp1000044
, "cp1000044.doc")
313 uno::Reference
<frame::XStorable
> xStorable(mxComponent
, uno::UNO_QUERY
);
314 // It wasn't possible to fill out this form.
315 CPPUNIT_ASSERT_EQUAL(false, bool(xStorable
->isReadonly()));
317 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
318 CPPUNIT_ASSERT(pTextDoc
);
319 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
320 CPPUNIT_ASSERT_EQUAL( true, pDoc
->getIDocumentSettingAccess().get( DocumentSettingId::PROTECT_FORM
) );
322 uno::Sequence
<beans::PropertyValue
> aGrabBag
= getProperty
< uno::Sequence
<beans::PropertyValue
> >(mxComponent
, "InteropGrabBag");
323 sal_Int32 nPasswordHash
= 0;
324 for ( sal_Int32 i
= 0; i
< aGrabBag
.getLength(); ++i
)
326 if ( aGrabBag
[i
].Name
== "FormPasswordHash" )
327 aGrabBag
[i
].Value
>>= nPasswordHash
;
329 CPPUNIT_ASSERT_EQUAL_MESSAGE("Password Hash", sal_Int32(609995782), nPasswordHash
);
332 DECLARE_WW8EXPORT_TEST(testBorderColours
, "bordercolours.doc")
334 // The following 6 colours can only be represented with WW9 (Word 2000)
335 // BRC (BoRder Control) structures. We can tell that they have been
336 // exported/imported using a WW8 (Word '97) BRC if they instead come
337 // through as one of the 16 colours listed at this link:
338 // http://msdn.microsoft.com/en-us/library/dd773060.aspx
339 table::BorderLine2
expectedTop(0xFA670C, 0, 53, 0, 1, 53);
340 table::BorderLine2
expectedLeft(0xD99594, 0, 79, 0, 0, 79);
341 table::BorderLine2
expectedRight(0xB2A1C7, 53, 53, 53, 3, 159);
342 table::BorderLine2
expectedBottom(0xB6DDE8, 0, 106, 0, 14, 106);
343 table::BorderLine2
expectedDashedRed(0xFA670C, 0, 53, 0, 2, 53);
344 table::BorderLine2
expectedDoubleGreen(0xC2D69B, 26, 106, 26, 4, 159);
347 uno::Reference
<text::XBookmarksSupplier
> bookmarksSupplier(mxComponent
,
349 uno::Reference
<container::XNameAccess
> bookmarks
=
350 bookmarksSupplier
->getBookmarks();
351 uno::Reference
<text::XTextContent
> bookmark(
352 bookmarks
->getByName("ParagraphBorder"), uno::UNO_QUERY
);
353 uno::Reference
<text::XTextRange
> anchor(bookmark
->getAnchor());
354 table::BorderLine2 border
;
355 border
= getProperty
<table::BorderLine2
>(anchor
, "TopBorder");
356 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
357 border
= getProperty
<table::BorderLine2
>(anchor
, "LeftBorder");
358 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
359 border
= getProperty
<table::BorderLine2
>(anchor
, "RightBorder");
360 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
361 border
= getProperty
<table::BorderLine2
>(anchor
, "BottomBorder");
362 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
365 OUString pageStyleName
= getProperty
<OUString
>(anchor
, "PageStyleName");
366 uno::Reference
<style::XStyle
> pageStyle(
367 getStyles("PageStyles")->getByName(pageStyleName
), uno::UNO_QUERY
);
368 border
= getProperty
<table::BorderLine2
>(pageStyle
, "TopBorder");
369 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
370 border
= getProperty
<table::BorderLine2
>(pageStyle
, "LeftBorder");
371 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
372 border
= getProperty
<table::BorderLine2
>(pageStyle
, "RightBorder");
373 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
374 border
= getProperty
<table::BorderLine2
>(pageStyle
, "BottomBorder");
375 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
378 bookmark
.set(bookmarks
->getByName("CharBorder"), uno::UNO_QUERY
);
379 anchor
= bookmark
->getAnchor();
380 border
= getProperty
<table::BorderLine2
>(anchor
, "CharTopBorder");
381 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
382 border
= getProperty
<table::BorderLine2
>(anchor
, "CharLeftBorder");
383 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
384 border
= getProperty
<table::BorderLine2
>(anchor
, "CharRightBorder");
385 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
386 border
= getProperty
<table::BorderLine2
>(anchor
, "CharBottomBorder");
387 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
390 uno::Reference
<text::XTextTablesSupplier
> tablesSupplier(mxComponent
,
392 uno::Reference
<container::XNameAccess
> tables
=
393 tablesSupplier
->getTextTables();
394 uno::Reference
<text::XTextTable
> table(
395 tables
->getByName("Table1"), uno::UNO_QUERY
);
396 table::TableBorder2 tableBorder
= getProperty
<table::TableBorder2
>(
397 table
, "TableBorder2");
398 CPPUNIT_ASSERT_EQUAL(expectedTop
.Color
, tableBorder
.TopLine
.Color
);
399 CPPUNIT_ASSERT_EQUAL(expectedLeft
.Color
, tableBorder
.LeftLine
.Color
);
400 CPPUNIT_ASSERT_EQUAL(expectedRight
.Color
, tableBorder
.RightLine
.Color
);
401 CPPUNIT_ASSERT_EQUAL(expectedBottom
.Color
, tableBorder
.BottomLine
.Color
);
404 uno::Reference
<table::XCell
> cell
=
405 table
->getCellByName("A2");
406 border
= getProperty
<table::BorderLine2
>(cell
, "TopBorder");
407 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
408 border
= getProperty
<table::BorderLine2
>(cell
, "LeftBorder");
409 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
410 border
= getProperty
<table::BorderLine2
>(cell
, "BottomBorder");
411 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
413 cell
= table
->getCellByName("B2");
414 border
= getProperty
<table::BorderLine2
>(cell
, "TopBorder");
415 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
416 border
= getProperty
<table::BorderLine2
>(cell
, "LeftBorder");
417 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
418 border
= getProperty
<table::BorderLine2
>(cell
, "BottomBorder");
419 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
421 cell
= table
->getCellByName("C2");
422 border
= getProperty
<table::BorderLine2
>(cell
, "TopBorder");
423 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
424 border
= getProperty
<table::BorderLine2
>(cell
, "LeftBorder");
425 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDashedRed
, border
);
426 border
= getProperty
<table::BorderLine2
>(cell
, "RightBorder");
427 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
428 border
= getProperty
<table::BorderLine2
>(cell
, "BottomBorder");
429 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
432 // (#if'd out as they are not yet imported with correct colours)
434 bookmark
.set(bookmarks
->getByName("PictureBorder"),uno::UNO_QUERY
);
435 anchor
= bookmark
->getAnchor();
436 border
= getProperty
<table::BorderLine2
>(anchor
, "TopBorder");
437 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
438 border
= getProperty
<table::BorderLine2
>(anchor
, "LeftBorder");
439 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
440 border
= getProperty
<table::BorderLine2
>(anchor
, "RightBorder");
441 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
442 border
= getProperty
<table::BorderLine2
>(anchor
, "BottomBorder");
443 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
447 DECLARE_WW8EXPORT_TEST(testMsoBrightnessContrast
, "msobrightnesscontrast.doc")
449 uno::Reference
<drawing::XShape
> image
= getShape(1);
450 uno::Reference
<beans::XPropertySet
> imageProperties(image
, uno::UNO_QUERY
);
451 uno::Reference
<graphic::XGraphic
> graphic
;
452 imageProperties
->getPropertyValue( "Graphic" ) >>= graphic
;
453 Graphic
vclGraphic(graphic
);
454 BitmapEx
bitmap(vclGraphic
.GetBitmapEx());
455 CPPUNIT_ASSERT_EQUAL( tools::Long(58), bitmap
.GetSizePixel().Width());
456 CPPUNIT_ASSERT_EQUAL( tools::Long(320), bitmap
.GetSizePixel().Height());
457 CPPUNIT_ASSERT_EQUAL( Color(206,206,206), bitmap
.GetPixelColor(16,27));
458 CPPUNIT_ASSERT_EQUAL( Color(206,206,206), bitmap
.GetPixelColor(22,48));
461 DECLARE_WW8EXPORT_TEST(testTdf95321
, "tdf95321.doc")
463 // The problem was that there should be content in the second cell
465 uno::Reference
<text::XTextTablesSupplier
> xTextTablesSupplier(mxComponent
, uno::UNO_QUERY
);
466 uno::Reference
<container::XIndexAccess
> xIndexAccess(xTextTablesSupplier
->getTextTables(), uno::UNO_QUERY
);
467 uno::Reference
<text::XTextTable
> xTable(xIndexAccess
->getByIndex(0), uno::UNO_QUERY
);
468 CPPUNIT_ASSERT_EQUAL(OUString("Second Column"), uno::Reference
<text::XTextRange
>(xTable
->getCellByName("B1"), uno::UNO_QUERY_THROW
)->getString());
471 DECLARE_WW8EXPORT_TEST(testFdo77844
, "fdo77844.doc")
473 uno::Reference
<container::XNameAccess
> pageStyles
= getStyles("PageStyles");
476 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
477 uno::Reference
<text::XTextViewCursorSupplier
> xTextViewCursorSupplier(
478 xModel
->getCurrentController(), uno::UNO_QUERY
);
479 uno::Reference
<text::XPageCursor
> xCursor(
480 xTextViewCursorSupplier
->getViewCursor(), uno::UNO_QUERY
);
482 // check that the first page has no header
483 xCursor
->jumpToFirstPage();
484 OUString pageStyleName
= getProperty
<OUString
>(xCursor
, "PageStyleName");
485 uno::Reference
<style::XStyle
> pageStyle(
486 pageStyles
->getByName(pageStyleName
), uno::UNO_QUERY
);
487 bool headerIsOn
= getProperty
<bool>(pageStyle
, "HeaderIsOn");
488 CPPUNIT_ASSERT(!headerIsOn
);
490 // check that the second page has a header
491 xCursor
->jumpToPage(2);
492 pageStyleName
= getProperty
<OUString
>(xCursor
, "PageStyleName");
494 pageStyles
->getByName(pageStyleName
), uno::UNO_QUERY
);
495 headerIsOn
= getProperty
<bool>(pageStyle
, "HeaderIsOn");
496 CPPUNIT_ASSERT(headerIsOn
);
498 // check that the third page has a header
499 xCursor
->jumpToPage(3);
500 pageStyleName
= getProperty
<OUString
>(xCursor
, "PageStyleName");
502 pageStyles
->getByName(pageStyleName
), uno::UNO_QUERY
);
503 headerIsOn
= getProperty
<bool>(pageStyle
, "HeaderIsOn");
504 CPPUNIT_ASSERT(headerIsOn
);
506 // check that the fourth page has no header
507 // (#if'd out as this is not yet imported correctly)
509 xCursor
->jumpToPage(4);
510 pageStyleName
= getProperty
<OUString
>(xCursor
, "PageStyleName");
512 pageStyles
->getByName(pageStyleName
), uno::UNO_QUERY
);
513 headerIsOn
= getProperty
<bool>(pageStyle
, "HeaderIsOn");
514 CPPUNIT_ASSERT(!headerIsOn
);
518 DECLARE_WW8EXPORT_TEST(testFdp80333
, "fdo80333.doc")
520 // Despite there is no character border, border shadow was imported
521 uno::Reference
<beans::XPropertySet
> xRun(getRun(getParagraph(1),1), uno::UNO_QUERY
);
522 const table::ShadowFormat aShadow
= getProperty
<table::ShadowFormat
>(xRun
, "CharShadowFormat");
523 CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_NONE
, aShadow
.Location
);
526 DECLARE_WW8EXPORT_TEST(testFdo81102
, "fdo81102.doc")
528 // get page style at beginning of document
529 uno::Reference
<text::XTextDocument
> textDocument(
530 mxComponent
, uno::UNO_QUERY
);
531 uno::Reference
<text::XTextRange
> start
=
532 textDocument
->getText()->getStart();
533 OUString pageStyleName
= getProperty
<OUString
>(start
, "PageStyleName");
534 uno::Reference
<style::XStyle
> pageStyle(
535 getStyles("PageStyles")->getByName(pageStyleName
), uno::UNO_QUERY
);
537 // check that left and right pages do not share the same header
538 bool headerIsShared
= getProperty
<bool>(pageStyle
, "HeaderIsShared");
539 CPPUNIT_ASSERT(!headerIsShared
);
542 DECLARE_WW8EXPORT_TEST(testBnc787942
, "bnc787942.doc")
544 // The frame ended up on the second page instead of first.
545 // this is on page 1 in Word
546 parseDump("/root/page[1]/body/txt[4]/anchored");
548 CPPUNIT_ASSERT_EQUAL(text::WrapTextMode_PARALLEL
, getProperty
<text::WrapTextMode
>(getShape(1), "Surround"));
549 CPPUNIT_ASSERT_EQUAL(text::RelOrientation::PAGE_FRAME
, getProperty
<sal_Int16
>(getShape(1), "HoriOrientRelation"));
552 DECLARE_WW8EXPORT_TEST(testTdf133504_wrapNotBeside
, "tdf133504_wrapNotBeside.doc")
554 CPPUNIT_ASSERT_EQUAL(text::WrapTextMode_NONE
, getProperty
<text::WrapTextMode
>(getShape(1), "Surround"));
557 DECLARE_WW8EXPORT_TEST(testTdf36711_inlineFrames
, "tdf36711_inlineFrames.doc")
559 CPPUNIT_ASSERT_EQUAL(text::RelOrientation::FRAME
, getProperty
<sal_Int16
>(getShape(1), "VertOrientRelation"));
562 DECLARE_WW8EXPORT_TEST(testLayoutHanging
, "fdo68967.doc")
564 // This must not hang in layout
568 DECLARE_WW8EXPORT_TEST(testfdo68963
, "fdo68963.doc")
570 // The problem was that the text was not displayed.
571 CPPUNIT_ASSERT ( !parseDump("/root/page/body/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/SwFieldPortion", "expand").isEmpty() );
572 CPPUNIT_ASSERT_EQUAL( OUString("Topic 1"), parseDump("/root/page/body/tab/row[2]/cell[1]/txt/SwParaPortion/SwLineLayout/SwFieldPortion", "expand") );
573 // all crossreference bookmarks should have a target. Shouldn't be any "Reference source not found" in the xml
574 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(-1), parseDump("/root/page/body/txt[24]/SwParaPortion/SwLineLayout/SwFieldPortion[2]","expand").indexOf("Reference source not found"));
578 DECLARE_WW8EXPORT_TEST(testTdf99100
, "tdf99100.doc")
580 uno::Reference
<text::XText
> xHeaderText
= getProperty
< uno::Reference
<text::XText
> >(getStyles("PageStyles")->getByName("Standard"), "HeaderText");
581 auto xField
= getProperty
< uno::Reference
<lang::XServiceInfo
> >(getRun(getParagraphOfText(1, xHeaderText
), 2), "TextField");
582 // This failed: the second text portion wasn't a field.
583 CPPUNIT_ASSERT(xField
.is());
584 CPPUNIT_ASSERT(xField
->supportsService("com.sun.star.text.textfield.Chapter"));
587 DECLARE_WW8EXPORT_TEST(testTdf74328
, "tdf74328.doc")
590 reading page numbers at sections > 255, in this case 256
592 uno::Reference
<text::XTextDocument
> textDocument(mxComponent
, uno::UNO_QUERY
);
593 uno::Reference
<text::XTextCursor
> xTextCursor
= textDocument
->getText()->createTextCursor( );
594 uno::Reference
<beans::XPropertySet
> xProps(xTextCursor
, uno::UNO_QUERY
);
595 uno::Any aOffset
= xProps
->getPropertyValue("PageNumberOffset");
596 sal_Int16 nOffset
= 0;
598 CPPUNIT_ASSERT_EQUAL(sal_Int16(256), nOffset
);
601 DECLARE_WW8EXPORT_TEST(testTdf95576
, "tdf95576.doc")
603 // The first three paragraphs in this document (which are headings)
604 // should have zero indent and first line indent
605 for (int nPara
= 1; nPara
<= 3; ++nPara
) {
606 std::cout
<< "nPara = " << nPara
<< "\n";
607 auto xPara
= getParagraph(nPara
);
609 // get the numbering rules effective at this paragraph
610 uno::Reference
<container::XIndexReplace
> xNumRules
=
611 getProperty
< uno::Reference
<container::XIndexReplace
> >(
612 xPara
, "NumberingRules");
614 // get the numbering level of this paragraph, and the properties
615 // associated with that numbering level
616 int numLevel
= getProperty
<sal_Int32
>(xPara
, "NumberingLevel");
617 uno::Sequence
< beans::PropertyValue
> aPropertyValues
;
618 xNumRules
->getByIndex(numLevel
) >>= aPropertyValues
;
620 // Now look through these properties for the indent and
621 // first line indent settings
622 sal_Int32 nIndentAt
= -1;
623 sal_Int32 nFirstLineIndent
= -1;
624 for(int j
= 0 ; j
< aPropertyValues
.getLength() ; ++j
)
626 auto aProp
= aPropertyValues
[j
];
627 std::cout
<< "Prop.Name: " << aProp
.Name
<< "\n";
628 if (aProp
.Name
== "FirstLineIndent") {
629 nFirstLineIndent
= aProp
.Value
.get
<sal_Int32
>();
630 } else if (aProp
.Name
== "IndentAt") {
631 nIndentAt
= aProp
.Value
.get
<sal_Int32
>();
635 // The indent and first line indent should be zero
636 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nIndentAt
);
637 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), nFirstLineIndent
);
641 DECLARE_WW8EXPORT_TEST(testTdf59896
, "tdf59896.doc")
643 // This was awt::FontWeight::NORMAL, i.e. the first run wasn't bold, when it should be bold
644 CPPUNIT_ASSERT_EQUAL(awt::FontWeight::BOLD
, getProperty
<float>(getRun(getParagraph(1), 1), "CharWeight"));
647 DECLARE_WW8EXPORT_TEST(testTdf102334
, "tdf102334.doc")
649 // This was false, i.e. the first run wasn't hidden, when it should have been
650 CPPUNIT_ASSERT_EQUAL(true, getProperty
<bool>(getRun(getParagraph(7), 1), "CharHidden"));
653 DECLARE_WW8EXPORT_TEST(testTdf128605
, "tdf128605.doc")
655 OUString aPara1PageStyleName
= getProperty
<OUString
>(getParagraph(1), "PageStyleName");
656 OUString aPara2PageStyleName
= getProperty
<OUString
>(getParagraph(2), "PageStyleName");
657 // Without the accompanying fix in place, this test would have failed with:
658 // - Expected: Standard
659 // - Actual : Convert 1
660 // i.e. the continuous section break resulted in an unwanted page break.
661 CPPUNIT_ASSERT_EQUAL(aPara1PageStyleName
, aPara2PageStyleName
);
664 DECLARE_WW8EXPORT_TEST(testTdf112535
, "tdf112535.doc")
666 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
667 CPPUNIT_ASSERT(pTextDoc
);
669 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
670 CPPUNIT_ASSERT(pDoc
->GetSpzFrameFormats());
672 auto& rFormats
= *pDoc
->GetSpzFrameFormats();
673 CPPUNIT_ASSERT(!rFormats
.empty());
675 const auto pFormat
= rFormats
[0];
676 CPPUNIT_ASSERT(pFormat
);
678 // Without the accompanying fix in place, this test would have failed: auto-contour was enabled
679 // in Writer, but not in Word.
680 CPPUNIT_ASSERT(!pFormat
->GetSurround().IsContour());
683 DECLARE_WW8EXPORT_TEST(testTdf106291
, "tdf106291.doc")
685 // Table cell was merged vertically instead of horizontally -> had incorrect dimensions
686 OUString cellWidth
= parseDump("/root/page[1]/body/tab/row/cell[1]/infos/bounds", "width");
687 OUString cellHeight
= parseDump("/root/page[1]/body/tab/row/cell[1]/infos/bounds", "height");
688 CPPUNIT_ASSERT_EQUAL(sal_Int32(8650), cellWidth
.toInt32());
689 CPPUNIT_ASSERT(cellHeight
.toInt32() > 200); // height might depend on font size
692 DECLARE_WW8EXPORT_TEST(testTransparentText
, "transparent-text.doc")
694 uno::Reference
<text::XText
> xHeaderText
= getProperty
<uno::Reference
<text::XText
>>(
695 getStyles("PageStyles")->getByName("Standard"), "HeaderText");
696 uno::Reference
<text::XTextRange
> xParagraph
= getParagraphOfText(3, xHeaderText
);
697 // Without the accompanying fix in place, this test would have failed: transparency was set to
698 // 100%, so the text was not readable.
699 sal_Int32
nExpected(COL_BLACK
);
700 sal_Int32
nActual(getProperty
<sal_Int16
>(xParagraph
, "CharTransparence"));
701 CPPUNIT_ASSERT_EQUAL(nExpected
, nActual
);
704 DECLARE_WW8EXPORT_TEST( testTdf105570
, "tdf105570.doc" )
707 * MS-DOC specification ( https://msdn.microsoft.com/en-us/library/cc313153 )
708 * ch. 2.6.3, sprmTTableHeader:
709 * A Bool8 value that specifies that the current table row is a header row.
710 * If the value is 0x01 but sprmTTableHeader is not applied with a value of 0x01
711 * for a previous row in the same table, then this property MUST be ignored.
713 * The document have three tables with three rows.
714 * Table 1 has { 1, 0, 0 } values of the "repeat as header row" property for each row
715 * Table 2 has { 1, 1, 0 }
716 * Table 3 has { 0, 1, 1 }
718 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
719 CPPUNIT_ASSERT(pTextDoc
);
720 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
721 SwWrtShell
* pWrtShell
= pDoc
->GetDocShell()->GetWrtShell();
722 SwShellCursor
* pShellCursor
= pWrtShell
->getShellCursor( false );
723 SwNodeIndex
aIdx( pShellCursor
->Start()->GetNode() );
726 SwTableNode
* pTableNd
= aIdx
.GetNode().FindTableNode();
728 CPPUNIT_ASSERT_EQUAL( sal_uInt16(1), pTableNd
->GetTable().GetRowsToRepeat() );
731 aIdx
.Assign( *pTableNd
->EndOfSectionNode(), 1 );
732 while ( nullptr == (pTableNd
= aIdx
.GetNode().GetTableNode()) ) ++aIdx
;
734 CPPUNIT_ASSERT_EQUAL( sal_uInt16(2), pTableNd
->GetTable().GetRowsToRepeat() );
737 aIdx
.Assign( *pTableNd
->EndOfSectionNode(), 1 );
738 while ( nullptr == (pTableNd
= aIdx
.GetNode().GetTableNode()) ) ++aIdx
;
740 // As first row hasn't sprmTTableHeader set, all following must be ignored, so no rows must be repeated
741 CPPUNIT_ASSERT_EQUAL( sal_uInt16(0), pTableNd
->GetTable().GetRowsToRepeat() );
744 CPPUNIT_TEST_FIXTURE(Test
, testTdf112346
)
746 auto verify
= [this]() {
747 // Multi-page table was imported as a single page.
748 CPPUNIT_ASSERT_EQUAL(2, getPages());
750 createSwDoc("tdf112346.doc");
752 saveAndReload("MS Word 97");
756 DECLARE_WW8EXPORT_TEST(testTdf79639
, "tdf79639.doc")
758 // Without the accompanying fix in place, this test would have failed with:
761 // as the floating table in the header wasn't converted to a TextFrame.
762 CPPUNIT_ASSERT_EQUAL(1, getShapes());
765 DECLARE_WW8EXPORT_TEST(testTdf122425_2
, "tdf122425_2.doc")
767 // This is for graphic objects in headers/footers
768 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
769 CPPUNIT_ASSERT(pTextDoc
);
770 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
771 SwPosFlyFrames aPosFlyFrames
= pDoc
->GetAllFlyFormats(nullptr, false);
772 // There is one fly frame in the document: the text box
773 CPPUNIT_ASSERT_EQUAL(size_t(1), aPosFlyFrames
.size());
774 for (const SwPosFlyFrame
& rPosFlyFrame
: aPosFlyFrames
)
776 const SwFrameFormat
& rFormat
= rPosFlyFrame
.GetFormat();
777 const SfxPoolItem
* pItem
= nullptr;
779 // Check for correct explicitly-set values of UL spacings. Previously this was "DEFAULT",
780 // and resulted in inherited values (114 = 2 mm) used.
781 CPPUNIT_ASSERT_EQUAL(SfxItemState::SET
, rFormat
.GetItemState(RES_UL_SPACE
, false, &pItem
));
782 auto pUL
= static_cast<const SvxULSpaceItem
*>(pItem
);
784 CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pUL
->GetUpper());
785 CPPUNIT_ASSERT_EQUAL(sal_uInt16(0), pUL
->GetLower());
789 DECLARE_WW8EXPORT_TEST(testTdf130262
, "tdf130262.doc")
791 // We had an infinite layout loop
794 DECLARE_WW8EXPORT_TEST(testTdf38778
, "tdf38778_properties_in_run_for_field.doc")
796 CPPUNIT_ASSERT_EQUAL(10.0f
, getProperty
<float>(getRun(getParagraph(1), 1), "CharHeight"));
797 CPPUNIT_ASSERT_EQUAL(OUString("Courier New"), getProperty
<OUString
>(getRun(getParagraph(1), 1), "CharFontName"));
800 DECLARE_WW8EXPORT_TEST(testN325936
, "n325936.doc")
803 * The problem was that the transparent background of the drawing in the
804 * header was exported as non-transparent.
806 * xray ThisComponent.DrawPage(0).BackColorTransparency
809 CPPUNIT_ASSERT_EQUAL(Color(0x000064), getProperty
< Color
>(getShape(1), "BackColorTransparency"));
812 DECLARE_WW8EXPORT_TEST(testTscp
, "tscp.doc")
814 uno::Reference
<uno::XComponentContext
> xComponentContext(comphelper::getProcessComponentContext());
815 uno::Reference
<rdf::XURI
> xType
= rdf::URI::create(xComponentContext
, "urn:bails");
816 uno::Reference
<rdf::XDocumentMetadataAccess
> xDocumentMetadataAccess(mxComponent
, uno::UNO_QUERY
);
817 uno::Sequence
< uno::Reference
<rdf::XURI
> > aGraphNames
= xDocumentMetadataAccess
->getMetadataGraphsWithType(xType
);
818 // This failed, no graphs had the urn:bails type.
819 CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32
>(1), aGraphNames
.getLength());
820 uno::Reference
<rdf::XURI
> xGraphName
= aGraphNames
[0];
821 uno::Reference
<rdf::XNamedGraph
> xGraph
= xDocumentMetadataAccess
->getRDFRepository()->getGraph(xGraphName
);
823 // No RDF statement on the first paragraph.
824 uno::Reference
<rdf::XResource
> xParagraph(getParagraph(1), uno::UNO_QUERY
);
825 uno::Reference
<container::XEnumeration
> xStatements
= xGraph
->getStatements(xParagraph
, uno::Reference
<rdf::XURI
>(), uno::Reference
<rdf::XURI
>());
826 CPPUNIT_ASSERT_EQUAL(false, static_cast<bool>(xStatements
->hasMoreElements()));
828 // 3 RDF statements on the second paragraph.
829 xParagraph
.set(getParagraph(2), uno::UNO_QUERY
);
830 std::map
<OUString
, OUString
> aExpectedStatements
=
832 {"urn:bails:ExportControl:BusinessAuthorization:Identifier", "urn:example:tscp:1"},
833 {"urn:bails:ExportControl:BusinessAuthorizationCategory:Identifier", "urn:example:tscp:1:confidential"},
834 {"urn:bails:ExportControl:Authorization:StartValidity", "2015-11-27"}
836 std::map
<OUString
, OUString
> aActualStatements
;
837 xStatements
= xGraph
->getStatements(xParagraph
, uno::Reference
<rdf::XURI
>(), uno::Reference
<rdf::XURI
>());
838 while (xStatements
->hasMoreElements())
840 rdf::Statement aStatement
= xStatements
->nextElement().get
<rdf::Statement
>();
841 aActualStatements
[aStatement
.Predicate
->getNamespace() + aStatement
.Predicate
->getLocalName()] = aStatement
.Object
->getStringValue();
843 CPPUNIT_ASSERT(bool(aExpectedStatements
== aActualStatements
));
845 // No RDF statement on the third paragraph.
846 xParagraph
.set(getParagraph(3), uno::UNO_QUERY
);
847 xStatements
= xGraph
->getStatements(xParagraph
, uno::Reference
<rdf::XURI
>(), uno::Reference
<rdf::XURI
>());
848 CPPUNIT_ASSERT_EQUAL(false, static_cast<bool>(xStatements
->hasMoreElements()));
851 CPPUNIT_TEST_FIXTURE(Test
, testFdo45724
)
853 loadAndReload("fdo45724.odt");
854 CPPUNIT_ASSERT_EQUAL(1, getShapes());
855 CPPUNIT_ASSERT_EQUAL(1, getPages());
856 // The text and background color of the control shape was not correct.
857 uno::Reference
<drawing::XControlShape
> xControlShape(getShape(1), uno::UNO_QUERY
);
858 uno::Reference
<form::validation::XValidatableFormComponent
> xComponent(xControlShape
->getControl(), uno::UNO_QUERY
);
859 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, getProperty
<Color
>(xComponent
, "BackgroundColor"));
860 CPPUNIT_ASSERT_EQUAL(OUString("xxx"), xComponent
->getCurrentValue().get
<OUString
>());
863 CPPUNIT_TEST_FIXTURE(Test
, testTdf136620
)
865 loadAndReload("tdf136620.odt");
866 CPPUNIT_ASSERT_EQUAL(1, getShapes());
867 CPPUNIT_ASSERT_EQUAL(1, getPages());
869 uno::Reference
<drawing::XShape
> xShape
= getShape(1);
871 CPPUNIT_ASSERT_EQUAL(sal_Int32(5636), xShape
->getPosition().X
);
872 CPPUNIT_ASSERT_EQUAL(sal_Int32(1826), xShape
->getPosition().Y
);
873 CPPUNIT_ASSERT_EQUAL(sal_Int32(6630), xShape
->getSize().Height
);
875 // Without the fix in place, this test would have failed with
878 CPPUNIT_ASSERT_EQUAL(sal_Int32(5853), xShape
->getSize().Width
);
881 CPPUNIT_TEST_FIXTURE(Test
, testFdo46020
)
883 loadAndReload("fdo46020.odt");
884 CPPUNIT_ASSERT_EQUAL(1, getPages());
885 // The footnote in that document wasn't exported, check that it is actually exported
886 uno::Reference
<text::XFootnotesSupplier
> xFootnotesSupplier(mxComponent
, uno::UNO_QUERY
);
887 uno::Reference
<container::XIndexAccess
> xFootnotes
= xFootnotesSupplier
->getFootnotes();
888 CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xFootnotes
->getCount());
891 DECLARE_WW8EXPORT_TEST(testFirstHeaderFooter
, "first-header-footer.doc")
893 // Test import and export of a section's headerf/footerf properties.
895 // The document has 6 pages. Note that we don't test if 4 or just 2 page
896 // styles are created, the point is that layout should be correct.
897 CPPUNIT_ASSERT_EQUAL(OUString("First page header"), parseDump("/root/page[1]/header/txt/text()"));
898 CPPUNIT_ASSERT_EQUAL(OUString("First page footer"), parseDump("/root/page[1]/footer/txt/text()"));
899 CPPUNIT_ASSERT_EQUAL(OUString("Even page header"), parseDump("/root/page[2]/header/txt/text()"));
900 CPPUNIT_ASSERT_EQUAL(OUString("Even page footer"), parseDump("/root/page[2]/footer/txt/text()"));
901 CPPUNIT_ASSERT_EQUAL(OUString("Odd page header"), parseDump("/root/page[3]/header/txt/text()"));
902 CPPUNIT_ASSERT_EQUAL(OUString("Odd page footer"), parseDump("/root/page[3]/footer/txt/text()"));
903 CPPUNIT_ASSERT_EQUAL(OUString("First page header2"), parseDump("/root/page[4]/header/txt/text()"));
904 CPPUNIT_ASSERT_EQUAL(OUString("First page footer 2"), parseDump("/root/page[4]/footer/txt/text()"));
905 CPPUNIT_ASSERT_EQUAL(OUString("Odd page header 2"), parseDump("/root/page[5]/header/txt/text()"));
906 CPPUNIT_ASSERT_EQUAL(OUString("Odd page footer 2"), parseDump("/root/page[5]/footer/txt/text()"));
907 CPPUNIT_ASSERT_EQUAL(OUString("Even page header 2"), parseDump("/root/page[6]/header/txt/text()"));
908 CPPUNIT_ASSERT_EQUAL(OUString("Even page footer 2"), parseDump("/root/page[6]/footer/txt/text()"));
911 DECLARE_WW8EXPORT_TEST(testZoom
, "zoom.doc")
913 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
914 uno::Reference
<view::XViewSettingsSupplier
> xViewSettingsSupplier(xModel
->getCurrentController(), uno::UNO_QUERY
);
915 uno::Reference
<beans::XPropertySet
> xPropertySet(xViewSettingsSupplier
->getViewSettings());
916 sal_Int16 nValue
= 0;
917 xPropertySet
->getPropertyValue("ZoomValue") >>= nValue
;
918 CPPUNIT_ASSERT_EQUAL(sal_Int16(42), nValue
);
921 DECLARE_WW8EXPORT_TEST(testZoomType
, "zoomtype.doc")
923 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
924 uno::Reference
<view::XViewSettingsSupplier
> xViewSettingsSupplier(xModel
->getCurrentController(), uno::UNO_QUERY
);
925 uno::Reference
<beans::XPropertySet
> xPropertySet(xViewSettingsSupplier
->getViewSettings());
926 sal_Int16 nValue
= 0;
927 xPropertySet
->getPropertyValue("ZoomType") >>= nValue
;
928 CPPUNIT_ASSERT_EQUAL(sal_Int16(view::DocumentZoomType::PAGE_WIDTH
), nValue
);
931 DECLARE_WW8EXPORT_TEST(test56513
, "fdo56513.doc")
933 CPPUNIT_ASSERT_EQUAL(OUString("This is the header of the first section"), parseDump("/root/page[1]/header/txt/text()"));
934 CPPUNIT_ASSERT_EQUAL(OUString("This is the first page header of the second section"), parseDump("/root/page[2]/header/txt/text()"));
935 CPPUNIT_ASSERT_EQUAL(OUString("This is the non-first-page header of the second section"), parseDump("/root/page[3]/header/txt/text()"));
938 DECLARE_WW8EXPORT_TEST(testNewPageStylesTable
, "new-page-styles.doc")
940 CPPUNIT_ASSERT_EQUAL(OUString("Sigma Space Performance Goals and Results (Page 1)*"), parseDump("/root/page[1]/header/txt/text()"));
941 CPPUNIT_ASSERT_EQUAL(OUString("Sigma Space Performance Assessment (Page 2)****"), parseDump("/root/page[2]/header/txt/text()"));
942 CPPUNIT_ASSERT_EQUAL(OUString("Sigma Space Performance Goals: Next Year (Page 3)*******"), parseDump("/root/page[3]/header/txt/text()"));
945 CPPUNIT_TEST_FIXTURE(Test
, testFdo42144
)
947 loadAndReload("fdo42144.odt");
948 CPPUNIT_ASSERT_EQUAL(1, getPages());
949 // Footer wasn't disabled -- instead empty footer was exported.
950 uno::Reference
<beans::XPropertySet
> xStyle(getStyles("PageStyles")->getByName("Standard"), uno::UNO_QUERY
);
951 CPPUNIT_ASSERT_EQUAL(false, getProperty
<bool>(xStyle
, "FooterIsOn"));
954 CPPUNIT_TEST_FIXTURE(Test
, testCharacterBorder
)
956 loadAndReload("charborder.odt");
957 CPPUNIT_ASSERT_EQUAL(1, getPages());
958 uno::Reference
<beans::XPropertySet
> xRun(getRun(getParagraph(1),1), uno::UNO_QUERY
);
959 // WW8 has just one border attribute (sprmCBrc) for text border so all side has
963 const table::BorderLine2 aTopBorder
= getProperty
<table::BorderLine2
>(xRun
,"CharTopBorder");
964 CPPUNIT_ASSERT_BORDER_EQUAL(table::BorderLine2(0xFF3333,0,318,0,0,318), aTopBorder
);
965 CPPUNIT_ASSERT_BORDER_EQUAL(aTopBorder
, getProperty
<table::BorderLine2
>(xRun
,"CharLeftBorder"));
966 CPPUNIT_ASSERT_BORDER_EQUAL(aTopBorder
, getProperty
<table::BorderLine2
>(xRun
,"CharBottomBorder"));
967 CPPUNIT_ASSERT_BORDER_EQUAL(aTopBorder
, getProperty
<table::BorderLine2
>(xRun
,"CharRightBorder"));
970 // Padding (dptSpace) it is constant 0
972 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty
<sal_Int32
>(xRun
,"CharTopBorderDistance"));
973 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty
<sal_Int32
>(xRun
,"CharLeftBorderDistance"));
974 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty
<sal_Int32
>(xRun
,"CharBottomBorderDistance"));
975 CPPUNIT_ASSERT_EQUAL(sal_Int32(0), getProperty
<sal_Int32
>(xRun
,"CharRightBorderDistance"));
979 /* WW8 use just one bool value for shadow so the next conversions
980 are made during an export-import round
982 location: any -> bottom-right
983 width: any -> border width */
985 const table::ShadowFormat aShadow
= getProperty
<table::ShadowFormat
>(xRun
, "CharShadowFormat");
986 CPPUNIT_ASSERT_EQUAL(COL_BLACK
, Color(ColorTransparency
, aShadow
.Color
));
987 CPPUNIT_ASSERT_EQUAL(table::ShadowLocation_BOTTOM_RIGHT
, aShadow
.Location
);
988 CPPUNIT_ASSERT_EQUAL(sal_Int16(318), aShadow
.ShadowWidth
);
992 CPPUNIT_TEST_FIXTURE(Test
, testTdf41542_imagePadding
)
994 loadAndReload("tdf41542_imagePadding.odt");
995 CPPUNIT_ASSERT_EQUAL(3, getShapes());
996 CPPUNIT_ASSERT_EQUAL(1, getPages());
997 // borderlessImage - image WITHOUT BORDERS : simulate padding with -crop
998 text::GraphicCrop crop
= getProperty
<text::GraphicCrop
>(getShape(2), "GraphicCrop");
999 CPPUNIT_ASSERT( crop
.Left
!= 0 );
1000 CPPUNIT_ASSERT( crop
.Right
!= 0 );
1001 CPPUNIT_ASSERT_EQUAL( crop
.Left
, crop
.Top
);
1002 CPPUNIT_ASSERT_EQUAL( crop
.Right
, crop
.Bottom
);
1003 CPPUNIT_ASSERT_EQUAL( crop
.Left
, crop
.Right
);
1005 // borderedImage - image WITH BORDERS : simulate padding with -crop
1006 crop
= getProperty
<text::GraphicCrop
>(getShape(3), "GraphicCrop");
1007 CPPUNIT_ASSERT( crop
.Left
!= 0 );
1008 CPPUNIT_ASSERT( crop
.Right
!= 0 );
1009 CPPUNIT_ASSERT_EQUAL( crop
.Left
, crop
.Top
);
1010 CPPUNIT_ASSERT_EQUAL( crop
.Right
, crop
.Bottom
);
1011 CPPUNIT_ASSERT_EQUAL( crop
.Left
, crop
.Right
);
1014 DECLARE_WW8EXPORT_TEST(testFdo77454
, "fdo77454.doc")
1017 // check negative crops round-trip (with border/padding of 1)
1018 text::GraphicCrop
const crop
=
1019 getProperty
<text::GraphicCrop
>(getShape(1), "GraphicCrop");
1020 CPPUNIT_ASSERT(abs(sal_Int32( -439) - crop
.Left
) <= 2);
1021 CPPUNIT_ASSERT(abs(sal_Int32(-7040) - crop
.Right
) <= 2);
1022 CPPUNIT_ASSERT(abs(sal_Int32( -220) - crop
.Top
) <= 2);
1023 CPPUNIT_ASSERT(abs(sal_Int32(-7040) - crop
.Bottom
) <= 2);
1027 // check positive crops round-trip (with padding of 1)
1028 text::GraphicCrop
const crop
=
1029 getProperty
<text::GraphicCrop
>(getShape(2), "GraphicCrop");
1030 CPPUNIT_ASSERT(abs(sal_Int32( 326) - crop
.Left
) <= 3);
1031 CPPUNIT_ASSERT(abs(sal_Int32(1208) - crop
.Right
) <= 3);
1032 CPPUNIT_ASSERT(abs(sal_Int32(1635) - crop
.Top
) <= 3);
1033 CPPUNIT_ASSERT(abs(sal_Int32( 95) - crop
.Bottom
) <= 3);
1037 DECLARE_WW8EXPORT_TEST(testFdo59530
, "fdo59530.doc")
1039 // See ooxmlexport's testFdo38244().
1040 // Test comment range feature.
1041 uno::Reference
<text::XTextDocument
> xTextDocument(mxComponent
, uno::UNO_QUERY
);
1042 uno::Reference
<container::XEnumerationAccess
> xParaEnumAccess(xTextDocument
->getText(), uno::UNO_QUERY
);
1043 uno::Reference
<container::XEnumeration
> xParaEnum
= xParaEnumAccess
->createEnumeration();
1044 uno::Reference
<container::XEnumerationAccess
> xRunEnumAccess(xParaEnum
->nextElement(), uno::UNO_QUERY
);
1045 uno::Reference
<container::XEnumeration
> xRunEnum
= xRunEnumAccess
->createEnumeration();
1046 xRunEnum
->nextElement();
1047 uno::Reference
<beans::XPropertySet
> xPropertySet(xRunEnum
->nextElement(), uno::UNO_QUERY
);
1048 CPPUNIT_ASSERT_EQUAL(OUString("Annotation"), getProperty
<OUString
>(xPropertySet
, "TextPortionType"));
1049 xRunEnum
->nextElement();
1050 xPropertySet
.set(xRunEnum
->nextElement(), uno::UNO_QUERY
);
1051 CPPUNIT_ASSERT_EQUAL(OUString("AnnotationEnd"), getProperty
<OUString
>(xPropertySet
, "TextPortionType"));
1054 uno::Reference
<text::XTextFieldsSupplier
> xTextFieldsSupplier(mxComponent
, uno::UNO_QUERY
);
1055 uno::Reference
<container::XEnumerationAccess
> xFieldsAccess(xTextFieldsSupplier
->getTextFields());
1056 uno::Reference
<container::XEnumeration
> xFields(xFieldsAccess
->createEnumeration());
1057 xPropertySet
.set(xFields
->nextElement(), uno::UNO_QUERY
);
1058 CPPUNIT_ASSERT_EQUAL(OUString("M"), getProperty
<OUString
>(xPropertySet
, "Initials"));
1060 // Test commented text range which spans over more text nodes
1061 // Comment starts in the second paragraph
1062 xRunEnumAccess
.set(xParaEnum
->nextElement(), uno::UNO_QUERY
);
1063 xRunEnum
= xRunEnumAccess
->createEnumeration();
1064 xRunEnum
->nextElement();
1065 xPropertySet
.set(xRunEnum
->nextElement(), uno::UNO_QUERY
);
1066 CPPUNIT_ASSERT_EQUAL(OUString("Annotation"), getProperty
<OUString
>(xPropertySet
, "TextPortionType"));
1067 // Comment ends in the third paragraph
1068 xRunEnumAccess
.set(xParaEnum
->nextElement(), uno::UNO_QUERY
);
1069 xRunEnum
= xRunEnumAccess
->createEnumeration();
1070 xRunEnum
->nextElement();
1071 xPropertySet
.set(xRunEnum
->nextElement(), uno::UNO_QUERY
);
1072 CPPUNIT_ASSERT_EQUAL(OUString("AnnotationEnd"), getProperty
<OUString
>(xPropertySet
, "TextPortionType"));
1075 DECLARE_WW8EXPORT_TEST(testCommentsNested
, "comments-nested.doc")
1077 uno::Reference
<beans::XPropertySet
> xOuter
= getProperty
< uno::Reference
<beans::XPropertySet
> >(getRun(getParagraph(1), 2), "TextField");
1078 CPPUNIT_ASSERT_EQUAL(OUString("Outer"), getProperty
<OUString
>(xOuter
, "Content"));
1080 uno::Reference
<beans::XPropertySet
> xInner
= getProperty
< uno::Reference
<beans::XPropertySet
> >(getRun(getParagraph(1), 4), "TextField");
1081 CPPUNIT_ASSERT_EQUAL(OUString("Inner"), getProperty
<OUString
>(xInner
, "Content"));
1084 CPPUNIT_TEST_FIXTURE(Test
, testBorderColoursExport
)
1086 loadAndReload("bordercolours.odt");
1087 CPPUNIT_ASSERT_EQUAL(1, getShapes());
1088 CPPUNIT_ASSERT_EQUAL(1, getPages());
1089 // This is very close to testBorderColours in ww8import.cxx, but for export
1091 // The following 6 colours can only be represented with WW9 (Word 2000)
1092 // BRC (BoRder Control) structures. We can tell that they have been
1093 // exported/imported using a WW8 (Word '97) BRC if they instead come
1094 // through as one of the 16 colours listed at this link:
1095 // http://msdn.microsoft.com/en-us/library/dd773060.aspx
1096 table::BorderLine2
expectedTop(0xFA670C, 0, 53, 0, 1, 53);
1097 table::BorderLine2
expectedLeft(0xD99594, 0, 79, 0, 0, 79);
1098 table::BorderLine2
expectedRight(0xB2A1C7, 53, 53, 53, 3, 159);
1099 table::BorderLine2
expectedBottom(0xB6DDE8, 0, 106, 0, 14, 106);
1100 table::BorderLine2
expectedDashedRed(0xFA670C, 0, 53, 0, 2, 53);
1101 table::BorderLine2
expectedDoubleGreen(0xC2D69B, 26, 106, 26, 4, 159);
1104 uno::Reference
<text::XBookmarksSupplier
> bookmarksSupplier(mxComponent
,
1106 uno::Reference
<container::XNameAccess
> bookmarks
=
1107 bookmarksSupplier
->getBookmarks();
1108 uno::Reference
<text::XTextContent
> bookmark(
1109 bookmarks
->getByName("ParagraphBorder"), uno::UNO_QUERY
);
1110 uno::Reference
<text::XTextRange
> anchor(bookmark
->getAnchor());
1111 table::BorderLine2 border
;
1112 border
= getProperty
<table::BorderLine2
>(anchor
, "TopBorder");
1113 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1114 border
= getProperty
<table::BorderLine2
>(anchor
, "LeftBorder");
1115 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
1116 border
= getProperty
<table::BorderLine2
>(anchor
, "RightBorder");
1117 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
1118 border
= getProperty
<table::BorderLine2
>(anchor
, "BottomBorder");
1119 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
1122 OUString pageStyleName
= getProperty
<OUString
>(anchor
, "PageStyleName");
1123 uno::Reference
<style::XStyle
> pageStyle(
1124 getStyles("PageStyles")->getByName(pageStyleName
), uno::UNO_QUERY
);
1125 border
= getProperty
<table::BorderLine2
>(pageStyle
, "TopBorder");
1126 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1127 border
= getProperty
<table::BorderLine2
>(pageStyle
, "LeftBorder");
1128 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
1129 border
= getProperty
<table::BorderLine2
>(pageStyle
, "RightBorder");
1130 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
1131 border
= getProperty
<table::BorderLine2
>(pageStyle
, "BottomBorder");
1132 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
1135 bookmark
.set(bookmarks
->getByName("CharBorder"), uno::UNO_QUERY
);
1136 anchor
= bookmark
->getAnchor();
1137 border
= getProperty
<table::BorderLine2
>(anchor
, "CharTopBorder");
1138 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1139 border
= getProperty
<table::BorderLine2
>(anchor
, "CharLeftBorder");
1140 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1141 border
= getProperty
<table::BorderLine2
>(anchor
, "CharRightBorder");
1142 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1143 border
= getProperty
<table::BorderLine2
>(anchor
, "CharBottomBorder");
1144 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1147 uno::Reference
<text::XTextTablesSupplier
> tablesSupplier(mxComponent
,
1149 uno::Reference
<container::XNameAccess
> tables
=
1150 tablesSupplier
->getTextTables();
1151 uno::Reference
<text::XTextTable
> table(
1152 tables
->getByName("Table1"), uno::UNO_QUERY
);
1153 table::TableBorder2 tableBorder
= getProperty
<table::TableBorder2
>(
1154 table
, "TableBorder2");
1155 CPPUNIT_ASSERT_EQUAL(expectedTop
.Color
, tableBorder
.TopLine
.Color
);
1156 CPPUNIT_ASSERT_EQUAL(expectedLeft
.Color
, tableBorder
.LeftLine
.Color
);
1157 CPPUNIT_ASSERT_EQUAL(expectedRight
.Color
, tableBorder
.RightLine
.Color
);
1159 // #if'd out because the "fine dashed" border line style for table borders
1160 // does not seem to save or load correctly in odt format at present
1161 CPPUNIT_ASSERT_EQUAL(expectedBottom
.Color
, tableBorder
.BottomLine
.Color
);
1165 uno::Reference
<table::XCell
> cell
=
1166 table
->getCellByName("A2");
1167 border
= getProperty
<table::BorderLine2
>(cell
, "TopBorder");
1168 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1169 border
= getProperty
<table::BorderLine2
>(cell
, "LeftBorder");
1170 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
1172 // #if'd out because the "fine dashed" border line style for table borders
1173 // does not seem to save or load correctly in odt format at present
1174 border
= getProperty
<table::BorderLine2
>(cell
, "BottomBorder");
1175 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
1178 cell
= table
->getCellByName("B2");
1179 border
= getProperty
<table::BorderLine2
>(cell
, "TopBorder");
1180 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
1181 border
= getProperty
<table::BorderLine2
>(cell
, "LeftBorder");
1182 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
1183 border
= getProperty
<table::BorderLine2
>(cell
, "BottomBorder");
1184 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
1186 cell
= table
->getCellByName("C2");
1187 border
= getProperty
<table::BorderLine2
>(cell
, "TopBorder");
1188 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
1189 border
= getProperty
<table::BorderLine2
>(cell
, "LeftBorder");
1190 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDashedRed
, border
);
1191 border
= getProperty
<table::BorderLine2
>(cell
, "RightBorder");
1192 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
1193 border
= getProperty
<table::BorderLine2
>(cell
, "BottomBorder");
1194 CPPUNIT_ASSERT_BORDER_EQUAL(expectedDoubleGreen
, border
);
1197 // (#if'd out as they are not yet exported with correct colours)
1199 bookmark
.set(bookmarks
->getByName("PictureBorder"),uno::UNO_QUERY
);
1200 anchor
= bookmark
->getAnchor();
1201 border
= getProperty
<table::BorderLine2
>(anchor
, "TopBorder");
1202 CPPUNIT_ASSERT_BORDER_EQUAL(expectedTop
, border
);
1203 border
= getProperty
<table::BorderLine2
>(anchor
, "LeftBorder");
1204 CPPUNIT_ASSERT_BORDER_EQUAL(expectedLeft
, border
);
1205 border
= getProperty
<table::BorderLine2
>(anchor
, "RightBorder");
1206 CPPUNIT_ASSERT_BORDER_EQUAL(expectedRight
, border
);
1207 border
= getProperty
<table::BorderLine2
>(anchor
, "BottomBorder");
1208 CPPUNIT_ASSERT_BORDER_EQUAL(expectedBottom
, border
);
1212 CPPUNIT_TEST_FIXTURE(Test
, testRedlineExport1
)
1214 loadAndReload("redline-export-1.odt");
1215 CPPUNIT_ASSERT_EQUAL(1, getPages());
1216 uno::Reference
<text::XTextRange
> xParagraph
= getParagraph(1);
1217 uno::Reference
<container::XEnumerationAccess
> xRunEnumAccess(xParagraph
, uno::UNO_QUERY
);
1218 uno::Reference
<container::XEnumeration
> xRunEnum
= xRunEnumAccess
->createEnumeration();
1219 //there must be no redline information on the first line before and after reloading
1220 while (xRunEnum
->hasMoreElements())
1222 uno::Reference
<text::XTextRange
> xRun(xRunEnum
->nextElement(), uno::UNO_QUERY
);
1223 CPPUNIT_ASSERT_EQUAL(false, hasProperty(xRun
, "RedlineType"));
1227 CPPUNIT_TEST_FIXTURE(Test
, testRedlineExport2
)
1229 loadAndReload("redline-export-2.odt");
1230 CPPUNIT_ASSERT_EQUAL(1, getPages());
1231 //there must be redline information on the first portion of the third paragraph before and after reloading
1232 CPPUNIT_ASSERT_EQUAL(true, hasProperty(getRun(getParagraph(3), 1), "RedlineType"));
1235 CPPUNIT_TEST_FIXTURE(Test
, testRedlineExport3
)
1237 loadAndReload("redline-export-3.odt");
1238 CPPUNIT_ASSERT_EQUAL(1, getPages());
1239 //there must be redline information just on the para-break boundary between para one and two
1240 CPPUNIT_ASSERT_EQUAL(false, hasProperty(getRun(getParagraph(1), 1), "RedlineType"));
1241 CPPUNIT_ASSERT_EQUAL(true, hasProperty(getRun(getParagraph(1), 2), "RedlineType"));
1242 CPPUNIT_ASSERT_EQUAL(true, hasProperty(getRun(getParagraph(2), 1), "RedlineType"));
1243 CPPUNIT_ASSERT_EQUAL(false, hasProperty(getRun(getParagraph(2), 2), "RedlineType"));
1246 CPPUNIT_TEST_FIXTURE(Test
, testCellBgColor
)
1248 loadAndReload("cell-bg-color.odt");
1249 CPPUNIT_ASSERT_EQUAL(1, getPages());
1250 uno::Reference
<text::XTextTablesSupplier
> xTablesSupplier(mxComponent
, uno::UNO_QUERY
);
1251 uno::Reference
<container::XIndexAccess
> xTables(xTablesSupplier
->getTextTables(), uno::UNO_QUERY
);
1252 uno::Reference
<text::XTextTable
> xTable(xTables
->getByIndex(0), uno::UNO_QUERY
);
1253 CPPUNIT_ASSERT_EQUAL(Color(0xCC0000), getProperty
<Color
>(xTable
->getCellByName("A1"), "BackColor"));
1256 DECLARE_WW8EXPORT_TEST(testBnc636128
, "bnc636128.doc")
1258 // Import / export of FFData.cch was missing.
1259 uno::Reference
<text::XFormField
> xFormField
= getProperty
< uno::Reference
<text::XFormField
> >(getRun(getParagraph(1), 2), "Bookmark");
1260 uno::Reference
<container::XNameContainer
> xParameters
= xFormField
->getParameters();
1261 // This resulted in a container.NoSuchElementException.
1262 CPPUNIT_ASSERT_EQUAL(sal_uInt16(5), xParameters
->getByName("MaxLength").get
<sal_uInt16
>());
1266 DECLARE_WW8EXPORT_TEST(testWw8Cjklist30
, "cjklist30.doc")
1268 sal_Int16 numFormat
= getNumberingTypeOfParagraph(1);
1269 CPPUNIT_ASSERT_EQUAL(style::NumberingType::TIAN_GAN_ZH
, numFormat
);
1272 DECLARE_WW8EXPORT_TEST(testWw8Cjklist31
, "cjklist31.doc")
1274 sal_Int16 numFormat
= getNumberingTypeOfParagraph(1);
1275 CPPUNIT_ASSERT_EQUAL(style::NumberingType::DI_ZI_ZH
, numFormat
);
1278 DECLARE_WW8EXPORT_TEST(testWw8Cjklist34
, "cjklist34.doc")
1280 sal_Int16 numFormat
= getNumberingTypeOfParagraph(1);
1281 CPPUNIT_ASSERT_EQUAL(style::NumberingType::NUMBER_UPPER_ZH_TW
, numFormat
);
1284 DECLARE_WW8EXPORT_TEST(testWw8Cjklist35
, "cjklist35.doc")
1286 sal_Int16 numFormat
= getNumberingTypeOfParagraph(1);
1287 CPPUNIT_ASSERT_EQUAL(style::NumberingType::NUMBER_LOWER_ZH
, numFormat
);
1290 DECLARE_WW8EXPORT_TEST(testTdf118564
, "tdf118564.doc")
1292 sal_Int16 numFormat
= getNumberingTypeOfParagraph(3);
1293 CPPUNIT_ASSERT_EQUAL(style::NumberingType::NUMBER_LOWER_ZH
, numFormat
);
1296 DECLARE_WW8EXPORT_TEST(testTdf92281
, "tdf92281.doc")
1298 uno::Reference
<beans::XPropertySet
> xRun(getRun(getParagraph(1),1), uno::UNO_QUERY
);
1299 CPPUNIT_ASSERT_EQUAL(OUString("Wingdings"), getProperty
<OUString
>(xRun
, "CharFontName"));
1300 CPPUNIT_ASSERT_EQUAL(OUString("Wingdings"), getProperty
<OUString
>(xRun
, "CharFontNameAsian"));
1301 CPPUNIT_ASSERT_EQUAL(OUString("Wingdings"), getProperty
<OUString
>(xRun
, "CharFontNameComplex"));
1303 uno::Reference
<text::XText
> xXText
= getParagraph(1)->getText();
1304 uno::Reference
<text::XTextCursor
> xCursor
= xXText
->createTextCursor();
1306 xCursor
->goRight( 5 , false );
1307 uno::Reference
< beans::XPropertySet
> xPropSet(xCursor
, uno::UNO_QUERY
);
1308 static constexpr OUStringLiteral aFontname
= u
"\u65B0\u7D30\u660E\u9AD4;PMingLiU";
1309 CPPUNIT_ASSERT_EQUAL(OUString("Calibri"), getProperty
<OUString
>(xPropSet
, "CharFontName"));
1310 CPPUNIT_ASSERT_EQUAL(OUString(aFontname
), getProperty
<OUString
>(xPropSet
, "CharFontNameAsian"));
1311 CPPUNIT_ASSERT_EQUAL(OUString("Times New Roman"), getProperty
<OUString
>(xPropSet
, "CharFontNameComplex"));
1314 DECLARE_WW8EXPORT_TEST(testCommentedTable
, "commented-table.doc")
1316 // Document has a non-trivial commented text range, as the range contains a table.
1317 uno::Reference
<text::XTextFieldsSupplier
> xTextFieldsSupplier(mxComponent
, uno::UNO_QUERY
);
1318 uno::Reference
<container::XEnumerationAccess
> xFieldsAccess(xTextFieldsSupplier
->getTextFields());
1319 uno::Reference
<container::XEnumeration
> xFields(xFieldsAccess
->createEnumeration());
1320 uno::Reference
<text::XTextContent
> xField(xFields
->nextElement(), uno::UNO_QUERY
);
1321 // After first import, there was an off-by-one during import, so this was "efore.\nA1\nB1\nAfte". (Notice the additional "e" prefix.)
1322 // After export and import, things got worse, this was "\nA1\nB1\nAfte".
1323 CPPUNIT_ASSERT_EQUAL(OUString("fore." SAL_NEWLINE_STRING
"A1" SAL_NEWLINE_STRING
"B1" SAL_NEWLINE_STRING
"Afte"), xField
->getAnchor()->getString());
1326 DECLARE_WW8EXPORT_TEST(testTextVerticalAdjustment
, "tdf36117_verticalAdjustment.doc")
1328 //Preserve the page vertical alignment setting for .doc
1329 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1330 CPPUNIT_ASSERT(pTextDoc
);
1331 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
1332 CPPUNIT_ASSERT(pDoc
);
1334 SwPageDesc
* pDesc
= &pDoc
->GetPageDesc( 0 );
1335 drawing::TextVerticalAdjust nVA
= pDesc
->GetVerticalAdjustment();
1336 CPPUNIT_ASSERT_EQUAL( drawing::TextVerticalAdjust_CENTER
, nVA
);
1338 pDesc
= &pDoc
->GetPageDesc( 1 );
1339 nVA
= pDesc
->GetVerticalAdjustment();
1340 CPPUNIT_ASSERT_EQUAL( drawing::TextVerticalAdjust_TOP
, nVA
);
1342 pDesc
= &pDoc
->GetPageDesc( 2 );
1343 nVA
= pDesc
->GetVerticalAdjustment();
1344 CPPUNIT_ASSERT_EQUAL( drawing::TextVerticalAdjust_BOTTOM
, nVA
);
1346 pDesc
= &pDoc
->GetPageDesc( 3 );
1347 nVA
= pDesc
->GetVerticalAdjustment();
1348 CPPUNIT_ASSERT_EQUAL( drawing::TextVerticalAdjust_BLOCK
, nVA
);
1351 DECLARE_WW8EXPORT_TEST(testRES_MIRROR_GRAPH_BOTH
, "tdf56321_flipImage_both.doc")
1353 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1354 CPPUNIT_ASSERT(pTextDoc
);
1355 SwDoc
* pDoc
= pTextDoc
->GetDocShell()->GetDoc();
1356 CPPUNIT_ASSERT(pDoc
);
1358 for (SwNodeOffset
n(0); ; n
++)
1360 SwNode
* pNode
= pDoc
->GetNodes()[ n
];
1361 if (SwGrfNode
*pGrfNode
= pNode
->GetGrfNode())
1363 CPPUNIT_ASSERT_EQUAL(int(MirrorGraph::Both
), static_cast<int>(pGrfNode
->GetSwAttrSet().GetMirrorGrf().GetValue()));
1369 CPPUNIT_TEST_FIXTURE(Test
, testCommentExport
)
1371 loadAndReload("comment-export.odt");
1372 CPPUNIT_ASSERT_EQUAL(1, getPages());
1373 struct TextPortionInfo
{
1379 const TextPortionInfo aTextPortions
[] = {
1380 {OUString("Annotation"), OUString("Comment on [A...A]"), 0},
1381 {OUString("Text"), OUString("[A xx "), 0},
1382 {OUString("Annotation"), OUString("Comment on [B...B]"), 1},
1383 {OUString("Text"), OUString("[B x "), 0},
1384 {OUString("Annotation"), OUString("Comment on [C..C]"), 2},
1385 {OUString("Text"), OUString("[C x B]"), 0},
1386 {OUString("AnnotationEnd"), OUString(), 1},
1387 {OUString("Text"), OUString(" x C]"), 0},
1388 {OUString("AnnotationEnd"), OUString(), 2},
1389 {OUString("Text"), OUString(" xx A]"), 0},
1390 {OUString("AnnotationEnd"), OUString(), 0},
1391 {OUString("Text"), OUString(" Comment on a point"), 0},
1392 {OUString("Annotation"), OUString("Comment on point"), 3},
1393 {OUString("Text"), OUString("x "), 0},
1394 {OUString("Annotation"), OUString("Comment on AA...BB"), 4},
1395 {OUString("Annotation"), OUString("Comment on AAAAAA"), 5},
1396 {OUString("Text"), OUString("AAAAAA"), 0},
1397 {OUString("AnnotationEnd"), OUString(), 5},
1398 {OUString("Text"), OUString(" BBBBBB"), 0},
1399 {OUString("AnnotationEnd"), OUString(), 4}
1404 const int nNumberOfTextPortions
= SAL_N_ELEMENTS(aTextPortions
);
1406 uno::Reference
<text::XTextRange
> xPara
= getParagraph(1);
1408 for (int i
= 0; i
< nNumberOfTextPortions
; ++i
)
1410 OUString sKind
= aTextPortions
[i
].sKind
;
1411 uno::Reference
<text::XTextRange
> xRun
= getRun(xPara
, i
+ 1);
1412 uno::Reference
<beans::XPropertySet
> xPropertySet(xRun
, uno::UNO_QUERY
);
1413 CPPUNIT_ASSERT_EQUAL(sKind
, getProperty
<OUString
>(xPropertySet
, "TextPortionType"));
1415 if (sKind
== "Text")
1417 // Check if textportion has the correct text
1418 CPPUNIT_ASSERT_EQUAL(aTextPortions
[i
].sText
, xRun
->getString());
1420 else if (sKind
== "Annotation")
1422 // Check if the comment text is correct and save the name of the comment
1423 uno::Reference
<beans::XPropertySet
> xComment
= getProperty
< uno::Reference
<beans::XPropertySet
> >(xRun
, "TextField");
1424 CPPUNIT_ASSERT_EQUAL(aTextPortions
[i
].sText
, getProperty
<OUString
>(xComment
, "Content"));
1425 sNames
[aTextPortions
[i
].nAnnotationID
] = getProperty
<OUString
>(xComment
, "Name");
1427 else // if (sKind == OUString("AnnotationEnd"))
1429 // Check if the correct Annotation ends here (by Name)
1430 uno::Reference
<container::XNamed
> xBookmark(getProperty
< uno::Reference
<beans::XPropertySet
> >(xRun
, "Bookmark"), uno::UNO_QUERY
);
1431 CPPUNIT_ASSERT_EQUAL(sNames
[aTextPortions
[i
].nAnnotationID
], xBookmark
->getName());
1435 // tdf#139759 import character highlight and shade for comment text
1436 uno::Reference
<text::XTextFieldsSupplier
> xTextFieldsSupplier(mxComponent
, uno::UNO_QUERY
);
1437 auto xFieldsAccess(xTextFieldsSupplier
->getTextFields());
1438 uno::Reference
<container::XEnumeration
> xFields(xFieldsAccess
->createEnumeration());
1439 uno::Reference
<text::XTextField
> xField(xFields
->nextElement(), uno::UNO_QUERY
);
1440 uno::Reference
<text::XText
> xText
= getProperty
<uno::Reference
<text::XText
>>(xField
, "TextRange");
1441 uno::Reference
<text::XTextRange
> xParagraph
= getParagraphOfText(1, xText
);
1442 CPPUNIT_ASSERT_EQUAL(COL_WHITE
, getProperty
<Color
>(getRun(xParagraph
, 1), "CharBackColor"));
1446 CPPUNIT_TEST_FIXTURE(Test
, testTableKeep
)
1448 loadAndReload("tdf91083.odt");
1449 CPPUNIT_ASSERT_EQUAL(7, getPages());
1450 //emulate table "keep with next" -do not split table
1451 CPPUNIT_ASSERT_EQUAL( OUString("Row 1"), parseDump("/root/page[3]/body/tab[1]/row[2]/cell[1]/txt[1]") );
1452 CPPUNIT_ASSERT_EQUAL( OUString("Row 1"), parseDump("/root/page[6]/body/tab[1]/row[2]/cell[1]/txt[1]") );
1456 CPPUNIT_TEST_FIXTURE(Test
, tesTdf91083_tableKeep2
)
1458 loadAndReload("tdf91083_tableKeep2.odt");
1459 //emulate table "keep with next" - split large row in order to keep with previous paragraph
1460 CPPUNIT_ASSERT_EQUAL_MESSAGE("Table doesn't split, so it starts on page 2",
1461 OUString("0"), parseDump("count(//page[1]//tab)") );
1462 CPPUNIT_ASSERT_EQUAL_MESSAGE("Page 2 starts with a paragraph/title, not a table",
1463 OUString("KeepWithNext"), parseDump("//page[2]/body/txt[1]") );
1464 CPPUNIT_ASSERT_EQUAL_MESSAGE("Table sticks with previous paragraph, so it starts on page 2",
1465 OUString("1"), parseDump("count(//page[2]//tab)") );
1466 CPPUNIT_ASSERT_MESSAGE("Row itself splits, not the table at a row boundary",
1467 "Cell 2" != parseDump("//page[3]//tab//row[2]/cell[1]/txt[1]") );
1470 CPPUNIT_TEST_FIXTURE(Test
, tesTdf91083_tableKeep3
)
1472 loadAndReload("tdf91083_tableKeep3.odt");
1473 CPPUNIT_ASSERT_EQUAL(3, getPages());
1474 //emulate table "keep with next" - split single row table in order to keep with previous paragraph
1475 CPPUNIT_ASSERT_EQUAL_MESSAGE("Table doesn't split, so it starts on page 2",
1476 OUString("0"), parseDump("count(//page[1]//tab)") );
1477 CPPUNIT_ASSERT_EQUAL_MESSAGE("Table sticks with previous paragraph, so it starts on page 2",
1478 OUString("1"), parseDump("count(//page[2]//tab)") );
1481 DECLARE_WW8EXPORT_TEST(testTdf76349_textboxMargins
, "tdf76349_textboxMargins.doc")
1483 // textboxes without borders were losing their spacing items in round-tripping
1484 CPPUNIT_ASSERT( 0 < parseDump("/root/page/body/txt/anchored/fly/infos/prtBounds", "left").toInt32() );
1486 uno::Reference
<drawing::XShape
> xShape
= getShape(1);
1487 CPPUNIT_ASSERT_EQUAL_MESSAGE("Textbox background color", Color(0xD8, 0xD8, 0xD8), getProperty
<Color
>(xShape
, "BackColor"));
1490 CPPUNIT_TEST_FIXTURE(Test
, testMoveRange
)
1492 loadAndReload("fdo66304-1.odt");
1493 //the save must survive without asserting
1496 CPPUNIT_TEST_FIXTURE(Test
, testClearFramePams
)
1498 loadAndReload("tdf46441-2.odt");
1499 CPPUNIT_ASSERT_EQUAL(1, getPages());
1500 //the save must survive without asserting
1503 CPPUNIT_TEST_FIXTURE(Test
, testTdf94386
)
1505 createSwDoc("tdf94386.odt");
1506 SwXTextDocument
* pTextDoc
= dynamic_cast<SwXTextDocument
*>(mxComponent
.get());
1507 CPPUNIT_ASSERT(pTextDoc
);
1508 SwWrtShell
* pWrtShell
= pTextDoc
->GetDocShell()->GetWrtShell();
1510 // emulate the behavior from tdf#94386 - insert an envelope to the
1513 SfxItemSet
aSet(pWrtShell
->GetView().GetCurShell()->GetPool(), svl::Items
<FN_ENVELOP
, FN_ENVELOP
>);
1514 aSet
.Put(SwEnvItem());
1515 SfxRequest
aRequest(FN_ENVELOP
, SfxCallMode::SYNCHRON
, aSet
);
1516 SW_MOD()->ExecOther(aRequest
);
1518 saveAndReload("MS Word 97");
1520 // check that the first and next page use different page styles
1521 uno::Reference
<frame::XModel
> xModel(mxComponent
, uno::UNO_QUERY
);
1522 uno::Reference
<text::XTextViewCursorSupplier
> xTextViewCursorSupplier(
1523 xModel
->getCurrentController(), uno::UNO_QUERY
);
1524 uno::Reference
<text::XPageCursor
> xCursor(
1525 xTextViewCursorSupplier
->getViewCursor(), uno::UNO_QUERY
);
1527 xCursor
->jumpToFirstPage();
1528 OUString firstPageStyleName
= getProperty
<OUString
>(xCursor
, "PageStyleName");
1529 xCursor
->jumpToLastPage();
1530 OUString lastPageStyleName
= getProperty
<OUString
>(xCursor
, "PageStyleName");
1531 CPPUNIT_ASSERT(firstPageStyleName
!= lastPageStyleName
);
1533 uno::Reference
<beans::XPropertySet
> xFirstPropertySet(getStyles("PageStyles")->getByName(firstPageStyleName
), uno::UNO_QUERY
);
1535 xFirstPropertySet
->getPropertyValue("Size") >>= fSize
;
1537 uno::Reference
<beans::XPropertySet
> xNextPropertySet(getStyles("PageStyles")->getByName(lastPageStyleName
), uno::UNO_QUERY
);
1539 xNextPropertySet
->getPropertyValue("Size") >>= lSize
;
1541 CPPUNIT_ASSERT((fSize
.Width
!= lSize
.Width
));
1542 CPPUNIT_ASSERT((fSize
.Height
!= lSize
.Height
));
1545 CPPUNIT_TEST_FIXTURE(Test
, testTdf99474
)
1547 loadAndReload("tdf99474.odt");
1548 CPPUNIT_ASSERT_EQUAL(1, getPages());
1549 // The bullet colour of paragraph #3 should be COL_AUTO
1550 auto xPara
= getParagraph(3);
1551 uno::Reference
<container::XIndexReplace
> xNumRules
=
1552 getProperty
< uno::Reference
<container::XIndexReplace
> >(
1553 xPara
, "NumberingRules");
1555 int numLevel
= getProperty
<sal_Int32
>(xPara
, "NumberingLevel");
1556 uno::Sequence
< beans::PropertyValue
> aPropertyValues
;
1557 xNumRules
->getByIndex(numLevel
) >>= aPropertyValues
;
1558 OUString charStyleName
;
1559 for(int j
= 0 ; j
< aPropertyValues
.getLength() ; ++j
)
1561 auto aProp
= aPropertyValues
[j
];
1562 if (aProp
.Name
== "CharStyleName") {
1563 charStyleName
= aProp
.Value
.get
<OUString
>();
1567 CPPUNIT_ASSERT(charStyleName
.getLength());
1568 uno::Reference
<beans::XPropertySet
> xStyle(
1569 getStyles("CharacterStyles")->getByName(charStyleName
),
1571 CPPUNIT_ASSERT_EQUAL(COL_AUTO
, getProperty
<Color
>(xStyle
, "CharColor"));
1574 CPPUNIT_PLUGIN_IMPLEMENT();
1576 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */