include/xmloff/xmlnumfe.hxx | 7 include/xmloff/xmltoken.hxx | 1 sc/qa/unit/data/contentCSV/testNumberFormats.csv | 32 +++ sc/qa/unit/data/ods/testNumberFormats.ods |binary sc/qa/unit/helper/qahelper.cxx | 5 sc/qa/unit/helper/qahelper.hxx | 2 sc/qa/unit/subsequent_export_test.cxx | 31 +++ schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng | 9 + svl/source/numbers/zformat.cxx | 3 xmloff/source/core/xmltoken.cxx | 1 xmloff/source/style/xmlnumfe.cxx | 101 ++++++------ xmloff/source/style/xmlnumfi.cxx | 29 +++ xmloff/source/token/tokens.txt | 1 13 files changed, 165 insertions(+), 57 deletions(-)
New commits: commit 46b7fd59f9d0dfb5544df99494d3a3d3a372ae8b Author: Laurent Balland <laurent.ball...@mailo.fr> AuthorDate: Sat Jan 14 15:48:12 2023 +0100 Commit: Eike Rathke <er...@redhat.com> CommitDate: Mon Jan 30 17:00:46 2023 +0000 tdf#118324 Treat blank ? in integer Restore and update change 56352 Test of https://cgit.freedesktop.org/libreoffice/core/commit/?id=8ca6468f0f4900d4d3bb45e0e938fe35c308512c is now ok Add disambiguation between '0' and '?' in integer part XML_MAX_BLANK_INTEGER_DIGITS is added for the number of '?' XML_MIN_INTEGER_DIGITS is the number of '?' and '0' This preserve compatibility with previous versions: in previous versions '?' will be transformed in '0' It also applies to scientific and fraction numbers. Integer part for number, scientific and fraction are treated the same way Include QA unit test Change-Id: Iab3127bf07223caac60e409306a1bee2edc37428 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/145932 Tested-by: Jenkins Reviewed-by: Eike Rathke <er...@redhat.com> diff --git a/include/xmloff/xmlnumfe.hxx b/include/xmloff/xmlnumfe.hxx index 5d971179bbd8..61836f534245 100644 --- a/include/xmloff/xmlnumfe.hxx +++ b/include/xmloff/xmlnumfe.hxx @@ -63,13 +63,14 @@ private: SAL_DLLPRIVATE void FinishTextElement_Impl(bool bUseExtensionNS = false); SAL_DLLPRIVATE void WriteColorElement_Impl( const Color& rColor ); + SAL_DLLPRIVATE void WriteIntegerElement_Impl( sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping ); SAL_DLLPRIVATE void WriteNumberElement_Impl( sal_Int32 nDecimals, sal_Int32 nMinDecimals, - sal_Int32 nInteger, const OUString& rDashStr, + sal_Int32 nInteger, sal_Int32 nBlankInteger, const OUString& rDashStr, bool bGrouping, sal_Int32 nTrailingThousands, const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ); - SAL_DLLPRIVATE void WriteScientificElement_Impl( sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, + SAL_DLLPRIVATE void WriteScientificElement_Impl( sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign ); - SAL_DLLPRIVATE void WriteFractionElement_Impl( sal_Int32 nInteger, bool bGrouping, + SAL_DLLPRIVATE void WriteFractionElement_Impl( sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping, const SvNumberformat& rFormat, sal_uInt16 nPart ); SAL_DLLPRIVATE void WriteCurrencyElement_Impl( const OUString& rString, std::u16string_view rExt ); diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index e33a39deb449..3b45568e7d24 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -3445,6 +3445,7 @@ namespace xmloff::token { XML_ZEROS_NUMERATOR_DIGITS, XML_ZEROS_DENOMINATOR_DIGITS, XML_INTEGER_FRACTION_DELIMITER, + XML_MAX_BLANK_INTEGER_DIGITS, // tdf#115319 XML_REFERENCE_LANGUAGE, diff --git a/sc/qa/unit/data/contentCSV/testNumberFormats.csv b/sc/qa/unit/data/contentCSV/testNumberFormats.csv new file mode 100644 index 000000000000..266f4baa8a46 --- /dev/null +++ b/sc/qa/unit/data/contentCSV/testNumberFormats.csv @@ -0,0 +1,32 @@ +;Integer;;;Thousand separator;;;Fraction;;;Fraction + Thousand separator;;;Scientific;;;Engineering;; +Format;"""format=""000000";"""format=""??????";"""format=""??0000";"""format=""000,000";"""format=""???,???";"""format=""??0,000";"""format=""000 ?/?";"""format=""??? ?/?";"""format=""?00 ?/?";"""format=""0,000 ?/?";"""format=""?,??? ?/?";"""format=""?,?00 ?/?";"""format=""0.000E+00";"""format=""?.###E+00";"""format=""?.0##E+00";"""format=""000E+00";"""format=""???E+00";"""format=""?00E+00" +0.123456;format=000000;format= ;format= 0000;format=000,000;format= ;format= 0,000;format=000 1/8;format= 1/8;format= 00 1/8;format=0,000 1/8;format= 1/8;format= 00 1/8;format=1.235E-01;format=1.235E-01;format=1.235E-01;format=123E-03;format=123E-03;format=123E-03 +1.23456;format=000001;format= 1;format= 0001;format=000,001;format= 1;format= 0,001;format=001 2/9;format= 1 2/9;format= 01 2/9;format=0,001 2/9;format= 1 2/9;format= 01 2/9;format=1.235E+00;format=1.235E+00;format=1.235E+00;format=001E+00;format= 1E+00;format= 01E+00 +12.3456;format=000012;format= 12;format= 0012;format=000,012;format= 12;format= 0,012;format=012 1/3;format= 12 1/3;format= 12 1/3;format=0,012 1/3;format= 12 1/3;format= 12 1/3;format=1.235E+01;format=1.235E+01;format=1.235E+01;format=012E+00;format= 12E+00;format= 12E+00 +123.456;format=000123;format= 123;format= 0123;format=000,123;format= 123;format= 0,123;format=123 4/9;format=123 4/9;format=123 4/9;format=0,123 4/9;format= 123 4/9;format= 123 4/9;format=1.235E+02;format=1.235E+02;format=1.235E+02;format=123E+00;format=123E+00;format=123E+00 +1234.56;format=001235;format= 1235;format= 1235;format=001,235;format= 1,235;format= 1,235;format=1234 5/9;format=1234 5/9;format=1234 5/9;format=1,234 5/9;format=1,234 5/9;format=1,234 5/9;format=1.235E+03;format=1.235E+03;format=1.235E+03;format=001E+03;format= 1E+03;format= 01E+03 +12345.6;format=012346;format= 12346;format= 12346;format=012,346;format= 12,346;format= 12,346;format=12345 3/5;format=12345 3/5;format=12345 3/5;format=12,345 3/5;format=12,345 3/5;format=12,345 3/5;format=1.235E+04;format=1.235E+04;format=1.235E+04;format=012E+03;format= 12E+03;format= 12E+03 +123456;format=123456;format=123456;format=123456;format=123,456;format=123,456;format=123,456;format=123456 ;format=123456 ;format=123456 ;format=123,456 ;format=123,456 ;format=123,456 ;format=1.235E+05;format=1.235E+05;format=1.235E+05;format=123E+03;format=123E+03;format=123E+03 +1234560;format=1234560;format=1234560;format=1234560;format=1,234,560;format=1,234,560;format=1,234,560;format=1234560 ;format=1234560 ;format=1234560 ;format=1,234,560 ;format=1,234,560 ;format=1,234,560 ;format=1.235E+06;format=1.235E+06;format=1.235E+06;format=001E+06;format= 1E+06;format= 01E+06 +12345600;format=12345600;format=12345600;format=12345600;format=12,345,600;format=12,345,600;format=12,345,600;format=12345600 ;format=12345600 ;format=12345600 ;format=12,345,600 ;format=12,345,600 ;format=12,345,600 ;format=1.235E+07;format=1.235E+07;format=1.235E+07;format=012E+06;format= 12E+06;format= 12E+06 +-0.123456;format=000000;format= ;format= 0000;format=000,000;format= ;format= 0,000;-format=000 1/8;-format= 1/8;-format= 00 1/8;-format=0,000 1/8;-format= 1/8;-format= 00 1/8;-format=1.235E-01;-format=1.235E-01;-format=1.235E-01;-format=123E-03;-format=123E-03;-format=123E-03 +-1.23456;-format=000001;-format= 1;-format= 0001;-format=000,001;-format= 1;-format= 0,001;-format=001 2/9;-format= 1 2/9;-format= 01 2/9;-format=0,001 2/9;-format= 1 2/9;-format= 01 2/9;-format=1.235E+00;-format=1.235E+00;-format=1.235E+00;-format=001E+00;-format= 1E+00;-format= 01E+00 +-12.3456;-format=000012;-format= 12;-format= 0012;-format=000,012;-format= 12;-format= 0,012;-format=012 1/3;-format= 12 1/3;-format= 12 1/3;-format=0,012 1/3;-format= 12 1/3;-format= 12 1/3;-format=1.235E+01;-format=1.235E+01;-format=1.235E+01;-format=012E+00;-format= 12E+00;-format= 12E+00 +-123.456;-format=000123;-format= 123;-format= 0123;-format=000,123;-format= 123;-format= 0,123;-format=123 4/9;-format=123 4/9;-format=123 4/9;-format=0,123 4/9;-format= 123 4/9;-format= 123 4/9;-format=1.235E+02;-format=1.235E+02;-format=1.235E+02;-format=123E+00;-format=123E+00;-format=123E+00 +-1234.56;-format=001235;-format= 1235;-format= 1235;-format=001,235;-format= 1,235;-format= 1,235;-format=1234 5/9;-format=1234 5/9;-format=1234 5/9;-format=1,234 5/9;-format=1,234 5/9;-format=1,234 5/9;-format=1.235E+03;-format=1.235E+03;-format=1.235E+03;-format=001E+03;-format= 1E+03;-format= 01E+03 +-12345.6;-format=012346;-format= 12346;-format= 12346;-format=012,346;-format= 12,346;-format= 12,346;-format=12345 3/5;-format=12345 3/5;-format=12345 3/5;-format=12,345 3/5;-format=12,345 3/5;-format=12,345 3/5;-format=1.235E+04;-format=1.235E+04;-format=1.235E+04;-format=012E+03;-format= 12E+03;-format= 12E+03 +-123456;-format=123456;-format=123456;-format=123456;-format=123,456;-format=123,456;-format=123,456;-format=123456 ;-format=123456 ;-format=123456 ;-format=123,456 ;-format=123,456 ;-format=123,456 ;-format=1.235E+05;-format=1.235E+05;-format=1.235E+05;-format=123E+03;-format=123E+03;-format=123E+03 +-1234560;-format=1234560;-format=1234560;-format=1234560;-format=1,234,560;-format=1,234,560;-format=1,234,560;-format=1234560 ;-format=1234560 ;-format=1234560 ;-format=1,234,560 ;-format=1,234,560 ;-format=1,234,560 ;-format=1.235E+06;-format=1.235E+06;-format=1.235E+06;-format=001E+06;-format= 1E+06;-format= 01E+06 +-12345600;-format=12345600;-format=12345600;-format=12345600;-format=12,345,600;-format=12,345,600;-format=12,345,600;-format=12345600 ;-format=12345600 ;-format=12345600 ;-format=12,345,600 ;-format=12,345,600 ;-format=12,345,600 ;-format=1.235E+07;-format=1.235E+07;-format=1.235E+07;-format=012E+06;-format= 12E+06;-format= 12E+06 +0.2;format=000000;format= ;format= 0000;format=000,000;format= ;format= 0,000;format=000 1/5;format= 1/5;format= 00 1/5;format=0,000 1/5;format= 1/5;format= 00 1/5;format=2.000E-01;format=2E-01;format=2.0E-01;format=200E-03;format=200E-03;format=200E-03 +2;format=000002;format= 2;format= 0002;format=000,002;format= 2;format= 0,002;format=002 ;format= 2 ;format= 02 ;format=0,002 ;format= 2 ;format= 02 ;format=2.000E+00;format=2E+00;format=2.0E+00;format=002E+00;format= 2E+00;format= 02E+00 +20;format=000020;format= 20;format= 0020;format=000,020;format= 20;format= 0,020;format=020 ;format= 20 ;format= 20 ;format=0,020 ;format= 20 ;format= 20 ;format=2.000E+01;format=2E+01;format=2.0E+01;format=020E+00;format= 20E+00;format= 20E+00 +200;format=000200;format= 200;format= 0200;format=000,200;format= 200;format= 0,200;format=200 ;format=200 ;format=200 ;format=0,200 ;format= 200 ;format= 200 ;format=2.000E+02;format=2E+02;format=2.0E+02;format=200E+00;format=200E+00;format=200E+00 +2000;format=002000;format= 2000;format= 2000;format=002,000;format= 2,000;format= 2,000;format=2000 ;format=2000 ;format=2000 ;format=2,000 ;format=2,000 ;format=2,000 ;format=2.000E+03;format=2E+03;format=2.0E+03;format=002E+03;format= 2E+03;format= 02E+03 +20000;format=020000;format= 20000;format= 20000;format=020,000;format= 20,000;format= 20,000;format=20000 ;format=20000 ;format=20000 ;format=20,000 ;format=20,000 ;format=20,000 ;format=2.000E+04;format=2E+04;format=2.0E+04;format=020E+03;format= 20E+03;format= 20E+03 +200000;format=200000;format=200000;format=200000;format=200,000;format=200,000;format=200,000;format=200000 ;format=200000 ;format=200000 ;format=200,000 ;format=200,000 ;format=200,000 ;format=2.000E+05;format=2E+05;format=2.0E+05;format=200E+03;format=200E+03;format=200E+03 +2000000;format=2000000;format=2000000;format=2000000;format=2,000,000;format=2,000,000;format=2,000,000;format=2000000 ;format=2000000 ;format=2000000 ;format=2,000,000 ;format=2,000,000 ;format=2,000,000 ;format=2.000E+06;format=2E+06;format=2.0E+06;format=002E+06;format= 2E+06;format= 02E+06 +20000000;format=20000000;format=20000000;format=20000000;format=20,000,000;format=20,000,000;format=20,000,000;format=20000000 ;format=20000000 ;format=20000000 ;format=20,000,000 ;format=20,000,000 ;format=20,000,000 ;format=2.000E+07;format=2E+07;format=2.0E+07;format=020E+06;format= 20E+06;format= 20E+06 +200000000;format=200000000;format=200000000;format=200000000;format=200,000,000;format=200,000,000;format=200,000,000;format=200000000 ;format=200000000 ;format=200000000 ;format=200,000,000 ;format=200,000,000 ;format=200,000,000 ;format=2.000E+08;format=2E+08;format=2.0E+08;format=200E+06;format=200E+06;format=200E+06 +;;;;;;;;;;;;;;;;;; +0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18 diff --git a/sc/qa/unit/data/ods/testNumberFormats.ods b/sc/qa/unit/data/ods/testNumberFormats.ods new file mode 100644 index 000000000000..aa2f073c27ee Binary files /dev/null and b/sc/qa/unit/data/ods/testNumberFormats.ods differ diff --git a/sc/qa/unit/helper/qahelper.cxx b/sc/qa/unit/helper/qahelper.cxx index c928af32ed4b..e132b5dd7bb5 100644 --- a/sc/qa/unit/helper/qahelper.cxx +++ b/sc/qa/unit/helper/qahelper.cxx @@ -133,11 +133,12 @@ void ScModelTestBase::testFile(const OUString& aFileName, ScDocument& rDoc, SCTA } } -void ScModelTestBase::testCondFile(const OUString& aFileName, ScDocument* pDoc, SCTAB nTab) +void ScModelTestBase::testCondFile( const OUString& aFileName, ScDocument* pDoc, SCTAB nTab, bool bCommaAsDelimiter ) { conditional_format_handler aHandler(pDoc, nTab); orcus::csv::parser_config aConfig; - aConfig.delimiters.push_back(','); + if ( bCommaAsDelimiter ) + aConfig.delimiters.push_back(','); aConfig.delimiters.push_back(';'); aConfig.text_qualifier = '"'; std::string aContent; diff --git a/sc/qa/unit/helper/qahelper.hxx b/sc/qa/unit/helper/qahelper.hxx index 67d58897ef2a..f632d57bdbbb 100644 --- a/sc/qa/unit/helper/qahelper.hxx +++ b/sc/qa/unit/helper/qahelper.hxx @@ -163,7 +163,7 @@ public: void testFile(const OUString& aFileName, ScDocument& rDoc, SCTAB nTab, StringType aStringFormat = StringType::StringValue); //need own handler because conditional formatting strings must be generated - void testCondFile(const OUString& aFileName, ScDocument* pDoc, SCTAB nTab); + void testCondFile(const OUString& aFileName, ScDocument* pDoc, SCTAB nTab, bool bCommaAsDelimiter = true); const SdrOle2Obj* getSingleOleObject(ScDocument& rDoc, sal_uInt16 nPage); diff --git a/sc/qa/unit/subsequent_export_test.cxx b/sc/qa/unit/subsequent_export_test.cxx index 5b66ae23f3d9..aefd1a8eda48 100644 --- a/sc/qa/unit/subsequent_export_test.cxx +++ b/sc/qa/unit/subsequent_export_test.cxx @@ -30,6 +30,8 @@ #include <svx/svdpage.hxx> #include <svx/svdograf.hxx> +#include <svl/zformat.hxx> +#include <svl/numformat.hxx> #include <tabprotection.hxx> #include <editeng/wghtitem.hxx> #include <editeng/postitem.hxx> @@ -183,6 +185,7 @@ public: void testPreserveTextWhitespace2XLSX(); void testTdf113646(); void testDateStandardfilterXLSX(); + void testNumberFormatODS(); CPPUNIT_TEST_SUITE(ScExportTest); CPPUNIT_TEST(test); @@ -290,6 +293,7 @@ public: CPPUNIT_TEST(testMoveCellAnchoredShapesODS); CPPUNIT_TEST(testTdf113646); CPPUNIT_TEST(testDateStandardfilterXLSX); + CPPUNIT_TEST(testNumberFormatODS); CPPUNIT_TEST_SUITE_END(); private: @@ -4305,6 +4309,33 @@ void ScExportTest::testDateStandardfilterXLSX() "dateTimeGrouping", "day"); } +void ScExportTest::testNumberFormatODS() +{ + createScDoc("ods/testNumberFormats.ods"); + saveAndReload("calc8"); + ScDocument* pDoc = getScDoc(); + sal_uInt32 nNumberFormat; + const sal_Int32 nCountFormats = 18; + const OUString aExpectedFormatStr[nCountFormats] + = { "\"format=\"000000", "\"format=\"??????", "\"format=\"??0000", + "\"format=\"000,000", "\"format=\"???,???", "\"format=\"??0,000", + "\"format=\"000\" \"?/?", "\"format=\"???\" \"?/?", "\"format=\"?00\" \"?/?", + "\"format=\"0,000\" \"?/?", "\"format=\"?,???\" \"?/?", "\"format=\"?,?00\" \"?/?", + "\"format=\"0.000E+00", "\"format=\"?.###E+00", "\"format=\"?.0##E+00", + "\"format=\"000E+00", "\"format=\"???E+00", "\"format=\"?00E+00" }; + for (sal_Int32 i = 0; i < nCountFormats; i++) + { + nNumberFormat = pDoc->GetNumberFormat(i + 1, 2, 0); + const SvNumberformat* pNumberFormat = pDoc->GetFormatTable()->GetEntry(nNumberFormat); + const OUString& rFormatStr = pNumberFormat->GetFormatstring(); + CPPUNIT_ASSERT_EQUAL_MESSAGE("Number format modified during export/import", + aExpectedFormatStr[i], rFormatStr); + } + OUString aCSVPath = createFilePath(u"contentCSV/testNumberFormats.csv"); + testCondFile(aCSVPath, &*pDoc, 0, + false); // comma is thousand separator and cannot be used as delimiter +} + CPPUNIT_TEST_SUITE_REGISTRATION(ScExportTest); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng index 98e6015ad23f..e6510e6c0d7a 100644 --- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng +++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng @@ -2633,6 +2633,15 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1. </rng:optional> </rng:define> + <rng:define name="common-number-attlist" combine="interleave"> + <!-- TODO no proposal, --> + <rng:optional> + <rng:attribute name="loext:max-blank-integer-digits"> + <rng:ref name="positiveInteger"/> + </rng:attribute> + </rng:optional> + </rng:define> + <!-- TODO no proposal --> <rng:define name="table-data-pilot-level-attlist" combine="interleave"> <rng:optional> diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx index eb790ee425b0..effb34ad996f 100644 --- a/svl/source/numbers/zformat.cxx +++ b/svl/source/numbers/zformat.cxx @@ -4947,9 +4947,10 @@ void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, SvNumFormatType& rScanne { p++; } - while ( *p++ == '0' ) + while ( *p == '0' || *p == '?' ) { nLeadingCnt++; + p++; } } else if (nType == NF_SYMBOLTYPE_DECSEP diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index d1d2047a50b9..78ef34951013 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -3450,6 +3450,7 @@ namespace xmloff::token { TOKEN( "zeros-numerator-digits", XML_ZEROS_NUMERATOR_DIGITS ), TOKEN( "zeros-denominator-digits", XML_ZEROS_DENOMINATOR_DIGITS ), TOKEN( "integer-fraction-delimiter", XML_INTEGER_FRACTION_DELIMITER ), + TOKEN( "max-blank-integer-digits", XML_MAX_BLANK_INTEGER_DIGITS ), // for optional language-dependent reference formats TOKEN( "reference-language", XML_REFERENCE_LANGUAGE ), diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx index 01367fe12e55..7d44f43342ef 100644 --- a/xmloff/source/style/xmlnumfe.cxx +++ b/xmloff/source/style/xmlnumfe.cxx @@ -532,9 +532,32 @@ void SvXMLNumFmtExport::WriteAMPMElement_Impl() // numbers +void SvXMLNumFmtExport::WriteIntegerElement_Impl( + sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping ) +{ + // integer digits: '0' and '?' + if ( nInteger >= 0 ) // negative = automatic + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, + OUString::number( nInteger ) ); + } + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + // blank integer digits: '?' + if ( nBlankInteger > 0 && ( (eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0 ) ) + { + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_MAX_BLANK_INTEGER_DIGITS, + OUString::number( nBlankInteger ) ); + } + // (automatic) grouping separator + if ( bGrouping ) + { + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); + } +} + void SvXMLNumFmtExport::WriteNumberElement_Impl( sal_Int32 nDecimals, sal_Int32 nMinDecimals, - sal_Int32 nInteger, const OUString& rDashStr, + sal_Int32 nInteger, sal_Int32 nBlankInteger, const OUString& rDashStr, bool bGrouping, sal_Int32 nTrailingThousands, const SvXMLEmbeddedTextEntryArr& rEmbeddedEntries ) { @@ -547,10 +570,10 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( OUString::number( nDecimals ) ); } + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); if ( nMinDecimals >= 0 ) // negative = automatic { // Export only for 1.2 with extensions or 1.3 and later. - SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); if (eVersion > SvtSaveOptions::ODFSVER_012) { // OFFICE-3860 For 1.2+ use loext namespace, for 1.3 use number namespace. @@ -560,14 +583,6 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( OUString::number( nMinDecimals ) ); } } - - // integer digits - if ( nInteger >= 0 ) // negative = automatic - { - rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, - OUString::number( nInteger ) ); - } - // decimal replacement (dashes) or variable decimals (#) if ( !rDashStr.isEmpty() || nMinDecimals < nDecimals ) { @@ -576,11 +591,7 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( rDashStr ); } - // (automatic) grouping separator - if ( bGrouping ) - { - rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); - } + WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping ); // display-factor if there are trailing thousands separators if ( nTrailingThousands ) @@ -626,7 +637,7 @@ void SvXMLNumFmtExport::WriteNumberElement_Impl( } void SvXMLNumFmtExport::WriteScientificElement_Impl( - sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, + sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign ) { FinishTextElement_Impl(); @@ -652,18 +663,7 @@ void SvXMLNumFmtExport::WriteScientificElement_Impl( } } - // integer digits - if ( nInteger >= 0 ) // negative = automatic - { - rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, - OUString::number( nInteger ) ); - } - - // (automatic) grouping separator - if ( bGrouping ) - { - rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); - } + WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping ); // exponent digits if ( nExp >= 0 ) @@ -702,10 +702,12 @@ void SvXMLNumFmtExport::WriteScientificElement_Impl( } void SvXMLNumFmtExport::WriteFractionElement_Impl( - sal_Int32 nInteger, bool bGrouping, + sal_Int32 nInteger, sal_Int32 nBlankInteger, bool bGrouping, const SvNumberformat& rFormat, sal_uInt16 nPart ) { FinishTextElement_Impl(); + WriteIntegerElement_Impl( nInteger, nBlankInteger, bGrouping ); + const OUString aNumeratorString = rFormat.GetNumeratorString( nPart ); const OUString aDenominatorString = rFormat.GetDenominatorString( nPart ); const OUString aIntegerFractionDelimiterString = rFormat.GetIntegerFractionDelimiterString( nPart ); @@ -734,21 +736,9 @@ void SvXMLNumFmtExport::WriteFractionElement_Impl( nZerosDenominatorDigits = 0; sal_Int32 nDenominator = aDenominatorString.toInt32(); - // integer digits - if ( nInteger >= 0 ) // negative = default (no integer part) - { - rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_INTEGER_DIGITS, - OUString::number( nInteger ) ); - } - - // (automatic) grouping separator - if ( bGrouping ) - { - rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_GROUPING, XML_TRUE ); - } + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); // integer/fraction delimiter - SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); if ( !aIntegerFractionDelimiterString.isEmpty() && aIntegerFractionDelimiterString != " " && ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) ) { // Export only for 1.2/1.3 with extensions. @@ -1249,7 +1239,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt if ( eBuiltIn == NF_NUMBER_STANDARD ) { // default number format contains just one number element - WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries ); + WriteNumberElement_Impl( -1, -1, 1, -1, OUString(), false, 0, aEmbeddedEntries ); bAnyContent = true; } else if ( eBuiltIn == NF_BOOLEAN ) @@ -1303,6 +1293,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt sal_Int32 nIntegerSymbols = 0; // for embedded-text, including "#" sal_Int32 nTrailingThousands = 0; // thousands-separators after all digits sal_Int32 nMinDecimals = nPrecision; + sal_Int32 nBlankInteger = 0; OUString sCurrExt; OUString aCalendar; bool bImplicitOtherCalendar = false; @@ -1327,7 +1318,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt bDecDashes = true; nMinDecimals = 0; } - else if ( !bInInteger && pElemStr ) + else if ( nFmtType != SvNumFormatType::FRACTION && !bInInteger && pElemStr ) { for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- ) { @@ -1343,9 +1334,17 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt } } if ( bInInteger && pElemStr ) + { nIntegerSymbols += pElemStr->getLength(); + for ( sal_Int32 i = pElemStr->getLength()-1; i >= 0 ; i-- ) + { + if ( (*pElemStr)[i] == '?' ) + nBlankInteger ++; + } + } nTrailingThousands = 0; break; + case NF_SYMBOLTYPE_FRACBLANK: case NF_SYMBOLTYPE_DECSEP: bInInteger = false; break; @@ -1507,7 +1506,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt } break; case NF_KEY_GENERAL : - WriteNumberElement_Impl( -1, -1, 1, OUString(), false, 0, aEmbeddedEntries ); + WriteNumberElement_Impl( -1, -1, 1, -1, OUString(), false, 0, aEmbeddedEntries ); bAnyContent = true; break; case NF_KEY_CCC: @@ -1566,7 +1565,10 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt // only one built-in format has automatic integer digits sal_Int32 nInteger = nLeading; if ( eBuiltIn == NF_NUMBER_SYSTEM ) + { nInteger = -1; + nBlankInteger = -1; + } // string for decimal replacement // has to be taken from nPrecision @@ -1578,16 +1580,16 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt if (bDecAlign && nPrecision > 0) sDashStr = " "; - WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, sDashStr.makeStringAndClear(), + WriteNumberElement_Impl(nDecimals, nMinDecimals, nInteger, nBlankInteger, sDashStr.makeStringAndClear(), bThousand, nTrailingThousands, aEmbeddedEntries); bAnyContent = true; } break; case SvNumFormatType::SCIENTIFIC: - // #i43959# for scientific numbers, count all integer symbols ("0" and "#") + // #i43959# for scientific numbers, count all integer symbols ("0", "?" and "#") // as integer digits: use nIntegerSymbols instead of nLeading // nIntegerSymbols represents exponent interval (for engineering notation) - WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, bThousand, nExpDigits, nIntegerSymbols, bExpSign ); + WriteScientificElement_Impl( nPrecision, nMinDecimals, nLeading, nBlankInteger, bThousand, nExpDigits, nIntegerSymbols, bExpSign ); bAnyContent = true; break; case SvNumFormatType::FRACTION: @@ -1599,8 +1601,9 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt // the fraction doesn't have an integer part, and no // min-integer-digits attribute must be written. nInteger = -1; + nBlankInteger = -1; } - WriteFractionElement_Impl( nInteger, bThousand, rFormat, nPart ); + WriteFractionElement_Impl( nInteger, nBlankInteger, bThousand, rFormat, nPart ); bAnyContent = true; } break; diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx index 370af2bde369..7cb1b7d679ef 100644 --- a/xmloff/source/style/xmlnumfi.cxx +++ b/xmloff/source/style/xmlnumfi.cxx @@ -88,7 +88,8 @@ public: struct SvXMLNumberInfo { sal_Int32 nDecimals = -1; - sal_Int32 nInteger = -1; + sal_Int32 nInteger = -1; /// Total min number of digits in integer part ('0' + '?') + sal_Int32 nBlankInteger = -1; /// Number of '?' in integer part sal_Int32 nExpDigits = -1; sal_Int32 nExpInterval = -1; sal_Int32 nMinNumerDigits = -1; @@ -675,6 +676,11 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) aNumInfo.nInteger = nAttrVal; break; + case XML_ELEMENT(LO_EXT, XML_MAX_BLANK_INTEGER_DIGITS): + case XML_ELEMENT(NUMBER, XML_MAX_BLANK_INTEGER_DIGITS): + if (::sax::Converter::convertNumber( nAttrVal, aIter.toView(), 0 )) + aNumInfo.nBlankInteger = nAttrVal; + break; case XML_ELEMENT(NUMBER, XML_GROUPING): if (::sax::Converter::convertBool( bAttrBool, aIter.toView() )) aNumInfo.bGrouping = bAttrBool; @@ -776,6 +782,8 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, XMLOFF_WARN_UNKNOWN("xmloff", aIter); } } + if ( aNumInfo.nBlankInteger > aNumInfo.nInteger ) + aNumInfo.nInteger = aNumInfo.nBlankInteger; if ( aNumInfo.nMinDecimalDigits == -1) { if ( bVarDecimals || aNumInfo.bDecReplace ) @@ -1722,6 +1730,25 @@ void SvXMLNumFormatContext::AddNumber( const SvXMLNumberInfo& rInfo ) aNumStr.stripStart('#'); } + if ( rInfo.nBlankInteger > 0 ) + { + // Replace nBlankInteger '0' by '?' + sal_Int32 nIndex = 0; + sal_Int32 nBlanks = rInfo.nBlankInteger; + sal_Int32 nIntegerEnd = aNumStr.indexOf( pFormatter->GetNumDecimalSep() ); + if ( nIntegerEnd < 0 ) + nIntegerEnd = aNumStr.getLength(); + while ( nIndex < nIntegerEnd && nBlanks > 0 ) + { + if ( aNumStr[nIndex] == '0' ) + { + aNumStr[nIndex] = '?'; + nBlanks--; + } + nIndex++; + } + } + if ( bGrouping && rInfo.nExpInterval > rInfo.nInteger ) { sal_Int32 nIndex = 0; diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt index e4a0a5fe7c36..74a725d91b30 100644 --- a/xmloff/source/token/tokens.txt +++ b/xmloff/source/token/tokens.txt @@ -3206,6 +3206,7 @@ max-numerator-digits zeros-numerator-digits zeros-denominator-digits integer-fraction-delimiter +max-blank-integer-digits reference-language newline creator-initials