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 <officecfg/Office/Common.hxx>
11 #include <config_fonts.h>
13 #include "helper/debughelper.hxx"
15 #include "helper/qahelper.hxx"
16 #include "helper/shared_test_impl.hxx"
18 #include <userdat.hxx>
19 #include <docpool.hxx>
20 #include <cellvalue.hxx>
21 #include <scitems.hxx>
23 #include <stlpool.hxx>
24 #include <editutil.hxx>
25 #include <scopetools.hxx>
27 #include <validat.hxx>
29 #include <svx/svdpage.hxx>
30 #include <tabprotection.hxx>
31 #include <editeng/wghtitem.hxx>
32 #include <editeng/postitem.hxx>
33 #include <editeng/eeitem.hxx>
34 #include <editeng/section.hxx>
35 #include <editeng/crossedoutitem.hxx>
36 #include <editeng/borderline.hxx>
37 #include <editeng/escapementitem.hxx>
38 #include <editeng/fontitem.hxx>
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/udlnitem.hxx>
41 #include <editeng/colritem.hxx>
43 using namespace ::com::sun::star
;
44 using namespace ::com::sun::star::uno
;
46 class ScExportTest
: public ScModelTestBase
49 void testExcelCellBorders(const OUString
& sFormatType
);
53 : ScModelTestBase("sc/qa/unit/data")
58 CPPUNIT_TEST_FIXTURE(ScExportTest
, testExport
)
62 ScDocument
* pDoc
= getScDoc();
64 pDoc
->SetValue(0, 0, 0, 1.0);
66 saveAndReload("calc8");
69 double aVal
= pDoc
->GetValue(0, 0, 0);
70 ASSERT_DOUBLES_EQUAL(1.0, aVal
);
73 CPPUNIT_TEST_FIXTURE(ScExportTest
, testDefaultFontHeight
)
77 ScDocument
* pDoc
= getScDoc();
78 ScDocumentPool
* pPool
= pDoc
->GetPool();
79 pPool
->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_FONT_HEIGHT
));
80 pPool
->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_CJK_FONT_HEIGHT
));
81 pPool
->SetPoolDefaultItem(SvxFontHeightItem(400, 100, ATTR_CTL_FONT_HEIGHT
));
83 saveAndReload("calc8");
86 pPool
= pDoc
->GetPool();
87 const SvxFontHeightItem
& rItem
= pPool
->GetDefaultItem(ATTR_FONT_HEIGHT
);
88 CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rItem
.GetHeight());
89 const SvxFontHeightItem
& rCJKItem
= pPool
->GetDefaultItem(ATTR_CJK_FONT_HEIGHT
);
90 CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rCJKItem
.GetHeight());
91 const SvxFontHeightItem
& rCTLItem
= pPool
->GetDefaultItem(ATTR_CTL_FONT_HEIGHT
);
92 CPPUNIT_ASSERT_EQUAL(sal_uInt32(400), rCTLItem
.GetHeight());
95 CPPUNIT_TEST_FIXTURE(ScExportTest
, testTdf139167
)
97 createScDoc("xlsx/tdf139167.xlsx");
99 save("Calc Office Open XML");
100 xmlDocUniquePtr pDoc
= parseExport("xl/styles.xml");
101 CPPUNIT_ASSERT(pDoc
);
103 assertXPath(pDoc
, "/x:styleSheet/x:cellStyles"_ostr
, "count"_ostr
, "6");
104 assertXPath(pDoc
, "/x:styleSheet/x:dxfs/x:dxf/x:fill/x:patternFill/x:bgColor"_ostr
, "rgb"_ostr
,
108 CPPUNIT_TEST_FIXTURE(ScExportTest
, testFontColorWithMultipleAttributesDefined
)
110 // Related: TDF #113271
111 // Test font color where "rgb" and "theme" attribute is defined and
112 // is imported and exported correctly. Theme should have priority,
113 // so LO is fine to ignore "rgb" at export.
115 createScDoc("xlsx/tdf113271.xlsx");
117 save("Calc Office Open XML");
118 xmlDocUniquePtr pDoc
= parseExport("xl/styles.xml");
119 CPPUNIT_ASSERT(pDoc
);
121 assertXPath(pDoc
, "/x:styleSheet/x:fonts"_ostr
, "count"_ostr
, "6");
123 // Expect "theme" attribute to be set correctly
124 assertXPath(pDoc
, "/x:styleSheet/x:fonts/x:font[1]/x:color"_ostr
, "theme"_ostr
, "1");
125 // We don't export "rgb" attribute
126 assertXPathNoAttribute(pDoc
, "/x:styleSheet/x:fonts/x:font[1]/x:color"_ostr
, "rgb"_ostr
);
127 // Just making sure the checked font is the correct one
128 assertXPath(pDoc
, "/x:styleSheet/x:fonts/x:font[1]/x:name"_ostr
, "val"_ostr
, "Calibri");
131 CPPUNIT_TEST_FIXTURE(ScExportTest
, testTdf139394
)
133 createScDoc("xlsx/tdf139394.xlsx");
135 save("Calc Office Open XML");
136 xmlDocUniquePtr pDoc
= parseExport("xl/worksheets/sheet1.xml");
137 CPPUNIT_ASSERT(pDoc
);
141 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
142 "x14:cfRule/xm:f"_ostr
,
143 "LEFT(A1,LEN(\"+\"))=\"+\"");
146 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
147 "x14:cfRule/xm:f"_ostr
,
148 "RIGHT(A2,LEN(\"-\"))=\"-\"");
151 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[3]/"
152 "x14:cfRule/xm:f"_ostr
,
153 "LEFT(A3,LEN($B$3))=$B$3");
156 CPPUNIT_TEST_FIXTURE(ScExportTest
, testExtCondFormatXLSX
)
158 createScDoc("xlsx/tdf139021.xlsx");
160 save("Calc Office Open XML");
161 xmlDocUniquePtr pDoc
= parseExport("xl/worksheets/sheet1.xml");
162 CPPUNIT_ASSERT(pDoc
);
166 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
168 "type"_ostr
, "containsText");
171 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
172 "x14:cfRule/xm:f[1]"_ostr
,
173 "NOT(ISERROR(SEARCH($B$1,A1)))");
176 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[1]/"
177 "x14:cfRule/xm:f[2]"_ostr
,
181 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
183 "type"_ostr
, "notContainsText");
186 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
187 "x14:cfRule/xm:f[1]"_ostr
,
188 "ISERROR(SEARCH($B$2,A2))");
191 "/x:worksheet/x:extLst/x:ext/x14:conditionalFormattings/x14:conditionalFormatting[2]/"
192 "x14:cfRule/xm:f[2]"_ostr
,
196 CPPUNIT_TEST_FIXTURE(ScExportTest
, testTdf90104
)
198 createScDoc("xlsx/tdf90104.xlsx");
200 save("Calc Office Open XML");
202 xmlDocUniquePtr pDoc
= parseExport("xl/worksheets/sheet1.xml");
203 CPPUNIT_ASSERT(pDoc
);
205 assertXPathContent(pDoc
,
206 "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent"
207 "/mc:Choice/x12ac:list"_ostr
,
208 "1,\"2,3\",4,\"5,6\"");
209 assertXPathContent(pDoc
,
210 "/x:worksheet/x:dataValidations/x:dataValidation/mc:AlternateContent"
211 "/mc:Fallback/x:formula1"_ostr
,
215 CPPUNIT_TEST_FIXTURE(ScExportTest
, testTdf111876
)
217 // Document with relative path hyperlink
219 createScDoc("xlsx/tdf111876.xlsx");
221 save("Calc Office Open XML");
222 xmlDocUniquePtr pDoc
= parseExport("xl/worksheets/_rels/sheet1.xml.rels");
223 CPPUNIT_ASSERT(pDoc
);
224 OUString sTarget
= getXPath(pDoc
, "/rels:Relationships/rels:Relationship"_ostr
, "Target"_ostr
);
226 // Document is saved to the temporary directory, relative path should be different than original one
227 CPPUNIT_ASSERT(sTarget
!= "../xls/bug-fixes.xls");
230 CPPUNIT_TEST_FIXTURE(ScExportTest
, testPasswordExport
)
232 std::vector
<OUString
> aFilterNames
{ "calc8", "MS Excel 97", "Calc Office Open XML" };
234 for (size_t i
= 0; i
< aFilterNames
.size(); ++i
)
238 ScDocument
* pDoc
= getScDoc();
240 pDoc
->SetValue(0, 0, 0, 1.0);
242 saveAndReload(aFilterNames
[i
], /*pPassword*/ "test");
245 double aVal
= pDoc
->GetValue(0, 0, 0);
246 ASSERT_DOUBLES_EQUAL(1.0, aVal
);
250 CPPUNIT_TEST_FIXTURE(ScExportTest
, testTdf134332
)
252 createScDoc("ods/tdf134332.ods");
254 ScDocument
* pDoc
= getScDoc();
256 ASSERT_DOUBLES_EQUAL(190.0, pDoc
->GetValue(ScAddress(0, 0, 0)));
258 ASSERT_DOUBLES_EQUAL(238.0, pDoc
->GetValue(ScAddress(0, 10144, 0)));
260 saveAndReload("calc8", /*pPassword*/ "test");
262 // Without the fixes in place, it would have failed here
264 ASSERT_DOUBLES_EQUAL(190.0, pDoc
->GetValue(ScAddress(0, 0, 0)));
266 ASSERT_DOUBLES_EQUAL(238.0, pDoc
->GetValue(ScAddress(0, 10144, 0)));
269 CPPUNIT_TEST_FIXTURE(ScExportTest
, testConditionalFormatExportODS
)
271 createScDoc("ods/new_cond_format_test_export.ods");
273 saveAndReload("calc8");
274 ScDocument
* pDoc
= getScDoc();
275 OUString aCSVPath
= createFilePath(u
"contentCSV/new_cond_format_test_export.csv");
276 testCondFile(aCSVPath
, &*pDoc
, 0);
279 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCondFormatExportCellIs
)
281 createScDoc("xlsx/condFormat_cellis.xlsx");
282 saveAndReload("Calc Office Open XML");
284 ScDocument
* pDoc
= getScDoc();
285 CPPUNIT_ASSERT_EQUAL(size_t(1), pDoc
->GetCondFormList(0)->size());
287 ScConditionalFormat
* pFormat
= pDoc
->GetCondFormat(0, 0, 0);
288 CPPUNIT_ASSERT(pFormat
);
290 const ScFormatEntry
* pEntry
= pFormat
->GetEntry(0);
291 CPPUNIT_ASSERT(pEntry
);
292 CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition
, pEntry
->GetType());
294 const ScCondFormatEntry
* pCondition
= static_cast<const ScCondFormatEntry
*>(pEntry
);
295 CPPUNIT_ASSERT_EQUAL(ScConditionMode::Equal
, pCondition
->GetOperation());
297 OUString aStr
= pCondition
->GetExpression(ScAddress(0, 0, 0), 0);
298 CPPUNIT_ASSERT_EQUAL(OUString("$Sheet2.$A$2"), aStr
);
300 pEntry
= pFormat
->GetEntry(1);
301 CPPUNIT_ASSERT(pEntry
);
302 CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::ExtCondition
, pEntry
->GetType());
304 pCondition
= static_cast<const ScCondFormatEntry
*>(pEntry
);
305 CPPUNIT_ASSERT_EQUAL(ScConditionMode::Equal
, pCondition
->GetOperation());
307 aStr
= pCondition
->GetExpression(ScAddress(0, 0, 0), 0);
308 CPPUNIT_ASSERT_EQUAL(OUString("$Sheet2.$A$1"), aStr
);
311 CPPUNIT_TEST_FIXTURE(ScExportTest
, testConditionalFormatExportXLSX
)
313 createScDoc("xlsx/new_cond_format_test_export.xlsx");
315 saveAndReload("Calc Office Open XML");
316 ScDocument
* pDoc
= getScDoc();
318 OUString aCSVPath
= createFilePath(u
"contentCSV/new_cond_format_test_export.csv");
319 testCondFile(aCSVPath
, &*pDoc
, 0);
322 OUString aCSVPath
= createFilePath(u
"contentCSV/new_cond_format_test_sheet2.csv");
323 testCondFile(aCSVPath
, &*pDoc
, 1);
327 CPPUNIT_TEST_FIXTURE(ScExportTest
, testTdf99856_dataValidationTest
)
329 createScDoc("ods/tdf99856_dataValidationTest.ods");
331 saveAndReload("Calc Office Open XML");
333 ScDocument
* pDoc
= getScDoc();
334 const ScValidationData
* pData
= pDoc
->GetValidationEntry(2);
335 CPPUNIT_ASSERT(pData
);
337 // Excel can't open corrupt file if the list is longer than 255 characters
338 std::vector
<ScTypedStrData
> aList
;
339 pData
->FillSelectionList(aList
, ScAddress(0, 1, 1));
340 CPPUNIT_ASSERT_EQUAL(size_t(18), aList
.size());
341 CPPUNIT_ASSERT_EQUAL(OUString("18 Missis"), aList
[17].GetString());
344 CPPUNIT_TEST_FIXTURE(ScExportTest
, testProtectionKeyODS_UTF16LErtlSHA1
)
346 OUString
constexpr password(u
"1012345678901234567890123456789012345678901234567890"_ustr
);
348 createScDoc("fods/protection-key1.fods");
350 ScDocument
* pDoc
= getScDoc();
351 ScDocProtection
* const pDocProt(pDoc
->GetDocProtection());
352 CPPUNIT_ASSERT(pDocProt
->verifyPassword(password
));
353 const ScTableProtection
* const pTabProt(pDoc
->GetTabProtection(0));
354 CPPUNIT_ASSERT(pTabProt
->verifyPassword(password
));
356 // we can't assume that the user entered the password; check that we
357 // round-trip the password as-is
359 xmlDocUniquePtr pXmlDoc
= parseExport("content.xml");
362 "//office:spreadsheet[@table:structure-protected='true' and "
363 "@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and "
364 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr
);
367 "//table:table[@table:protected='true' and "
368 "@table:protection-key='vbnhxyBKtPHCA1wB21zG1Oha8ZA=' and "
369 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr
);
372 CPPUNIT_TEST_FIXTURE(ScExportTest
, testProtectionKeyODS_UTF8SHA1
)
374 OUString
constexpr password(u
"1012345678901234567890123456789012345678901234567890"_ustr
);
376 createScDoc("fods/protection-key2.fods");
378 ScDocument
* pDoc
= getScDoc();
379 ScDocProtection
* const pDocProt(pDoc
->GetDocProtection());
380 CPPUNIT_ASSERT(pDocProt
->verifyPassword(password
));
381 const ScTableProtection
* const pTabProt(pDoc
->GetTabProtection(0));
382 CPPUNIT_ASSERT(pTabProt
->verifyPassword(password
));
384 // we can't assume that the user entered the password; check that we
385 // round-trip the password as-is
387 xmlDocUniquePtr pXmlDoc
= parseExport("content.xml");
390 "//office:spreadsheet[@table:structure-protected='true' and "
391 "@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and "
392 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr
);
395 "//table:table[@table:protected='true' and "
396 "@table:protection-key='nLHas0RIwepGDaH4c2hpyIUvIS8=' and "
397 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr
);
400 CPPUNIT_TEST_FIXTURE(ScExportTest
, testProtectionKeyODS_UTF8SHA256ODF12
)
402 OUString
constexpr password(u
"1012345678901234567890123456789012345678901234567890"_ustr
);
404 createScDoc("fods/protection-key3.fods");
406 ScDocument
* pDoc
= getScDoc();
407 ScDocProtection
* const pDocProt(pDoc
->GetDocProtection());
408 CPPUNIT_ASSERT(pDocProt
->verifyPassword(password
));
409 const ScTableProtection
* const pTabProt(pDoc
->GetTabProtection(0));
410 CPPUNIT_ASSERT(pTabProt
->verifyPassword(password
));
412 // we can't assume that the user entered the password; check that we
413 // round-trip the password as-is
415 xmlDocUniquePtr pXmlDoc
= parseExport("content.xml");
418 "//office:spreadsheet[@table:structure-protected='true' and "
419 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
420 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr
);
423 "//table:table[@table:protected='true' and "
424 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
425 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr
);
428 CPPUNIT_TEST_FIXTURE(ScExportTest
, testProtectionKeyODS_UTF8SHA256W3C
)
430 OUString
constexpr password(u
"1012345678901234567890123456789012345678901234567890"_ustr
);
432 createScDoc("fods/protection-key4.fods");
434 ScDocument
* pDoc
= getScDoc();
435 ScDocProtection
* const pDocProt(pDoc
->GetDocProtection());
436 CPPUNIT_ASSERT(pDocProt
->verifyPassword(password
));
437 const ScTableProtection
* const pTabProt(pDoc
->GetTabProtection(0));
438 CPPUNIT_ASSERT(pTabProt
->verifyPassword(password
));
440 // we can't assume that the user entered the password; check that we
441 // round-trip the password as-is
443 xmlDocUniquePtr pXmlDoc
= parseExport("content.xml");
446 "//office:spreadsheet[@table:structure-protected='true' and "
447 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
448 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr
);
451 "//table:table[@table:protected='true' and "
452 "@table:protection-key='1tnJohagR2T0yF/v69hLPuumSTsj32CumW97nkKGuSQ=' and "
453 "@table:protection-key-digest-algorithm='http://www.w3.org/2000/09/xmldsig#sha256']"_ostr
);
456 CPPUNIT_TEST_FIXTURE(ScExportTest
, testProtectionKeyODS_XL_SHA1
)
458 OUString
constexpr password(u
"1012345678901234567890123456789012345678901234567890"_ustr
);
460 createScDoc("fods/protection-key5.fods");
462 ScDocument
* pDoc
= getScDoc();
463 ScDocProtection
* const pDocProt(pDoc
->GetDocProtection());
464 CPPUNIT_ASSERT(pDocProt
->verifyPassword(password
));
465 const ScTableProtection
* const pTabProt(pDoc
->GetTabProtection(0));
466 CPPUNIT_ASSERT(pTabProt
->verifyPassword(password
));
468 // we can't assume that the user entered the password; check that we
469 // round-trip the password as-is
471 xmlDocUniquePtr pXmlDoc
= parseExport("content.xml");
474 "//office:spreadsheet[@table:structure-protected='true' and "
475 "@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and "
476 "@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/"
477 "legacy-hash-excel' and "
478 "@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr
);
481 "//table:table[@table:protected='true' and "
482 "@table:protection-key='OX3WkEe79fv1PE+FUmfOLdwVoqI=' and "
483 "@table:protection-key-digest-algorithm='http://docs.oasis-open.org/office/ns/table/"
484 "legacy-hash-excel' and "
485 "@loext:protection-key-digest-algorithm-2='http://www.w3.org/2000/09/xmldsig#sha1']"_ostr
);
488 CPPUNIT_TEST_FIXTURE(ScExportTest
, testColorScaleExportODS
)
490 createScDoc("ods/colorscale.ods");
492 saveAndReload("calc8");
494 ScDocument
* pDoc
= getScDoc();
496 testColorScale2Entry_Impl(*pDoc
);
497 testColorScale3Entry_Impl(*pDoc
);
500 CPPUNIT_TEST_FIXTURE(ScExportTest
, testColorScaleExportXLSX
)
502 createScDoc("xlsx/colorscale.xlsx");
504 saveAndReload("Calc Office Open XML");
506 ScDocument
* pDoc
= getScDoc();
508 testColorScale2Entry_Impl(*pDoc
);
509 testColorScale3Entry_Impl(*pDoc
);
512 CPPUNIT_TEST_FIXTURE(ScExportTest
, testDataBarExportODS
)
514 createScDoc("ods/databar.ods");
516 saveAndReload("calc8");
518 ScDocument
* pDoc
= getScDoc();
520 testDataBar_Impl(*pDoc
);
523 CPPUNIT_TEST_FIXTURE(ScExportTest
, testFormatExportODS
)
525 createScDoc("ods/formats.ods");
527 saveAndReload("calc8");
529 ScDocument
* pDoc
= getScDoc();
531 testFormats(pDoc
, u
"calc8");
534 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCommentExportXLSX
)
536 //tdf#104729 FILESAVE OpenOffice do not save author of the comment during export to .xlsx
537 createScDoc("ods/comment.ods");
539 save("Calc Office Open XML");
540 xmlDocUniquePtr pComments
= parseExport("xl/comments1.xml");
541 CPPUNIT_ASSERT(pComments
);
543 assertXPathContent(pComments
, "/x:comments/x:authors/x:author[1]"_ostr
, "BAKO");
544 assertXPath(pComments
, "/x:comments/x:authors/x:author"_ostr
, 1);
546 assertXPathContent(pComments
, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t"_ostr
,
549 xmlDocUniquePtr pVmlDrawing
= parseExport("xl/drawings/vmlDrawing1.vml");
550 CPPUNIT_ASSERT(pVmlDrawing
);
552 //assertXPath(pVmlDrawing, "/xml/v:shapetype", "coordsize", "21600,21600");
553 assertXPath(pVmlDrawing
, "/xml/v:shapetype"_ostr
, "spt"_ostr
, "202");
554 assertXPath(pVmlDrawing
, "/xml/v:shapetype/v:stroke"_ostr
, "joinstyle"_ostr
, "miter");
555 const OUString sShapeTypeId
= "#" + getXPath(pVmlDrawing
, "/xml/v:shapetype"_ostr
, "id"_ostr
);
557 assertXPath(pVmlDrawing
, "/xml/v:shape"_ostr
, "type"_ostr
, sShapeTypeId
);
558 assertXPath(pVmlDrawing
, "/xml/v:shape/v:shadow"_ostr
, "color"_ostr
, "black");
559 assertXPath(pVmlDrawing
, "/xml/v:shape/v:shadow"_ostr
, "obscured"_ostr
, "t");
561 //tdf#117274 fix MSO interoperability with the secret VML shape type id
562 assertXPath(pVmlDrawing
, "/xml/v:shapetype"_ostr
, "id"_ostr
, "_x0000_t202");
563 assertXPath(pVmlDrawing
, "/xml/v:shape"_ostr
, "type"_ostr
, "#_x0000_t202");
566 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCommentExportXLSX_2_XLSX
)
568 //tdf#117287 FILESAVE XLSX: Comments always disappear after opening the exported XLSX file with Excel
569 createScDoc("xlsx/tdf117287_comment.xlsx");
571 ScDocument
* pDoc
= getScDoc();
572 ScAddress
aPosC9(2, 8, 0);
573 ScPostIt
* pNote
= pDoc
->GetNote(aPosC9
);
575 CPPUNIT_ASSERT(pNote
);
576 CPPUNIT_ASSERT(!pNote
->IsCaptionShown());
578 pNote
->ShowCaption(aPosC9
, true);
580 save("Calc Office Open XML");
581 xmlDocUniquePtr pComments
= parseExport("xl/comments1.xml");
582 CPPUNIT_ASSERT(pComments
);
584 assertXPathContent(pComments
, "/x:comments/x:commentList/x:comment/x:text/x:r/x:t"_ostr
,
587 xmlDocUniquePtr pVmlDrawing
= parseExport("xl/drawings/vmlDrawing1.vml");
588 CPPUNIT_ASSERT(pVmlDrawing
);
590 assertXPath(pVmlDrawing
, "/xml/v:shape/x:ClientData/x:Visible"_ostr
, 0);
594 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCustomColumnWidthExportXLSX
)
596 //tdf#100946 FILESAVE Excel on macOS ignored column widths in XLSX last saved by LO
597 createScDoc("ods/custom_column_width.ods");
599 save("Calc Office Open XML");
600 xmlDocUniquePtr pSheet
= parseExport("xl/worksheets/sheet1.xml");
601 CPPUNIT_ASSERT(pSheet
);
603 // tdf#124741: check that we export default width, otherwise the skipped columns would have
604 // wrong width. Previously defaultColWidth attribute was missing
606 = getXPath(pSheet
, "/x:worksheet/x:sheetFormatPr"_ostr
, "defaultColWidth"_ostr
).toDouble();
607 CPPUNIT_ASSERT_DOUBLES_EQUAL(11.53515625, nDefWidth
, 0.01);
609 // First column, has everything default (width in Calc: 1280), skipped
611 // Second column, has custom width (width in Calc: 1225)
612 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "hidden"_ostr
, "false");
613 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "outlineLevel"_ostr
, "0");
614 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "customWidth"_ostr
, "true");
615 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "collapsed"_ostr
, "false");
616 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "min"_ostr
, "2");
617 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "max"_ostr
, "2");
619 // Third column, has everything default (width in Calc: 1280), skipped
621 // Fourth column has custom width. Columns from 4 to 7 are hidden
622 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "hidden"_ostr
, "true");
623 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "outlineLevel"_ostr
, "0");
624 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "customWidth"_ostr
, "true");
625 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "collapsed"_ostr
, "false");
626 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "min"_ostr
, "4");
627 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "max"_ostr
, "4");
629 // 5th column has custom width. Columns from 4 to 7 are hidden
630 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "hidden"_ostr
, "true");
631 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "outlineLevel"_ostr
, "0");
632 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "customWidth"_ostr
, "true");
633 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "collapsed"_ostr
, "false");
634 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "min"_ostr
, "5");
635 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "max"_ostr
, "5");
637 // 6th and 7th columns have default width and they are hidden
638 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "hidden"_ostr
, "true");
639 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "outlineLevel"_ostr
, "0");
640 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "customWidth"_ostr
, "false");
641 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "collapsed"_ostr
, "false");
642 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "min"_ostr
, "6");
643 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "max"_ostr
, "7");
645 // 8th column has everything default - skipped
647 // 9th column has custom width
648 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "hidden"_ostr
, "false");
649 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "outlineLevel"_ostr
, "0");
650 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "customWidth"_ostr
, "true");
651 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "collapsed"_ostr
, "false");
652 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "min"_ostr
, "9");
653 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "max"_ostr
, "9");
655 // We expected that exactly 5 unique Nodes will be produced
656 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col"_ostr
, 5);
658 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "hidden"_ostr
, "false");
659 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "outlineLevel"_ostr
, "0");
660 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "collapsed"_ostr
, "false");
661 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "customFormat"_ostr
, "false");
662 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "customHeight"_ostr
, "false");
666 CPPUNIT_TEST_FIXTURE(ScExportTest
, testXfDefaultValuesXLSX
)
668 //tdf#70565 FORMATTING: User Defined Custom Formatting is not applied during importing XLSX documents
669 createScDoc("xlsx/xf_default_values.xlsx");
671 save("Calc Office Open XML");
672 xmlDocUniquePtr pSheet
= parseExport("xl/styles.xml");
673 CPPUNIT_ASSERT(pSheet
);
675 // cellStyleXfs don't need xfId, so we need to make sure it is not saved
676 assertXPathNoAttribute(pSheet
, "/x:styleSheet/x:cellStyleXfs/x:xf[1]"_ostr
, "xfId"_ostr
);
678 // Because numFmtId fontId fillId borderId xfId are not existing during import
679 // it should be created during export, with values set to "0"
680 assertXPath(pSheet
, "/x:styleSheet/x:cellXfs/x:xf[1]"_ostr
, "xfId"_ostr
, "0");
681 assertXPath(pSheet
, "/x:styleSheet/x:cellXfs/x:xf[2]"_ostr
, "xfId"_ostr
, "0");
682 assertXPath(pSheet
, "/x:styleSheet/x:cellXfs/x:xf[3]"_ostr
, "xfId"_ostr
, "0");
683 assertXPath(pSheet
, "/x:styleSheet/x:cellXfs/x:xf[4]"_ostr
, "xfId"_ostr
, "0");
685 // We expected that exactly 15 cellXfs:xf Nodes will be produced
686 assertXPath(pSheet
, "/x:styleSheet/x:cellXfs/x:xf"_ostr
, 14);
689 static auto verifySpreadsheet13(char const* const pTestName
, ScDocument
& rDoc
) -> void
691 // OFFICE-2173 table:tab-color
692 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, Color(0xff3838), rDoc
.GetTabBgColor(0));
693 // OFFICE-3857 table:scale-to-X/table:scale-to-Y
694 OUString styleName
= rDoc
.GetPageStyle(0);
695 ScStyleSheetPool
* pStylePool
= rDoc
.GetStyleSheetPool();
696 SfxStyleSheetBase
* pStyleSheet
= pStylePool
->Find(styleName
, SfxStyleFamily::Page
);
697 CPPUNIT_ASSERT_MESSAGE(pTestName
, pStyleSheet
);
699 SfxItemSet
const& rSet
= pStyleSheet
->GetItemSet();
700 ScPageScaleToItem
const& rItem(rSet
.Get(ATTR_PAGE_SCALETO
));
701 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, sal_uInt16(2), rItem
.GetWidth());
702 CPPUNIT_ASSERT_EQUAL_MESSAGE(pTestName
, sal_uInt16(3), rItem
.GetHeight());
705 CPPUNIT_TEST_FIXTURE(ScExportTest
, testODF13
)
708 createScDoc("ods/spreadsheet13e.ods");
709 ScDocument
* pDoc
= getScDoc();
712 verifySpreadsheet13("import", *pDoc
);
715 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
716 comphelper::ConfigurationChanges::create());
717 officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch
);
718 return pBatch
->commit();
723 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
724 comphelper::ConfigurationChanges::create());
725 officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch
);
728 // FIXME: Error: unexpected attribute "loext:scale-to-X"
731 saveAndReload("calc8");
735 xmlDocUniquePtr pContentXml
= parseExport("content.xml");
736 assertXPath(pContentXml
, "/office:document-content/office:automatic-styles/style:style/"
737 "style:table-properties[@table:tab-color='#ff3838']"_ostr
);
738 xmlDocUniquePtr pStylesXml
= parseExport("styles.xml");
739 assertXPath(pStylesXml
, "/office:document-styles/office:automatic-styles/style:page-layout/"
740 "style:page-layout-properties[@style:scale-to-X='2']"_ostr
);
741 assertXPath(pStylesXml
, "/office:document-styles/office:automatic-styles/style:page-layout/"
742 "style:page-layout-properties[@style:scale-to-Y='3']"_ostr
);
745 verifySpreadsheet13("1.3 reload", *pDoc
);
748 // export ODF 1.2 Extended
749 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
750 comphelper::ConfigurationChanges::create());
751 officecfg::Office::Common::Save::ODF::DefaultVersion::set(9, pBatch
);
754 saveAndReload("calc8");
758 xmlDocUniquePtr pContentXml
= parseExport("content.xml");
759 assertXPath(pContentXml
, "/office:document-content/office:automatic-styles/style:style/"
760 "style:table-properties[@tableooo:tab-color='#ff3838']"_ostr
);
761 xmlDocUniquePtr pStylesXml
= parseExport("styles.xml");
762 assertXPath(pStylesXml
, "/office:document-styles/office:automatic-styles/style:page-layout/"
763 "style:page-layout-properties[@loext:scale-to-X='2']"_ostr
);
764 assertXPath(pStylesXml
, "/office:document-styles/office:automatic-styles/style:page-layout/"
765 "style:page-layout-properties[@loext:scale-to-Y='3']"_ostr
);
768 verifySpreadsheet13("1.2 Extended reload", *pDoc
);
772 std::shared_ptr
<comphelper::ConfigurationChanges
> pBatch(
773 comphelper::ConfigurationChanges::create());
774 officecfg::Office::Common::Save::ODF::DefaultVersion::set(4, pBatch
);
780 xmlDocUniquePtr pContentXml
= parseExport("content.xml");
781 assertXPathNoAttribute(
783 "/office:document-content/office:automatic-styles/style:style/style:table-properties"_ostr
,
785 xmlDocUniquePtr pStylesXml
= parseExport("styles.xml");
786 assertXPathNoAttribute(pStylesXml
,
787 "/office:document-styles/office:automatic-styles/"
788 "style:page-layout[1]/style:page-layout-properties"_ostr
,
790 assertXPathNoAttribute(pStylesXml
,
791 "/office:document-styles/office:automatic-styles/"
792 "style:page-layout[1]/style:page-layout-properties"_ostr
,
795 // don't reload - no point
799 CPPUNIT_TEST_FIXTURE(ScExportTest
, testColumnWidthResaveXLSX
)
801 // tdf#91475 FILESAVE: Column width is not preserved in XLSX / after round trip.
802 // Test if after resave .xlsx file, columns width is identical with previous one
803 createScDoc("xlsx/different-column-width-excel2010.xlsx");
805 save("Calc Office Open XML");
806 xmlDocUniquePtr pSheet
= parseExport("xl/worksheets/sheet1.xml");
807 CPPUNIT_ASSERT(pSheet
);
809 // In original Excel document the width is "24"
810 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "width"_ostr
, "24");
811 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "customWidth"_ostr
, "true");
813 // In original Excel document the width is "12"
814 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "width"_ostr
, "12");
815 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "customWidth"_ostr
, "true");
817 // In original Excel document the width is "6"
818 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "width"_ostr
, "6");
819 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "customWidth"_ostr
, "true");
821 // In original Excel document the width is "1"
822 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "width"_ostr
, "1");
823 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "customWidth"_ostr
, "true");
825 // In original Excel document the width is "250"
826 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "width"_ostr
, "250");
827 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "customWidth"_ostr
, "true");
829 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col"_ostr
, 5);
833 CPPUNIT_TEST_FIXTURE(ScExportTest
, testColumnWidthExportFromODStoXLSX
)
835 // tdf#91475 FILESAVE: Column width is not preserved in XLSX / after round trip.
836 // Test if after export .ods to .xlsx format, displayed columns width
837 // is identical with previous (.ods) one
839 createScDoc("ods/different-column-width.ods");
841 ScDocument
* pDoc
= getScDoc();
843 // Col 1, Tab 0 (Column width 2.00 in)
844 sal_uInt16 nExpectedColumn0Width
845 = pDoc
->GetColWidth(static_cast<SCCOL
>(0), static_cast<SCTAB
>(0), false);
846 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(2880), nExpectedColumn0Width
);
848 // Col 2, Tab 0 (Column width 1.00 in)
849 sal_uInt16 nExpectedColumn1Width
850 = pDoc
->GetColWidth(static_cast<SCCOL
>(1), static_cast<SCTAB
>(0), false);
851 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(1440), nExpectedColumn1Width
);
853 // Col 3, Tab 0 (Column width 0.50 in)
854 sal_uInt16 nExpectedColumn2Width
855 = pDoc
->GetColWidth(static_cast<SCCOL
>(2), static_cast<SCTAB
>(0), false);
856 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(720), nExpectedColumn2Width
);
858 // Col 4, Tab 0 (Column width 0.25 in)
859 sal_uInt16 nExpectedColumn3Width
860 = pDoc
->GetColWidth(static_cast<SCCOL
>(3), static_cast<SCTAB
>(0), false);
861 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(360), nExpectedColumn3Width
);
863 // Col 5, Tab 0 (Column width 13.57 in)
864 sal_uInt16 nExpectedColumn4Width
865 = pDoc
->GetColWidth(static_cast<SCCOL
>(4), static_cast<SCTAB
>(0), false);
866 CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt16
>(19539), nExpectedColumn4Width
);
868 // Export to .xlsx and compare column width with the .ods
869 // We expect that column width from .ods will be exactly the same as imported from .xlsx
871 saveAndReload("Calc Office Open XML");
876 sal_uInt16 nCalcWidth
;
877 nCalcWidth
= pDoc
->GetColWidth(static_cast<SCCOL
>(0), static_cast<SCTAB
>(0), false);
878 CPPUNIT_ASSERT_EQUAL(nExpectedColumn0Width
, nCalcWidth
);
881 nCalcWidth
= pDoc
->GetColWidth(static_cast<SCCOL
>(1), static_cast<SCTAB
>(0), false);
882 CPPUNIT_ASSERT_EQUAL(nExpectedColumn1Width
, nCalcWidth
);
885 nCalcWidth
= pDoc
->GetColWidth(static_cast<SCCOL
>(2), static_cast<SCTAB
>(0), false);
886 CPPUNIT_ASSERT_EQUAL(nExpectedColumn2Width
, nCalcWidth
);
889 nCalcWidth
= pDoc
->GetColWidth(static_cast<SCCOL
>(3), static_cast<SCTAB
>(0), false);
890 CPPUNIT_ASSERT_EQUAL(nExpectedColumn3Width
, nCalcWidth
);
893 nCalcWidth
= pDoc
->GetColWidth(static_cast<SCCOL
>(4), static_cast<SCTAB
>(0), false);
894 CPPUNIT_ASSERT_EQUAL(nExpectedColumn4Width
, nCalcWidth
);
898 CPPUNIT_TEST_FIXTURE(ScExportTest
, testOutlineExportXLSX
)
900 //tdf#100347 FILESAVE FILEOPEN after exporting to .xlsx format grouping are lost
901 //tdf#51524 FILESAVE .xlsx and.xls looses width information for hidden/collapsed grouped columns
902 createScDoc("ods/outline.ods");
904 save("Calc Office Open XML");
905 xmlDocUniquePtr pSheet
= parseExport("xl/worksheets/sheet1.xml");
906 CPPUNIT_ASSERT(pSheet
);
908 // Maximum Outline Row is 4 for this document
909 assertXPath(pSheet
, "/x:worksheet/x:sheetFormatPr"_ostr
, "outlineLevelRow"_ostr
, "4");
910 // Maximum Outline Column is 4 for this document
911 assertXPath(pSheet
, "/x:worksheet/x:sheetFormatPr"_ostr
, "outlineLevelCol"_ostr
, "4");
913 // First XML node, creates two columns (from min=1 to max=2)
914 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "hidden"_ostr
, "false");
915 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "outlineLevel"_ostr
, "1");
916 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "collapsed"_ostr
, "false");
917 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "min"_ostr
, "1");
918 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[1]"_ostr
, "max"_ostr
, "2");
920 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "hidden"_ostr
, "true");
921 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "outlineLevel"_ostr
, "2");
922 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "collapsed"_ostr
, "false");
923 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "min"_ostr
, "3");
924 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[2]"_ostr
, "max"_ostr
, "3");
926 // Column 4 has custom width and it is hidden. We need to make sure that it is created
927 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "hidden"_ostr
, "true");
928 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "outlineLevel"_ostr
, "2");
929 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "collapsed"_ostr
, "false");
930 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "min"_ostr
, "4");
931 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[3]"_ostr
, "max"_ostr
, "4");
933 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "hidden"_ostr
, "true");
934 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "outlineLevel"_ostr
, "3");
935 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "collapsed"_ostr
, "false");
936 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "min"_ostr
, "5");
937 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[4]"_ostr
, "max"_ostr
, "6");
939 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "hidden"_ostr
, "true");
940 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "outlineLevel"_ostr
, "4");
941 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "collapsed"_ostr
, "false");
942 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "min"_ostr
, "7");
943 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[5]"_ostr
, "max"_ostr
, "7");
945 // Column 8 has custom width and it is hidden. We need to make sure that it is created
946 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[6]"_ostr
, "hidden"_ostr
, "true");
947 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[6]"_ostr
, "outlineLevel"_ostr
, "4");
948 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[6]"_ostr
, "collapsed"_ostr
, "false");
949 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[6]"_ostr
, "min"_ostr
, "8");
950 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[6]"_ostr
, "max"_ostr
, "8");
952 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[7]"_ostr
, "hidden"_ostr
, "true");
953 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[7]"_ostr
, "outlineLevel"_ostr
, "4");
954 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[7]"_ostr
, "collapsed"_ostr
, "false");
955 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[7]"_ostr
, "min"_ostr
, "9");
956 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[7]"_ostr
, "max"_ostr
, "19");
958 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[8]"_ostr
, "hidden"_ostr
, "true");
959 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[8]"_ostr
, "outlineLevel"_ostr
, "3");
960 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[8]"_ostr
, "collapsed"_ostr
, "true");
961 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[8]"_ostr
, "min"_ostr
, "20");
962 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[8]"_ostr
, "max"_ostr
, "20");
964 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[9]"_ostr
, "hidden"_ostr
, "true");
965 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[9]"_ostr
, "outlineLevel"_ostr
, "3");
966 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[9]"_ostr
, "collapsed"_ostr
, "false");
967 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[9]"_ostr
, "min"_ostr
, "21");
968 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[9]"_ostr
, "max"_ostr
, "21");
970 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[10]"_ostr
, "hidden"_ostr
, "true");
971 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[10]"_ostr
, "outlineLevel"_ostr
, "2");
972 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[10]"_ostr
, "collapsed"_ostr
, "false");
973 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[10]"_ostr
, "min"_ostr
, "22");
974 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[10]"_ostr
, "max"_ostr
, "23");
976 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[11]"_ostr
, "hidden"_ostr
, "false");
977 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[11]"_ostr
, "outlineLevel"_ostr
, "1");
978 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[11]"_ostr
, "collapsed"_ostr
, "true");
979 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[11]"_ostr
, "min"_ostr
, "24");
980 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[11]"_ostr
, "max"_ostr
, "24");
982 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[12]"_ostr
, "hidden"_ostr
, "false");
983 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[12]"_ostr
, "outlineLevel"_ostr
, "1");
984 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[12]"_ostr
, "collapsed"_ostr
, "false");
985 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[12]"_ostr
, "min"_ostr
, "25");
986 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col[12]"_ostr
, "max"_ostr
, "26");
988 // We expected that exactly 12 unique Nodes will be produced
989 assertXPath(pSheet
, "/x:worksheet/x:cols/x:col"_ostr
, 12);
991 // First row is empty and default so it is not written into XML file
992 // so we need to save 29 rows, as it provides information about outLineLevel
993 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "r"_ostr
, "2");
994 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "hidden"_ostr
, "false");
995 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "outlineLevel"_ostr
, "1");
996 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "collapsed"_ostr
, "false");
997 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[2]"_ostr
, "r"_ostr
, "3");
998 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[2]"_ostr
, "hidden"_ostr
, "false");
999 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[2]"_ostr
, "outlineLevel"_ostr
, "2");
1000 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[2]"_ostr
, "collapsed"_ostr
, "false");
1001 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[3]"_ostr
, "r"_ostr
, "4");
1002 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[3]"_ostr
, "hidden"_ostr
, "false");
1003 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[3]"_ostr
, "outlineLevel"_ostr
, "2");
1004 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[3]"_ostr
, "collapsed"_ostr
, "false");
1005 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[4]"_ostr
, "r"_ostr
, "5");
1006 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[4]"_ostr
, "hidden"_ostr
, "false");
1007 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[4]"_ostr
, "outlineLevel"_ostr
, "3");
1008 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[4]"_ostr
, "collapsed"_ostr
, "false");
1009 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[5]"_ostr
, "r"_ostr
, "6");
1010 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[5]"_ostr
, "hidden"_ostr
, "false");
1011 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[5]"_ostr
, "outlineLevel"_ostr
, "3");
1012 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[5]"_ostr
, "collapsed"_ostr
, "false");
1013 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[6]"_ostr
, "r"_ostr
, "7");
1014 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[6]"_ostr
, "hidden"_ostr
, "true");
1015 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[6]"_ostr
, "outlineLevel"_ostr
, "4");
1016 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[6]"_ostr
, "collapsed"_ostr
, "false");
1017 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[7]"_ostr
, "r"_ostr
, "8");
1018 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[7]"_ostr
, "hidden"_ostr
, "true");
1019 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[7]"_ostr
, "outlineLevel"_ostr
, "4");
1020 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[7]"_ostr
, "collapsed"_ostr
, "false");
1021 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[8]"_ostr
, "r"_ostr
, "9");
1022 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[8]"_ostr
, "hidden"_ostr
, "true");
1023 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[8]"_ostr
, "outlineLevel"_ostr
, "4");
1024 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[8]"_ostr
, "collapsed"_ostr
, "false");
1025 // Next rows are the same as the previous one but it needs to be preserved,
1026 // as they contain information about outlineLevel
1027 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[20]"_ostr
, "r"_ostr
, "21");
1028 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[20]"_ostr
, "hidden"_ostr
, "true");
1029 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[20]"_ostr
, "outlineLevel"_ostr
, "4");
1030 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[20]"_ostr
, "collapsed"_ostr
, "false");
1031 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[21]"_ostr
, "r"_ostr
, "22");
1032 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[21]"_ostr
, "hidden"_ostr
, "false");
1033 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[21]"_ostr
, "outlineLevel"_ostr
, "3");
1034 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[21]"_ostr
, "collapsed"_ostr
, "true");
1035 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[22]"_ostr
, "r"_ostr
, "23");
1036 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[22]"_ostr
, "hidden"_ostr
, "false");
1037 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[22]"_ostr
, "outlineLevel"_ostr
, "3");
1038 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[22]"_ostr
, "collapsed"_ostr
, "false");
1040 // We expected that exactly 29 Row Nodes will be produced
1041 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row"_ostr
, 29);
1044 CPPUNIT_TEST_FIXTURE(ScExportTest
, testAllRowsHiddenXLSX
)
1046 createScDoc("xlsx/tdf105840_allRowsHidden.xlsx");
1048 save("Calc Office Open XML");
1049 xmlDocUniquePtr pSheet
= parseExport("xl/worksheets/sheet1.xml");
1050 CPPUNIT_ASSERT(pSheet
);
1051 assertXPath(pSheet
, "/x:worksheet/x:sheetFormatPr"_ostr
, "zeroHeight"_ostr
, "true");
1052 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row"_ostr
, 0);
1055 CPPUNIT_TEST_FIXTURE(ScExportTest
, testHiddenEmptyRowsXLSX
)
1057 //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX
1058 createScDoc("ods/hidden-empty-rows.ods");
1060 save("Calc Office Open XML");
1061 xmlDocUniquePtr pSheet
= parseExport("xl/worksheets/sheet1.xml");
1062 CPPUNIT_ASSERT(pSheet
);
1064 assertXPath(pSheet
, "/x:worksheet/x:sheetFormatPr"_ostr
, "zeroHeight"_ostr
, "false");
1065 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[1]"_ostr
, "hidden"_ostr
, "true");
1066 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[2]"_ostr
, "hidden"_ostr
, "true");
1067 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[3]"_ostr
, "hidden"_ostr
, "true");
1068 assertXPath(pSheet
, "/x:worksheet/x:sheetData/x:row[4]"_ostr
, "hidden"_ostr
, "false");
1071 CPPUNIT_TEST_FIXTURE(ScExportTest
, testHiddenEmptyColsODS
)
1073 //tdf#98106 FILESAVE: Hidden and empty rows became visible when export to .XLSX
1074 createScDoc("ods/tdf128895_emptyHiddenCols.ods");
1077 xmlDocUniquePtr pSheet
= parseExport("content.xml");
1078 CPPUNIT_ASSERT(pSheet
);
1079 assertXPath(pSheet
, "//table:table/table:table-column[2]"_ostr
);
1080 assertXPath(pSheet
, "//table:table/table:table-column[2]"_ostr
, "number-columns-repeated"_ostr
,
1084 CPPUNIT_TEST_FIXTURE(ScExportTest
, testLandscapeOrientationXLSX
)
1086 //tdf#48767 - Landscape page orientation is not loaded from .xlsx format with MS Excel, after export with Libre Office
1087 createScDoc("ods/hidden-empty-rows.ods");
1089 save("Calc Office Open XML");
1090 xmlDocUniquePtr pSheet
= parseExport("xl/worksheets/sheet1.xml");
1091 CPPUNIT_ASSERT(pSheet
);
1093 // the usePrinterDefaults cannot be saved to allow opening sheets in Landscape mode via MS Excel
1094 assertXPathNoAttribute(pSheet
, "/x:worksheet/x:pageSetup"_ostr
, "usePrinterDefaults"_ostr
);
1095 assertXPath(pSheet
, "/x:worksheet/x:pageSetup"_ostr
, "orientation"_ostr
, "landscape");
1098 CPPUNIT_TEST_FIXTURE(ScExportTest
, testDataBarExportXLSX
)
1100 createScDoc("xlsx/databar.xlsx");
1102 saveAndReload("Calc Office Open XML");
1104 ScDocument
* pDoc
= getScDoc();
1106 testDataBar_Impl(*pDoc
);
1109 CPPUNIT_TEST_FIXTURE(ScExportTest
, testMiscRowHeightExport
)
1111 static const TestParam::RowData DfltRowData
[] = {
1112 { 0, 4, 0, 529, 0, false },
1113 { 5, 10, 0, 1058, 0, false },
1114 { 17, 20, 0, 1746, 0, false },
1115 // check last couple of row in document to ensure
1116 // they are 5.29mm ( effective default row xlsx height )
1117 { 1048573, 1048575, 0, 529, 0, false },
1120 static const TestParam::RowData EmptyRepeatRowData
[] = {
1121 // rows 0-4, 5-10, 17-20 are all set at various
1122 // heights, there is no content in the rows, there
1123 // was a bug where only the first row ( of repeated rows )
1124 // was set after export
1125 { 0, 4, 0, 529, 0, false },
1126 { 5, 10, 0, 1058, 0, false },
1127 { 17, 20, 0, 1767, 0, false },
1130 TestParam aTestValues
[] = {
1131 // Checks that some distributed ( non-empty ) heights remain set after export (roundtrip)
1132 // additionally there is effectively a default row height ( 5.29 mm ). So we test the
1133 // unset rows at the end of the document to ensure the effective xlsx default height
1134 // is set there too.
1135 { u
"xlsx/miscrowheights.xlsx", "Calc Office Open XML", SAL_N_ELEMENTS(DfltRowData
),
1137 // Checks that some distributed ( non-empty ) heights remain set after export (to xls)
1138 { u
"xlsx/miscrowheights.xlsx", "MS Excel 97", SAL_N_ELEMENTS(DfltRowData
), DfltRowData
},
1139 // Checks that repreated rows ( of various heights ) remain set after export ( to xlsx )
1140 { u
"ods/miscemptyrepeatedrowheights.ods", "Calc Office Open XML",
1141 SAL_N_ELEMENTS(EmptyRepeatRowData
), EmptyRepeatRowData
},
1142 // Checks that repreated rows ( of various heights ) remain set after export ( to xls )
1143 { u
"ods/miscemptyrepeatedrowheights.ods", "MS Excel 97", SAL_N_ELEMENTS(EmptyRepeatRowData
),
1144 EmptyRepeatRowData
},
1146 miscRowHeightsTest(aTestValues
, SAL_N_ELEMENTS(aTestValues
));
1151 void setAttribute(ScFieldEditEngine
& rEE
, sal_Int32 nPara
, sal_Int32 nStart
, sal_Int32 nEnd
,
1152 sal_uInt16 nType
, Color nColor
= COL_BLACK
)
1155 aSel
.nStartPara
= aSel
.nEndPara
= nPara
;
1156 aSel
.nStartPos
= nStart
;
1157 aSel
.nEndPos
= nEnd
;
1159 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
1162 case EE_CHAR_WEIGHT
:
1164 SvxWeightItem
aWeight(WEIGHT_BOLD
, nType
);
1165 aItemSet
.Put(aWeight
);
1166 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1169 case EE_CHAR_ITALIC
:
1171 SvxPostureItem
aItalic(ITALIC_NORMAL
, nType
);
1172 aItemSet
.Put(aItalic
);
1173 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1176 case EE_CHAR_STRIKEOUT
:
1178 SvxCrossedOutItem
aCrossOut(STRIKEOUT_SINGLE
, nType
);
1179 aItemSet
.Put(aCrossOut
);
1180 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1183 case EE_CHAR_OVERLINE
:
1185 SvxOverlineItem
aItem(LINESTYLE_DOUBLE
, nType
);
1186 aItemSet
.Put(aItem
);
1187 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1190 case EE_CHAR_UNDERLINE
:
1192 SvxUnderlineItem
aItem(LINESTYLE_DOUBLE
, nType
);
1193 aItemSet
.Put(aItem
);
1194 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1199 SvxColorItem
aItem(nColor
, nType
);
1200 aItemSet
.Put(aItem
);
1201 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1208 void setFont(ScFieldEditEngine
& rEE
, sal_Int32 nPara
, sal_Int32 nStart
, sal_Int32 nEnd
,
1209 const OUString
& rFontName
)
1212 aSel
.nStartPara
= aSel
.nEndPara
= nPara
;
1213 aSel
.nStartPos
= nStart
;
1214 aSel
.nEndPos
= nEnd
;
1216 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
1217 SvxFontItem
aItem(FAMILY_MODERN
, rFontName
, "", PITCH_VARIABLE
, RTL_TEXTENCODING_UTF8
,
1219 aItemSet
.Put(aItem
);
1220 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1223 void setEscapement(ScFieldEditEngine
& rEE
, sal_Int32 nPara
, sal_Int32 nStart
, sal_Int32 nEnd
,
1224 short nEsc
, sal_uInt8 nRelSize
)
1227 aSel
.nStartPara
= aSel
.nEndPara
= nPara
;
1228 aSel
.nStartPos
= nStart
;
1229 aSel
.nEndPos
= nEnd
;
1231 SfxItemSet aItemSet
= rEE
.GetEmptyItemSet();
1232 SvxEscapementItem
aItem(nEsc
, nRelSize
, EE_CHAR_ESCAPEMENT
);
1233 aItemSet
.Put(aItem
);
1234 rEE
.QuickSetAttribs(aItemSet
, aSel
);
1238 CPPUNIT_TEST_FIXTURE(ScExportTest
, testNamedRangeBugfdo62729
)
1240 #if !defined(MACOSX) // FIXME: infinite loop on jenkins' mac
1241 createScDoc("ods/fdo62729.ods");
1242 ScDocument
* pDoc
= getScDoc();
1244 ScRangeName
* pNames
= pDoc
->GetRangeName();
1245 //should be just a single named range
1246 CPPUNIT_ASSERT_EQUAL(size_t(1), pNames
->size());
1248 //should be still a single named range
1249 CPPUNIT_ASSERT_EQUAL(size_t(1), pNames
->size());
1250 saveAndReload("calc8");
1254 pNames
= pDoc
->GetRangeName();
1255 //after reload should still have a named range
1256 CPPUNIT_ASSERT_EQUAL(size_t(1), pNames
->size());
1260 CPPUNIT_TEST_FIXTURE(ScExportTest
, testBuiltinRangesXLSX
)
1262 createScDoc("xlsx/built-in_ranges.xlsx");
1264 save("Calc Office Open XML");
1265 xmlDocUniquePtr pDoc
= parseExport("xl/workbook.xml");
1266 CPPUNIT_ASSERT(pDoc
);
1268 //assert the existing OOXML built-in names are still there
1269 assertXPathContent(pDoc
,
1270 "/x:workbook/x:definedNames/"
1271 "x:definedName[@name='_xlnm._FilterDatabase'][@localSheetId='0']"_ostr
,
1272 "'Sheet1 Test'!$A$1:$A$5");
1273 assertXPathContent(pDoc
,
1274 "/x:workbook/x:definedNames/"
1275 "x:definedName[@name='_xlnm._FilterDatabase'][@localSheetId='1']"_ostr
,
1276 "'Sheet2 Test'!$K$10:$K$14");
1279 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='0']"_ostr
,
1280 "'Sheet1 Test'!$A$1:$A$5");
1283 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area'][@localSheetId='1']"_ostr
,
1284 "'Sheet2 Test'!$K$10:$M$18");
1286 //...and that no extra ones are added (see tdf#112571)
1288 "/x:workbook/x:definedNames/"
1289 "x:definedName[@name='_xlnm._FilterDatabase_0'][@localSheetId='0']"_ostr
,
1292 "/x:workbook/x:definedNames/"
1293 "x:definedName[@name='_xlnm._FilterDatabase_0'][@localSheetId='1']"_ostr
,
1297 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='0']"_ostr
,
1301 "/x:workbook/x:definedNames/x:definedName[@name='_xlnm.Print_Area_0'][@localSheetId='1']"_ostr
,
1305 CPPUNIT_TEST_FIXTURE(ScExportTest
, testRichTextExportODS
)
1309 static bool isBold(const editeng::Section
& rAttr
)
1312 rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(), [](const SfxPoolItem
* p
) {
1313 return p
->Which() == EE_CHAR_WEIGHT
1314 && static_cast<const SvxWeightItem
*>(p
)->GetWeight() == WEIGHT_BOLD
;
1318 static bool isItalic(const editeng::Section
& rAttr
)
1321 rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(), [](const SfxPoolItem
* p
) {
1322 return p
->Which() == EE_CHAR_ITALIC
1323 && static_cast<const SvxPostureItem
*>(p
)->GetPosture() == ITALIC_NORMAL
;
1327 static bool isStrikeOut(const editeng::Section
& rAttr
)
1330 rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(), [](const SfxPoolItem
* p
) {
1331 return p
->Which() == EE_CHAR_STRIKEOUT
1332 && static_cast<const SvxCrossedOutItem
*>(p
)->GetStrikeout()
1333 == STRIKEOUT_SINGLE
;
1337 static bool isOverline(const editeng::Section
& rAttr
, FontLineStyle eStyle
)
1339 return std::any_of(rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(),
1340 [&eStyle
](const SfxPoolItem
* p
) {
1341 return p
->Which() == EE_CHAR_OVERLINE
1342 && static_cast<const SvxOverlineItem
*>(p
)->GetLineStyle()
1347 static bool isUnderline(const editeng::Section
& rAttr
, FontLineStyle eStyle
)
1349 return std::any_of(rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(),
1350 [&eStyle
](const SfxPoolItem
* p
) {
1351 return p
->Which() == EE_CHAR_UNDERLINE
1352 && static_cast<const SvxUnderlineItem
*>(p
)->GetLineStyle()
1357 static bool isFont(const editeng::Section
& rAttr
, const OUString
& rFontName
)
1359 return std::any_of(rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(),
1360 [&rFontName
](const SfxPoolItem
* p
) {
1361 return p
->Which() == EE_CHAR_FONTINFO
1362 && static_cast<const SvxFontItem
*>(p
)->GetFamilyName()
1367 static bool isEscapement(const editeng::Section
& rAttr
, short nEsc
, sal_uInt8 nRelSize
)
1369 return std::any_of(rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(),
1370 [&nEsc
, &nRelSize
](const SfxPoolItem
* p
) {
1371 if (p
->Which() != EE_CHAR_ESCAPEMENT
)
1373 const SvxEscapementItem
* pItem
1374 = static_cast<const SvxEscapementItem
*>(p
);
1375 return ((pItem
->GetEsc() == nEsc
)
1376 && (pItem
->GetProportionalHeight() == nRelSize
));
1380 static bool isColor(const editeng::Section
& rAttr
, Color nColor
)
1382 return std::any_of(rAttr
.maAttributes
.begin(), rAttr
.maAttributes
.end(),
1383 [&nColor
](const SfxPoolItem
* p
) {
1384 return p
->Which() == EE_CHAR_COLOR
1385 && static_cast<const SvxColorItem
*>(p
)->GetValue()
1390 bool checkB2(const EditTextObject
* pText
) const
1395 if (pText
->GetParagraphCount() != 1)
1398 if (pText
->GetText(0) != "Bold and Italic")
1401 std::vector
<editeng::Section
> aSecAttrs
;
1402 pText
->GetAllSections(aSecAttrs
);
1403 if (aSecAttrs
.size() != 3)
1406 // Check the first bold section.
1407 const editeng::Section
* pAttr
= aSecAttrs
.data();
1408 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 0 || pAttr
->mnEnd
!= 4)
1411 if (pAttr
->maAttributes
.size() != 1 || !isBold(*pAttr
))
1414 // The middle section should be unformatted.
1415 pAttr
= &aSecAttrs
[1];
1416 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 4 || pAttr
->mnEnd
!= 9)
1419 if (!pAttr
->maAttributes
.empty())
1422 // The last section should be italic.
1423 pAttr
= &aSecAttrs
[2];
1424 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 9 || pAttr
->mnEnd
!= 15)
1427 if (pAttr
->maAttributes
.size() != 1 || !isItalic(*pAttr
))
1433 bool checkB4(const EditTextObject
* pText
) const
1438 if (pText
->GetParagraphCount() != 3)
1441 if (pText
->GetText(0) != "One")
1444 if (pText
->GetText(1) != "Two")
1447 if (pText
->GetText(2) != "Three")
1453 bool checkB5(const EditTextObject
* pText
) const
1458 if (pText
->GetParagraphCount() != 6)
1461 if (!pText
->GetText(0).isEmpty())
1464 if (pText
->GetText(1) != "Two")
1467 if (pText
->GetText(2) != "Three")
1470 if (!pText
->GetText(3).isEmpty())
1473 if (pText
->GetText(4) != "Five")
1476 if (!pText
->GetText(5).isEmpty())
1482 bool checkB6(const EditTextObject
* pText
) const
1487 if (pText
->GetParagraphCount() != 1)
1490 if (pText
->GetText(0) != "Strike Me")
1493 std::vector
<editeng::Section
> aSecAttrs
;
1494 pText
->GetAllSections(aSecAttrs
);
1495 if (aSecAttrs
.size() != 2)
1498 // Check the first strike-out section.
1499 const editeng::Section
* pAttr
= aSecAttrs
.data();
1500 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 0 || pAttr
->mnEnd
!= 6)
1503 if (pAttr
->maAttributes
.size() != 1 || !isStrikeOut(*pAttr
))
1506 // The last section should be unformatted.
1507 pAttr
= &aSecAttrs
[1];
1508 return pAttr
->mnParagraph
== 0 && pAttr
->mnStart
== 6 && pAttr
->mnEnd
== 9;
1511 bool checkB7(const EditTextObject
* pText
) const
1516 if (pText
->GetParagraphCount() != 1)
1519 if (pText
->GetText(0) != "Font1 and Font2")
1522 std::vector
<editeng::Section
> aSecAttrs
;
1523 pText
->GetAllSections(aSecAttrs
);
1524 if (aSecAttrs
.size() != 3)
1527 // First section should have "Courier" font applied.
1528 const editeng::Section
* pAttr
= aSecAttrs
.data();
1529 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 0 || pAttr
->mnEnd
!= 5)
1532 if (pAttr
->maAttributes
.size() != 1 || !isFont(*pAttr
, "Courier"))
1535 // Last section should have "Luxi Mono" applied.
1536 pAttr
= &aSecAttrs
[2];
1537 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 10 || pAttr
->mnEnd
!= 15)
1540 if (pAttr
->maAttributes
.size() != 1 || !isFont(*pAttr
, "Luxi Mono"))
1546 bool checkB8(const EditTextObject
* pText
) const
1551 if (pText
->GetParagraphCount() != 1)
1554 if (pText
->GetText(0) != "Over and Under")
1557 std::vector
<editeng::Section
> aSecAttrs
;
1558 pText
->GetAllSections(aSecAttrs
);
1559 if (aSecAttrs
.size() != 3)
1562 // First section should have overline applied.
1563 const editeng::Section
* pAttr
= aSecAttrs
.data();
1564 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 0 || pAttr
->mnEnd
!= 4)
1567 if (pAttr
->maAttributes
.size() != 1 || !isOverline(*pAttr
, LINESTYLE_DOUBLE
))
1570 // Last section should have underline applied.
1571 pAttr
= &aSecAttrs
[2];
1572 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 9 || pAttr
->mnEnd
!= 14)
1575 if (pAttr
->maAttributes
.size() != 1 || !isUnderline(*pAttr
, LINESTYLE_DOUBLE
))
1581 bool checkB9(const EditTextObject
* pText
) const
1586 if (pText
->GetParagraphCount() != 1)
1589 if (pText
->GetText(0) != "Sub and Super")
1592 std::vector
<editeng::Section
> aSecAttrs
;
1593 pText
->GetAllSections(aSecAttrs
);
1594 if (aSecAttrs
.size() != 3)
1598 const editeng::Section
* pAttr
= aSecAttrs
.data();
1599 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 0 || pAttr
->mnEnd
!= 3)
1602 if (pAttr
->maAttributes
.size() != 1 || !isEscapement(*pAttr
, 32, 64))
1606 pAttr
= &aSecAttrs
[2];
1607 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 8 || pAttr
->mnEnd
!= 13)
1610 if (pAttr
->maAttributes
.size() != 1 || !isEscapement(*pAttr
, -32, 66))
1616 bool checkB10(const EditTextObject
* pText
) const
1621 if (pText
->GetParagraphCount() != 1)
1624 if (pText
->GetText(0) != "BLUE AUTO")
1627 std::vector
<editeng::Section
> aSecAttrs
;
1628 pText
->GetAllSections(aSecAttrs
);
1629 if (aSecAttrs
.size() != 2)
1633 const editeng::Section
* pAttr
= &aSecAttrs
[1];
1634 if (pAttr
->mnParagraph
!= 0 || pAttr
->mnStart
!= 5 || pAttr
->mnEnd
!= 9)
1637 if (pAttr
->maAttributes
.size() != 1 || !isColor(*pAttr
, COL_AUTO
))
1645 // Start with an empty document, put one edit text cell, and make sure it
1646 // survives the save and reload.
1648 const EditTextObject
* pEditText
;
1650 ScDocument
* pDoc
= getScDoc();
1651 CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.",
1652 pDoc
->GetTableCount() > 0);
1654 // Insert an edit text cell.
1655 ScFieldEditEngine
* pEE
= &pDoc
->GetEditEngine();
1656 pEE
->SetTextCurrentDefaults("Bold and Italic");
1657 // Set the 'Bold' part bold.
1658 setAttribute(*pEE
, 0, 0, 4, EE_CHAR_WEIGHT
);
1659 // Set the 'Italic' part italic.
1660 setAttribute(*pEE
, 0, 9, 15, EE_CHAR_ITALIC
);
1662 aSel
.nStartPara
= aSel
.nEndPara
= 0;
1664 // Set this edit text to cell B2.
1665 pDoc
->SetEditText(ScAddress(1, 1, 0), pEE
->CreateTextObject());
1666 pEditText
= pDoc
->GetEditText(ScAddress(1, 1, 0));
1667 CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value.", aCheckFunc
.checkB2(pEditText
));
1670 // Now, save and reload this document.
1671 saveAndReload("calc8");
1673 ScDocument
* pDoc
= getScDoc();
1674 CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.",
1675 pDoc
->GetTableCount() > 0);
1676 ScFieldEditEngine
* pEE
= &pDoc
->GetEditEngine();
1677 pEditText
= pDoc
->GetEditText(ScAddress(1, 1, 0));
1679 // Make sure the content of B2 is still intact.
1680 CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value.", aCheckFunc
.checkB2(pEditText
));
1682 // Insert a multi-line content to B4.
1684 pEE
->SetTextCurrentDefaults("One\nTwo\nThree");
1685 pDoc
->SetEditText(ScAddress(1, 3, 0), pEE
->CreateTextObject());
1686 pEditText
= pDoc
->GetEditText(ScAddress(1, 3, 0));
1687 CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc
.checkB4(pEditText
));
1690 // Reload the doc again, and check the content of B2 and B4.
1691 saveAndReload("calc8");
1693 ScDocument
* pDoc
= getScDoc();
1694 ScFieldEditEngine
* pEE
= &pDoc
->GetEditEngine();
1696 pEditText
= pDoc
->GetEditText(ScAddress(1, 1, 0));
1697 CPPUNIT_ASSERT_MESSAGE("B2 should be an edit text.", pEditText
);
1698 pEditText
= pDoc
->GetEditText(ScAddress(1, 3, 0));
1699 CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value.", aCheckFunc
.checkB4(pEditText
));
1701 // Insert a multi-line content to B5, but this time, set some empty paragraphs.
1703 pEE
->SetTextCurrentDefaults("\nTwo\nThree\n\nFive\n");
1704 pDoc
->SetEditText(ScAddress(1, 4, 0), pEE
->CreateTextObject());
1705 pEditText
= pDoc
->GetEditText(ScAddress(1, 4, 0));
1706 CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value.", aCheckFunc
.checkB5(pEditText
));
1708 // Insert a text with strikethrough in B6.
1710 pEE
->SetTextCurrentDefaults("Strike Me");
1711 // Set the 'Strike' part strikethrough.
1712 setAttribute(*pEE
, 0, 0, 6, EE_CHAR_STRIKEOUT
);
1713 pDoc
->SetEditText(ScAddress(1, 5, 0), pEE
->CreateTextObject());
1714 pEditText
= pDoc
->GetEditText(ScAddress(1, 5, 0));
1715 CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value.", aCheckFunc
.checkB6(pEditText
));
1717 // Insert a text with different font segments in B7.
1719 pEE
->SetTextCurrentDefaults("Font1 and Font2");
1720 setFont(*pEE
, 0, 0, 5, "Courier");
1721 setFont(*pEE
, 0, 10, 15, "Luxi Mono");
1722 pDoc
->SetEditText(ScAddress(1, 6, 0), pEE
->CreateTextObject());
1723 pEditText
= pDoc
->GetEditText(ScAddress(1, 6, 0));
1724 CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value.", aCheckFunc
.checkB7(pEditText
));
1726 // Insert a text with overline and underline in B8.
1728 pEE
->SetTextCurrentDefaults("Over and Under");
1729 setAttribute(*pEE
, 0, 0, 4, EE_CHAR_OVERLINE
);
1730 setAttribute(*pEE
, 0, 9, 14, EE_CHAR_UNDERLINE
);
1731 pDoc
->SetEditText(ScAddress(1, 7, 0), pEE
->CreateTextObject());
1732 pEditText
= pDoc
->GetEditText(ScAddress(1, 7, 0));
1733 CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value.", aCheckFunc
.checkB8(pEditText
));
1736 pEE
->SetTextCurrentDefaults("Sub and Super");
1737 setEscapement(*pEE
, 0, 0, 3, 32, 64);
1738 setEscapement(*pEE
, 0, 8, 13, -32, 66);
1739 pDoc
->SetEditText(ScAddress(1, 8, 0), pEE
->CreateTextObject());
1740 pEditText
= pDoc
->GetEditText(ScAddress(1, 8, 0));
1741 CPPUNIT_ASSERT_MESSAGE("Incorrect B9 value.", aCheckFunc
.checkB9(pEditText
));
1743 ScPatternAttr
aCellFontColor(pDoc
->GetPool());
1744 aCellFontColor
.GetItemSet().Put(SvxColorItem(COL_BLUE
, ATTR_FONT_COLOR
));
1745 // Set font color of B10 to blue.
1746 pDoc
->ApplyPattern(1, 9, 0, aCellFontColor
);
1748 pEE
->SetTextCurrentDefaults("BLUE AUTO");
1749 // Set the color of the string "AUTO" to automatic color.
1750 setAttribute(*pEE
, 0, 5, 9, EE_CHAR_COLOR
, COL_AUTO
);
1751 pDoc
->SetEditText(ScAddress(1, 9, 0), pEE
->CreateTextObject());
1752 pEditText
= pDoc
->GetEditText(ScAddress(1, 9, 0));
1753 CPPUNIT_ASSERT_MESSAGE("Incorrect B10 value.", aCheckFunc
.checkB10(pEditText
));
1756 // Reload the doc again, and check the content of B2, B4, B6 and B7.
1757 saveAndReload("calc8");
1758 ScDocument
* pDoc
= getScDoc();
1760 pEditText
= pDoc
->GetEditText(ScAddress(1, 1, 0));
1761 CPPUNIT_ASSERT_MESSAGE("Incorrect B2 value after save and reload.",
1762 aCheckFunc
.checkB2(pEditText
));
1763 pEditText
= pDoc
->GetEditText(ScAddress(1, 3, 0));
1764 CPPUNIT_ASSERT_MESSAGE("Incorrect B4 value after save and reload.",
1765 aCheckFunc
.checkB4(pEditText
));
1766 pEditText
= pDoc
->GetEditText(ScAddress(1, 4, 0));
1767 CPPUNIT_ASSERT_MESSAGE("Incorrect B5 value after save and reload.",
1768 aCheckFunc
.checkB5(pEditText
));
1769 pEditText
= pDoc
->GetEditText(ScAddress(1, 5, 0));
1770 CPPUNIT_ASSERT_MESSAGE("Incorrect B6 value after save and reload.",
1771 aCheckFunc
.checkB6(pEditText
));
1772 pEditText
= pDoc
->GetEditText(ScAddress(1, 6, 0));
1773 CPPUNIT_ASSERT_MESSAGE("Incorrect B7 value after save and reload.",
1774 aCheckFunc
.checkB7(pEditText
));
1775 pEditText
= pDoc
->GetEditText(ScAddress(1, 7, 0));
1776 CPPUNIT_ASSERT_MESSAGE("Incorrect B8 value after save and reload.",
1777 aCheckFunc
.checkB8(pEditText
));
1778 pEditText
= pDoc
->GetEditText(ScAddress(1, 9, 0));
1779 CPPUNIT_ASSERT_MESSAGE("Incorrect B10 value after save and reload.",
1780 aCheckFunc
.checkB10(pEditText
));
1783 CPPUNIT_TEST_FIXTURE(ScExportTest
, testRichTextCellFormatXLSX
)
1785 createScDoc("xls/cellformat.xls");
1787 save("Calc Office Open XML");
1788 xmlDocUniquePtr pSheet
= parseExport("xl/worksheets/sheet1.xml");
1789 CPPUNIT_ASSERT(pSheet
);
1791 // make sure the only cell in this doc is assigned some formatting record
1792 OUString aCellFormat
= getXPath(pSheet
, "/x:worksheet/x:sheetData/x:row/x:c"_ostr
, "s"_ostr
);
1793 CPPUNIT_ASSERT_MESSAGE("Cell format is missing", !aCellFormat
.isEmpty());
1795 xmlDocUniquePtr pStyles
= parseExport("xl/styles.xml");
1796 CPPUNIT_ASSERT(pStyles
);
1798 OString nFormatIdx
= OString::number(aCellFormat
.toInt32() + 1);
1799 const OString
aXPath1("/x:styleSheet/x:cellXfs/x:xf[" + nFormatIdx
+ "]/x:alignment");
1800 // formatting record is set to wrap text
1801 assertXPath(pStyles
, aXPath1
, "wrapText"_ostr
, "true");
1803 // see what font it references
1804 const OString
aXPath2("/x:styleSheet/x:cellXfs/x:xf[" + nFormatIdx
+ "]");
1805 OUString aFontId
= getXPath(pStyles
, aXPath2
, "fontId"_ostr
);
1806 OString nFontIdx
= OString::number(aFontId
.toInt32() + 1);
1808 // that font should be bold
1809 const OString
aXPath3("/x:styleSheet/x:fonts/x:font[" + nFontIdx
+ "]/x:b");
1810 assertXPath(pStyles
, aXPath3
, "val"_ostr
, "true");
1813 CPPUNIT_TEST_FIXTURE(ScExportTest
, testWrapText
)
1815 createScDoc("xlsx/wrap-text.xlsx");
1817 save("Calc Office Open XML");
1819 xmlDocUniquePtr pStyles
= parseExport("xl/styles.xml");
1820 CPPUNIT_ASSERT(pStyles
);
1822 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs"_ostr
, "count"_ostr
, "7");
1824 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[1]/x:alignment"_ostr
, "wrapText"_ostr
,
1826 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[2]/x:alignment"_ostr
, "wrapText"_ostr
,
1828 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[3]/x:alignment"_ostr
, "wrapText"_ostr
,
1830 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[4]/x:alignment"_ostr
, "wrapText"_ostr
,
1832 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[5]/x:alignment"_ostr
, "wrapText"_ostr
,
1834 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[6]/x:alignment"_ostr
, "wrapText"_ostr
,
1836 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[7]/x:alignment"_ostr
, "wrapText"_ostr
,
1840 CPPUNIT_TEST_FIXTURE(ScExportTest
, testFormulaRefSheetNameODS
)
1842 createScDoc("ods/formula-quote-in-sheet-name.ods");
1844 ScDocument
* pDoc
= getScDoc();
1846 sc::AutoCalcSwitch
aACSwitch(*pDoc
, true); // turn on auto calc.
1847 pDoc
->SetString(ScAddress(1, 1, 0), "='90''s Data'.B2");
1848 CPPUNIT_ASSERT_EQUAL(1.1, pDoc
->GetValue(ScAddress(1, 1, 0)));
1849 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("='90''s Data'.B2"),
1850 pDoc
->GetFormula(1, 1, 0));
1852 // Now, save and reload this document.
1853 saveAndReload("calc8");
1855 ScDocument
* pDoc
= getScDoc();
1857 CPPUNIT_ASSERT_EQUAL(1.1, pDoc
->GetValue(ScAddress(1, 1, 0)));
1858 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula", OUString("='90''s Data'.B2"),
1859 pDoc
->GetFormula(1, 1, 0));
1862 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCellValuesExportODS
)
1864 // Start with an empty document
1867 ScDocument
* pDoc
= getScDoc();
1868 CPPUNIT_ASSERT_MESSAGE("This document should at least have one sheet.",
1869 pDoc
->GetTableCount() > 0);
1871 // set a value double
1872 pDoc
->SetValue(ScAddress(0, 0, 0), 2.0); // A1
1875 pDoc
->SetValue(ScAddress(2, 0, 0), 3.0); // C1
1876 pDoc
->SetValue(ScAddress(3, 0, 0), 3); // D1
1877 pDoc
->SetString(ScAddress(4, 0, 0), "=10*C1/4"); // E1
1878 pDoc
->SetValue(ScAddress(5, 0, 0), 3.0); // F1
1879 pDoc
->SetString(ScAddress(7, 0, 0), "=SUM(C1:F1)"); //H1
1882 pDoc
->SetString(ScAddress(0, 2, 0), "a simple line"); //A3
1884 // set a digit string
1885 pDoc
->SetString(ScAddress(0, 4, 0), "'12"); //A5
1886 // set a contiguous value
1887 pDoc
->SetValue(ScAddress(0, 5, 0), 12.0); //A6
1888 // set a contiguous string
1889 pDoc
->SetString(ScAddress(0, 6, 0), "a string"); //A7
1890 // set a contiguous formula
1891 pDoc
->SetString(ScAddress(0, 7, 0), "=$A$6"); //A8
1894 saveAndReload("calc8");
1895 ScDocument
* pDoc
= getScDoc();
1896 CPPUNIT_ASSERT_MESSAGE("Reloaded document should at least have one sheet.",
1897 pDoc
->GetTableCount() > 0);
1900 CPPUNIT_ASSERT_EQUAL(2.0, pDoc
->GetValue(0, 0, 0));
1901 CPPUNIT_ASSERT_EQUAL(3.0, pDoc
->GetValue(2, 0, 0));
1902 CPPUNIT_ASSERT_EQUAL(3.0, pDoc
->GetValue(3, 0, 0));
1903 CPPUNIT_ASSERT_EQUAL(7.5, pDoc
->GetValue(4, 0, 0));
1904 CPPUNIT_ASSERT_EQUAL(3.0, pDoc
->GetValue(5, 0, 0));
1907 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =10*C1/4", OUString("=10*C1/4"),
1908 pDoc
->GetFormula(4, 0, 0));
1909 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =SUM(C1:F1)", OUString("=SUM(C1:F1)"),
1910 pDoc
->GetFormula(7, 0, 0));
1911 CPPUNIT_ASSERT_EQUAL(16.5, pDoc
->GetValue(7, 0, 0));
1914 ScRefCellValue aCell
;
1915 aCell
.assign(*pDoc
, ScAddress(0, 2, 0));
1916 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING
, aCell
.getType());
1918 // check for an empty cell
1919 aCell
.assign(*pDoc
, ScAddress(0, 3, 0));
1920 CPPUNIT_ASSERT_EQUAL(CELLTYPE_NONE
, aCell
.getType());
1922 // check a digit string
1923 aCell
.assign(*pDoc
, ScAddress(0, 4, 0));
1924 CPPUNIT_ASSERT_EQUAL(CELLTYPE_STRING
, aCell
.getType());
1926 //check contiguous values
1927 CPPUNIT_ASSERT_EQUAL(12.0, pDoc
->GetValue(0, 5, 0));
1928 CPPUNIT_ASSERT_EQUAL(OUString("a string"), pDoc
->GetString(0, 6, 0));
1929 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula =$A$6", OUString("=$A$6"),
1930 pDoc
->GetFormula(0, 7, 0));
1931 CPPUNIT_ASSERT_EQUAL(pDoc
->GetValue(0, 5, 0), pDoc
->GetValue(0, 7, 0));
1934 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCellNoteExportODS
)
1936 createScDoc("ods/single-note.ods");
1937 ScAddress
aPos(0, 0, 0); // Start with A1.
1939 ScDocument
* pDoc
= getScDoc();
1941 CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc
->HasNote(aPos
));
1943 aPos
.IncRow(); // Move to A2.
1944 ScPostIt
* pNote
= pDoc
->GetOrCreateNote(aPos
);
1945 pNote
->SetText(aPos
, "Note One");
1946 pNote
->SetAuthor("Author One");
1947 CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc
->HasNote(aPos
));
1950 saveAndReload("calc8");
1951 ScDocument
* pDoc
= getScDoc();
1953 aPos
.SetRow(0); // Move back to A1.
1954 CPPUNIT_ASSERT_MESSAGE("There should be a note at A1.", pDoc
->HasNote(aPos
));
1955 aPos
.IncRow(); // Move to A2.
1956 CPPUNIT_ASSERT_MESSAGE("There should be a note at A2.", pDoc
->HasNote(aPos
));
1959 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCellNoteExportXLS
)
1961 // Start with an empty document.s
1962 createScDoc("ods/notes-on-3-sheets.ods");
1964 ScDocument
* pDoc
= getScDoc();
1965 CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3),
1966 pDoc
->GetTableCount());
1968 // Check note's presence.
1969 CPPUNIT_ASSERT(pDoc
->HasNote(ScAddress(0, 0, 0)));
1970 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 1, 0)));
1971 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 2, 0)));
1973 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 0, 1)));
1974 CPPUNIT_ASSERT(pDoc
->HasNote(ScAddress(0, 1, 1)));
1975 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 2, 1)));
1977 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 0, 2)));
1978 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 1, 2)));
1979 CPPUNIT_ASSERT(pDoc
->HasNote(ScAddress(0, 2, 2)));
1981 // save and reload as XLS.
1982 saveAndReload("MS Excel 97");
1984 ScDocument
* pDoc
= getScDoc();
1985 CPPUNIT_ASSERT_EQUAL_MESSAGE("This document should have 3 sheets.", SCTAB(3),
1986 pDoc
->GetTableCount());
1988 // Check note's presence again.
1989 CPPUNIT_ASSERT(pDoc
->HasNote(ScAddress(0, 0, 0)));
1990 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 1, 0)));
1991 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 2, 0)));
1993 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 0, 1)));
1994 CPPUNIT_ASSERT(pDoc
->HasNote(ScAddress(0, 1, 1)));
1995 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 2, 1)));
1997 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 0, 2)));
1998 CPPUNIT_ASSERT(!pDoc
->HasNote(ScAddress(0, 1, 2)));
1999 CPPUNIT_ASSERT(pDoc
->HasNote(ScAddress(0, 2, 2)));
2005 void checkMatrixRange(ScDocument
& rDoc
, const ScRange
& rRange
)
2008 ScAddress aMatOrigin
;
2009 for (SCCOL nCol
= rRange
.aStart
.Col(); nCol
<= rRange
.aEnd
.Col(); ++nCol
)
2011 for (SCROW nRow
= rRange
.aStart
.Row(); nRow
<= rRange
.aEnd
.Row(); ++nRow
)
2013 ScAddress
aPos(nCol
, nRow
, rRange
.aStart
.Tab());
2014 bool bIsMatrix
= rDoc
.GetMatrixFormulaRange(aPos
, aMatRange
);
2015 CPPUNIT_ASSERT_MESSAGE("Matrix expected, but not found.", bIsMatrix
);
2016 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong matrix range.", rRange
, aMatRange
);
2017 const ScFormulaCell
* pCell
= rDoc
.GetFormulaCell(aPos
);
2018 CPPUNIT_ASSERT_MESSAGE("This must be a formula cell.", pCell
);
2020 bIsMatrix
= pCell
->GetMatrixOrigin(rDoc
, aMatOrigin
);
2021 CPPUNIT_ASSERT_MESSAGE("Not a part of matrix formula.", bIsMatrix
);
2022 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong matrix origin.", aMatRange
.aStart
, aMatOrigin
);
2028 CPPUNIT_TEST_FIXTURE(ScExportTest
, testInlineArrayXLS
)
2030 createScDoc("xls/inline-array.xls");
2032 saveAndReload("MS Excel 97");
2034 ScDocument
* pDoc
= getScDoc();
2036 // B2:C3 contains a matrix.
2037 checkMatrixRange(*pDoc
, ScRange(1, 1, 0, 2, 2, 0));
2039 // B5:D6 contains a matrix.
2040 checkMatrixRange(*pDoc
, ScRange(1, 4, 0, 3, 5, 0));
2043 checkMatrixRange(*pDoc
, ScRange(1, 7, 0, 2, 9, 0));
2046 CPPUNIT_TEST_FIXTURE(ScExportTest
, testEmbeddedChartODS
)
2048 createScDoc("xls/embedded-chart.xls");
2052 xmlDocUniquePtr pDoc
= parseExport("content.xml");
2053 CPPUNIT_ASSERT(pDoc
);
2055 "/office:document-content/office:body/office:spreadsheet/table:table[2]/"
2056 "table:table-row[7]/table:table-cell[2]/draw:frame/draw:object"_ostr
,
2057 "notify-on-update-of-ranges"_ostr
,
2058 "Chart1.B3:Chart1.B5 Chart1.C2:Chart1.C2 Chart1.C3:Chart1.C5");
2061 CPPUNIT_TEST_FIXTURE(ScExportTest
, testEmbeddedChartXLS
)
2063 createScDoc("xls/embedded-chart.xls");
2065 saveAndReload("MS Excel 97");
2067 ScDocument
* pDoc
= getScDoc();
2069 // Make sure the 2nd sheet is named 'Chart1'.
2071 pDoc
->GetName(1, aName
);
2072 CPPUNIT_ASSERT_EQUAL(OUString("Chart1"), aName
);
2074 const SdrOle2Obj
* pOleObj
= getSingleChartObject(*pDoc
, 1);
2075 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve a chart object from the 2nd sheet.", pOleObj
);
2077 ScRangeList aRanges
= getChartRanges(*pDoc
, *pOleObj
);
2078 CPPUNIT_ASSERT_MESSAGE("Label range (B3:B5) not found.",
2079 aRanges
.Contains(ScRange(1, 2, 1, 1, 4, 1)));
2080 CPPUNIT_ASSERT_MESSAGE("Data label (C2) not found.", aRanges
.Contains(ScAddress(2, 1, 1)));
2081 CPPUNIT_ASSERT_MESSAGE("Data range (C3:C5) not found.",
2082 aRanges
.Contains(ScRange(2, 2, 1, 2, 4, 1)));
2085 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCellAnchoredGroupXLS
)
2087 createScDoc("xls/cell-anchored-group.xls");
2089 saveAndReload("calc8");
2091 // the document contains a group anchored on the first cell, make sure it's there in the right place
2092 ScDocument
* pDoc
= getScDoc();
2093 CPPUNIT_ASSERT_MESSAGE("There should be at least one sheet.", pDoc
->GetTableCount() > 0);
2094 ScDrawLayer
* pDrawLayer
= pDoc
->GetDrawLayer();
2095 SdrPage
* pPage
= pDrawLayer
->GetPage(0);
2096 CPPUNIT_ASSERT_MESSAGE("draw page for sheet 1 should exist.", pPage
);
2097 const size_t nCount
= pPage
->GetObjCount();
2098 CPPUNIT_ASSERT_EQUAL_MESSAGE("There should be 1 objects.", static_cast<size_t>(1), nCount
);
2100 SdrObject
* pObj
= pPage
->GetObj(0);
2101 CPPUNIT_ASSERT_MESSAGE("Failed to get drawing object.", pObj
);
2102 ScDrawObjData
* pData
= ScDrawLayer::GetObjData(pObj
);
2103 CPPUNIT_ASSERT_MESSAGE("Failed to retrieve user data for this object.", pData
);
2104 CPPUNIT_ASSERT_MESSAGE("Upper left of bounding rectangle should be nonnegative.",
2105 pData
->getShapeRect().Left() >= 0 || pData
->getShapeRect().Top() >= 0);
2108 CPPUNIT_TEST_FIXTURE(ScExportTest
, testFormulaReferenceXLS
)
2110 createScDoc("xls/formula-reference.xls");
2112 saveAndReload("MS Excel 97");
2114 ScDocument
* pDoc
= getScDoc();
2116 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D2", OUString("=$A$2+$B$2+$C$2"),
2117 pDoc
->GetFormula(3, 1, 0));
2118 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D3", OUString("=A3+B3+C3"),
2119 pDoc
->GetFormula(3, 2, 0));
2120 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D6", OUString("=SUM($A$6:$C$6)"),
2121 pDoc
->GetFormula(3, 5, 0));
2122 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D7", OUString("=SUM(A7:C7)"),
2123 pDoc
->GetFormula(3, 6, 0));
2124 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D10", OUString("=$Two.$A$2+$Two.$B$2+$Two.$C$2"),
2125 pDoc
->GetFormula(3, 9, 0));
2126 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D11", OUString("=$Two.A3+$Two.B3+$Two.C3"),
2127 pDoc
->GetFormula(3, 10, 0));
2128 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D14", OUString("=MIN($Two.$A$2:$C$2)"),
2129 pDoc
->GetFormula(3, 13, 0));
2130 CPPUNIT_ASSERT_EQUAL_MESSAGE("Wrong formula in D15", OUString("=MAX($Two.A3:C3)"),
2131 pDoc
->GetFormula(3, 14, 0));
2134 CPPUNIT_TEST_FIXTURE(ScExportTest
, testSheetProtectionXLSX
)
2136 createScDoc("xlsx/ProtecteSheet1234Pass.xlsx");
2138 saveAndReload("Calc Office Open XML");
2140 ScDocument
* pDoc
= getScDoc();
2141 const ScTableProtection
* pTabProtect
= pDoc
->GetTabProtection(0);
2142 CPPUNIT_ASSERT(pTabProtect
);
2143 Sequence
<sal_Int8
> aHash
= pTabProtect
->getPasswordHash(PASSHASH_XL
);
2145 if (aHash
.getLength() >= 2)
2147 CPPUNIT_ASSERT_EQUAL(sal_uInt8(204), static_cast<sal_uInt8
>(aHash
[0]));
2148 CPPUNIT_ASSERT_EQUAL(sal_uInt8(61), static_cast<sal_uInt8
>(aHash
[1]));
2150 // we could flesh out this check I guess
2151 CPPUNIT_ASSERT(!pTabProtect
->isOptionEnabled(ScTableProtection::OBJECTS
));
2152 CPPUNIT_ASSERT(!pTabProtect
->isOptionEnabled(ScTableProtection::SCENARIOS
));
2155 CPPUNIT_TEST_FIXTURE(ScExportTest
, testSheetProtectionXLSB
)
2157 createScDoc("xlsb/tdf108017_calcProtection.xlsb");
2159 saveAndReload("Calc Office Open XML");
2161 ScDocument
* pDoc
= getScDoc();
2162 const ScTableProtection
* pTabProtect
= pDoc
->GetTabProtection(0);
2163 CPPUNIT_ASSERT(pTabProtect
);
2164 CPPUNIT_ASSERT(pTabProtect
->isOptionEnabled(ScTableProtection::SELECT_UNLOCKED_CELLS
));
2165 CPPUNIT_ASSERT(!pTabProtect
->isOptionEnabled(ScTableProtection::SELECT_LOCKED_CELLS
));
2168 CPPUNIT_TEST_FIXTURE(ScExportTest
, testConditionalFormatNumberInTextRule
)
2172 ScDocument
* pDocument
= getScDoc();
2173 ScAddress
aAddress(0, 0, 0);
2175 auto pFormat
= std::make_unique
<ScConditionalFormat
>(0, pDocument
);
2176 ScRange
aCondFormatRange(aAddress
);
2177 ScRangeList
aRangeList(aCondFormatRange
);
2178 pFormat
->SetRange(aRangeList
);
2179 ScCondFormatEntry
* pEntry
2180 = new ScCondFormatEntry(ScConditionMode::BeginsWith
, "15", "", *pDocument
, aAddress
, "");
2181 pFormat
->AddEntry(pEntry
);
2182 pDocument
->AddCondFormat(std::move(pFormat
), 0);
2184 saveAndReload("Calc Office Open XML");
2185 pDocument
= getScDoc();
2187 ScConditionalFormat
* pCondFormat
= pDocument
->GetCondFormat(0, 0, 0);
2188 CPPUNIT_ASSERT(pCondFormat
);
2189 CPPUNIT_ASSERT_EQUAL(size_t(1), pCondFormat
->size());
2190 const ScFormatEntry
* pCondFormatEntry
= pCondFormat
->GetEntry(0);
2191 CPPUNIT_ASSERT(pCondFormatEntry
);
2192 CPPUNIT_ASSERT_EQUAL(ScFormatEntry::Type::Condition
, pCondFormatEntry
->GetType());
2193 const ScConditionEntry
* pConditionEntry
2194 = static_cast<const ScConditionEntry
*>(pCondFormatEntry
);
2195 CPPUNIT_ASSERT_EQUAL(ScConditionMode::BeginsWith
, pConditionEntry
->GetOperation());
2196 CPPUNIT_ASSERT_EQUAL(OUString("\"15\""), pConditionEntry
->GetExpression(aAddress
, 0));
2201 const char* toBorderName(SvxBorderLineStyle eStyle
)
2205 case SvxBorderLineStyle::SOLID
:
2207 case SvxBorderLineStyle::DOTTED
:
2209 case SvxBorderLineStyle::DASHED
:
2211 case SvxBorderLineStyle::DASH_DOT
:
2213 case SvxBorderLineStyle::DASH_DOT_DOT
:
2214 return "DASH_DOT_DOT";
2215 case SvxBorderLineStyle::DOUBLE_THIN
:
2216 return "DOUBLE_THIN";
2217 case SvxBorderLineStyle::FINE_DASHED
:
2218 return "FINE_DASHED";
2226 void ScExportTest::testExcelCellBorders(const OUString
& sFormatType
)
2231 SvxBorderLineStyle mnStyle
;
2232 tools::Long mnWidth
;
2234 { 1, SvxBorderLineStyle::SOLID
, 1 }, // hair
2235 { 3, SvxBorderLineStyle::DOTTED
, 15 }, // dotted
2236 { 5, SvxBorderLineStyle::DASH_DOT_DOT
, 15 }, // dash dot dot
2237 { 7, SvxBorderLineStyle::DASH_DOT
, 15 }, // dash dot
2238 { 9, SvxBorderLineStyle::FINE_DASHED
, 15 }, // dashed
2239 { 11, SvxBorderLineStyle::SOLID
, 15 }, // thin
2240 { 13, SvxBorderLineStyle::DASH_DOT_DOT
, 35 }, // medium dash dot dot
2241 { 17, SvxBorderLineStyle::DASH_DOT
, 35 }, // medium dash dot
2242 { 19, SvxBorderLineStyle::DASHED
, 35 }, // medium dashed
2243 { 21, SvxBorderLineStyle::SOLID
, 35 }, // medium
2244 { 23, SvxBorderLineStyle::SOLID
, 50 }, // thick
2245 { 25, SvxBorderLineStyle::DOUBLE_THIN
, -1 }, // double (don't check width)
2249 ScDocument
* pDoc
= getScDoc();
2251 for (auto const[nRow
, eStyle
, nWidth
] : aChecks
)
2253 const editeng::SvxBorderLine
* pLine
= nullptr;
2254 pDoc
->GetBorderLines(2, nRow
, 0, nullptr, &pLine
, nullptr, nullptr);
2255 CPPUNIT_ASSERT(pLine
);
2256 CPPUNIT_ASSERT_EQUAL(toBorderName(eStyle
), toBorderName(pLine
->GetBorderLineStyle()));
2258 CPPUNIT_ASSERT_EQUAL(nWidth
, pLine
->GetWidth());
2262 saveAndReload(sFormatType
);
2263 ScDocument
* pDoc
= getScDoc();
2264 for (auto const[nRow
, eStyle
, nWidth
] : aChecks
)
2266 const editeng::SvxBorderLine
* pLine
= nullptr;
2267 pDoc
->GetBorderLines(2, nRow
, 0, nullptr, &pLine
, nullptr, nullptr);
2268 CPPUNIT_ASSERT(pLine
);
2269 CPPUNIT_ASSERT_EQUAL(toBorderName(eStyle
), toBorderName(pLine
->GetBorderLineStyle()));
2271 CPPUNIT_ASSERT_EQUAL(nWidth
, pLine
->GetWidth());
2275 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCellBordersXLS
)
2277 createScDoc("xls/cell-borders.xls");
2278 testExcelCellBorders("MS Excel 97");
2281 CPPUNIT_TEST_FIXTURE(ScExportTest
, testCellBordersXLSX
)
2283 createScDoc("xlsx/cell-borders.xlsx");
2284 testExcelCellBorders("Calc Office Open XML");
2287 CPPUNIT_TEST_FIXTURE(ScExportTest
, testTdf155368
)
2289 createScDoc("ods/tdf155368.ods");
2291 dispatchCommand(mxComponent
, ".uno:SelectAll", {});
2293 dispatchCommand(mxComponent
, ".uno:WrapText", {});
2295 save("Calc Office Open XML");
2297 xmlDocUniquePtr pStyles
= parseExport("xl/styles.xml");
2298 CPPUNIT_ASSERT(pStyles
);
2300 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[1]/x:alignment"_ostr
, "wrapText"_ostr
,
2303 // Without the fix in place, this test would have failed with
2304 // - Expected: false
2306 assertXPath(pStyles
, "/x:styleSheet/x:cellXfs/x:xf[2]/x:alignment"_ostr
, "wrapText"_ostr
,
2310 CPPUNIT_PLUGIN_IMPLEMENT();
2312 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */