diff --git a/include/svl/zformat.hxx b/include/svl/zformat.hxx index 916a0d3004c8..b9c4101effb8 100644 --- a/include/svl/zformat.hxx +++ b/include/svl/zformat.hxx @@ -250,6 +250,7 @@ public: short GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos ) const; OUString GetDenominatorString( sal_uInt16 nNumFor ) const; + OUString GetNumeratorString( sal_uInt16 nNumFor ) const; /** If the count of string elements (substrings, ignoring [modifiers] and so on) in a subformat code nNumFor (0..3) is equal to the given number. Used by ImpSvNumberInputScan::IsNumberFormatMain() to detect a matched diff --git a/include/xmloff/xmlnumfe.hxx b/include/xmloff/xmlnumfe.hxx index 0f9d19a02331..8e47ff6dfbba 100644 --- a/include/xmloff/xmlnumfe.hxx +++ b/include/xmloff/xmlnumfe.hxx @@ -69,7 +69,7 @@ private: SAL_DLLPRIVATE void WriteScientificElement_Impl( sal_Int32 nDecimals, sal_Int32 nMinDecimals, sal_Int32 nInteger, bool bGrouping, sal_Int32 nExp, sal_Int32 nExpInterval, bool bExpSign ); SAL_DLLPRIVATE void WriteFractionElement_Impl( sal_Int32 nInteger, bool bGrouping, - sal_Int32 nNumeratorDigits, sal_Int32 nDenominatorDigits, sal_Int32 nDenominator ); + const OUString& aNumeratorString, const OUString& aDenominatorString ); SAL_DLLPRIVATE void WriteCurrencyElement_Impl( const OUString& rString, const OUString& rExt ); SAL_DLLPRIVATE void WriteBooleanElement_Impl(); diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx index ccbb8cf08e41..aaabbba53244 100644 --- a/include/xmloff/xmltoken.hxx +++ b/include/xmloff/xmltoken.hxx @@ -3259,6 +3259,8 @@ namespace xmloff { namespace token { XML_EXPONENT_INTERVAL, XML_FORCED_EXPONENT_SIGN, XML_MIN_DECIMAL_PLACES, + XML_MAX_DENOMINATOR_VALUE, + XML_MAX_NUMERATOR_DIGITS, XML_TOKEN_END }; diff --git a/svl/source/numbers/zformat.cxx b/svl/source/numbers/zformat.cxx index 0529f271979c..2f2d412ad114 100644 --- a/svl/source/numbers/zformat.cxx +++ b/svl/source/numbers/zformat.cxx @@ -2004,7 +2004,6 @@ void lcl_GetOutputStringScientific(double fNumber, sal_uInt16 nCharCount, nPrec, rFormatter.GetNumDecimalSep()[0], true ); } - OUString lcl_GetDenominatorString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nAnz) { sal_uInt16 i; @@ -2025,6 +2024,24 @@ OUString lcl_GetDenominatorString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 return aDenominatorString.makeStringAndClear(); } +OUString lcl_GetNumeratorString(const ImpSvNumberformatInfo &rInfo, sal_uInt16 nAnz) +{ + sal_Int16 i; + OUStringBuffer aNumeratorString; + for( i = 0; i < nAnz; i++ ) + { + if( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_FRAC ) + { + for( i--; i >= 0 && rInfo.nTypeArray[i] == NF_SYMBOLTYPE_DIGIT ; i-- ) + { + aNumeratorString.insert( 0, rInfo.sStrArray[i] ); + } + i = nAnz; + } + } + return aNumeratorString.makeStringAndClear(); +} + // TODO: More optimizations? void lcl_ForcedDenominator(sal_uLong &nFrac, sal_uLong &nDiv, sal_uLong nForcedDiv) { @@ -2051,6 +2068,13 @@ OUString SvNumberformat::GetDenominatorString( sal_uInt16 nNumFor ) const return lcl_GetDenominatorString( rInfo, nAnz ); } +OUString SvNumberformat::GetNumeratorString( sal_uInt16 nNumFor ) const +{ + const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); + sal_uInt16 nAnz = NumFor[nNumFor].GetCount(); + return lcl_GetNumeratorString( rInfo, nAnz ); +} + bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, OUString& rOutString) const { using namespace std; diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index 77ff93c7913b..847f61d9eecf 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -3255,6 +3255,8 @@ namespace xmloff { namespace token { TOKEN( "exponent-interval", XML_EXPONENT_INTERVAL ), TOKEN( "forced-exponent-sign", XML_FORCED_EXPONENT_SIGN ), TOKEN( "min-decimal-places", XML_MIN_DECIMAL_PLACES ), + TOKEN( "max-denominator-value", XML_MAX_DENOMINATOR_VALUE ), + TOKEN( "max-numerator-digits", XML_MAX_NUMERATOR_DIGITS ), #if OSL_DEBUG_LEVEL > 0 { 0, nullptr, nullptr, XML_TOKEN_END } diff --git a/xmloff/source/style/xmlnumfe.cxx b/xmloff/source/style/xmlnumfe.cxx index 229237c2c309..235920df5fe8 100644 --- a/xmloff/source/style/xmlnumfe.cxx +++ b/xmloff/source/style/xmlnumfe.cxx @@ -721,9 +721,22 @@ void SvXMLNumFmtExport::WriteScientificElement_Impl( void SvXMLNumFmtExport::WriteFractionElement_Impl( sal_Int32 nInteger, bool bGrouping, - sal_Int32 nNumeratorDigits, sal_Int32 nDenominatorDigits, sal_Int32 nDenominator ) + const OUString& aNumeratorString , const OUString& aDenominatorString ) { FinishTextElement_Impl(); + sal_Int32 nMaxNumeratorDigits = aNumeratorString.getLength(); + sal_Int32 nMinNumeratorDigits = aNumeratorString.indexOf('?'); + if ( nMinNumeratorDigits >= 0 ) + nMinNumeratorDigits = nMaxNumeratorDigits - nMinNumeratorDigits; + else + nMinNumeratorDigits = 0; + sal_Int32 nMaxDenominatorDigits = aDenominatorString.getLength(); + sal_Int32 nMinDenominatorDigits = aDenominatorString.indexOf('?'); + if ( nMinDenominatorDigits >= 0 ) + nMinDenominatorDigits = nMaxDenominatorDigits - nMinDenominatorDigits; + else + nMinDenominatorDigits = 0; + sal_Int32 nDenominator = aDenominatorString.toInt32(); // integer digits if ( nInteger >= 0 ) // negative = default (no integer part) @@ -739,10 +752,17 @@ void SvXMLNumFmtExport::WriteFractionElement_Impl( } // numerator digits - if ( nNumeratorDigits >= 0 ) + if ( nMinNumeratorDigits == 0 ) // at least one digit to keep compatibility with previous versions + nMinNumeratorDigits++; + rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, + OUString::number( nMinNumeratorDigits ) ); + // Export only for 1.2 with extensions or 1.3 and later. + SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion(); + if ((eVersion & SvtSaveOptions::ODFSVER_EXTENDED) != 0) { - rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, - OUString::number( nNumeratorDigits ) ); + // For extended ODF use loext namespace + rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_MAX_NUMERATOR_DIGITS, + OUString::number( nMaxNumeratorDigits ) ); } if ( nDenominator ) @@ -750,12 +770,22 @@ void SvXMLNumFmtExport::WriteFractionElement_Impl( rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_DENOMINATOR_VALUE, OUString::number( nDenominator) ); } - // I guess it's not necessary to export nDenominatorDigits - // if we have a forced denominator ( remove ? ) - if ( nDenominatorDigits >= 0 ) + // it's not necessary to export nDenominatorDigits + // if we have a forced denominator + else { + if ( nMinDenominatorDigits == 0 ) // at least one digit to keep compatibility with previous versions + nMinDenominatorDigits++; rExport.AddAttribute( XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, - OUString::number( nDenominatorDigits ) ); + OUString::number( nMinDenominatorDigits ) ); + if (eVersion > SvtSaveOptions::ODFSVER_012) + { + // For 1.2+ use loext namespace, for 1.3 use number namespace. + rExport.AddAttribute( + ((eVersion < SvtSaveOptions::ODFSVER_013) ? XML_NAMESPACE_LO_EXT : XML_NAMESPACE_NUMBER), + XML_MAX_DENOMINATOR_VALUE, + OUString::number( pow ( 10.0, nMaxDenominatorDigits ) - 1 ) ); // 9, 99 or 999 + } } SvXMLElementExport aElem( rExport, XML_NAMESPACE_NUMBER, XML_FRACTION, @@ -1486,10 +1516,7 @@ void SvXMLNumFmtExport::ExportPart_Impl( const SvNumberformat& rFormat, sal_uInt // min-integer-digits attribute must be written. nInteger = -1; } - OUString aDenominatorString = rFormat.GetDenominatorString( nPart ); - sal_Int32 nDenominator = aDenominatorString.toInt32(); - sal_Int32 nDenominatorLength = aDenominatorString.getLength(); - WriteFractionElement_Impl( nInteger, bThousand, nPrecision, nDenominatorLength, nDenominator ); + WriteFractionElement_Impl( nInteger, bThousand, rFormat.GetNumeratorString( nPart ), rFormat.GetDenominatorString( nPart ) ); bAnyContent = true; } break; diff --git a/xmloff/source/style/xmlnumfi.cxx b/xmloff/source/style/xmlnumfi.cxx index ddd925cc4f3f..b85bb1312e49 100644 --- a/xmloff/source/style/xmlnumfi.cxx +++ b/xmloff/source/style/xmlnumfi.cxx @@ -95,8 +95,10 @@ struct SvXMLNumberInfo sal_Int32 nInteger; sal_Int32 nExpDigits; sal_Int32 nExpInterval; - sal_Int32 nNumerDigits; - sal_Int32 nDenomDigits; + sal_Int32 nMinNumerDigits; + sal_Int32 nMinDenomDigits; + sal_Int32 nMaxNumerDigits; + sal_Int32 nMaxDenomDigits; sal_Int32 nFracDenominator; sal_Int32 nMinDecimalDigits; bool bGrouping; @@ -108,7 +110,7 @@ struct SvXMLNumberInfo SvXMLNumberInfo() { - nDecimals = nInteger = nExpDigits = nExpInterval = nNumerDigits = nDenomDigits = + nDecimals = nInteger = nExpDigits = nExpInterval = nMinNumerDigits = nMinDenomDigits = nMaxNumerDigits = nMaxDenomDigits = nFracDenominator = nMinDecimalDigits = -1; bGrouping = bDecReplace = bDecAlign = false; bExpSign = true; @@ -262,6 +264,8 @@ enum SvXMLStyleElemAttrTokens XML_TOK_ELEM_ATTR_FORCED_EXPONENT_SIGN, XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS, + XML_TOK_ELEM_ATTR_MAX_NUMERATOR_DIGITS, + XML_TOK_ELEM_ATTR_MAX_DENOMINATOR_VALUE, XML_TOK_ELEM_ATTR_RFC_LANGUAGE_TAG, XML_TOK_ELEM_ATTR_LANGUAGE, XML_TOK_ELEM_ATTR_SCRIPT, @@ -562,6 +566,9 @@ const SvXMLTokenMap& SvXMLNumImpData::GetStyleElemAttrTokenMap() { XML_NAMESPACE_NUMBER, XML_FORCED_EXPONENT_SIGN, XML_TOK_ELEM_ATTR_FORCED_EXPONENT_SIGN }, { XML_NAMESPACE_NUMBER, XML_MIN_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS }, { XML_NAMESPACE_NUMBER, XML_MIN_DENOMINATOR_DIGITS, XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS }, + { XML_NAMESPACE_LO_EXT, XML_MAX_NUMERATOR_DIGITS, XML_TOK_ELEM_ATTR_MAX_NUMERATOR_DIGITS }, + { XML_NAMESPACE_LO_EXT, XML_MAX_DENOMINATOR_VALUE, XML_TOK_ELEM_ATTR_MAX_DENOMINATOR_VALUE }, + { XML_NAMESPACE_NUMBER, XML_MAX_DENOMINATOR_VALUE, XML_TOK_ELEM_ATTR_MAX_DENOMINATOR_VALUE }, { XML_NAMESPACE_NUMBER, XML_RFC_LANGUAGE_TAG, XML_TOK_ELEM_ATTR_RFC_LANGUAGE_TAG }, { XML_NAMESPACE_NUMBER, XML_LANGUAGE, XML_TOK_ELEM_ATTR_LANGUAGE }, { XML_NAMESPACE_NUMBER, XML_SCRIPT, XML_TOK_ELEM_ATTR_SCRIPT }, @@ -906,6 +913,7 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, sal_Int32 nAttrVal; bool bAttrBool(false); bool bVarDecimals = false; + bool bIsMaxDenominator = false; sal_uInt16 nAttrEnum; double fAttrDouble; @@ -967,17 +975,31 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, aNumInfo.bExpSign = bAttrBool; break; case XML_TOK_ELEM_ATTR_MIN_NUMERATOR_DIGITS: - if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 )) // at least one '?' (tdf#38097) - aNumInfo.nNumerDigits = nAttrVal; + if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) + aNumInfo.nMinNumerDigits = nAttrVal; break; - case XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS: // while max-denominator-digits not treated (tdf#99661) - if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 )) // at least one '?' (tdf#38097) - aNumInfo.nDenomDigits = nAttrVal; + case XML_TOK_ELEM_ATTR_MIN_DENOMINATOR_DIGITS: + if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) + aNumInfo.nMinDenomDigits = nAttrVal; + break; + case XML_TOK_ELEM_ATTR_MAX_NUMERATOR_DIGITS: + if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 )) // at least one '#' + aNumInfo.nMaxNumerDigits = nAttrVal; break; case XML_TOK_ELEM_ATTR_DENOMINATOR_VALUE: - if (::sax::Converter::convertNumber( nAttrVal, sValue, 0 )) + if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 )) // 0 is not valid + { aNumInfo.nFracDenominator = nAttrVal; + bIsMaxDenominator = false; + } break; + case XML_TOK_ELEM_ATTR_MAX_DENOMINATOR_VALUE: // part of ODF 1.3 + if (::sax::Converter::convertNumber( nAttrVal, sValue, 1 ) && aNumInfo.nFracDenominator <= 0) + { // if denominator value not yet defined + aNumInfo.nFracDenominator = nAttrVal; + bIsMaxDenominator = true; + } + break; case XML_TOK_ELEM_ATTR_RFC_LANGUAGE_TAG: aLanguageTagODF.maRfcLanguageTag = sValue; break; @@ -1010,6 +1032,24 @@ SvXMLNumFmtElementContext::SvXMLNumFmtElementContext( SvXMLImport& rImport, else aNumInfo.nMinDecimalDigits = aNumInfo.nDecimals; } + if ( aNumInfo.nMinDenomDigits >= 0 ) + if ( aNumInfo.nMaxDenomDigits < aNumInfo.nMinDenomDigits ) + aNumInfo.nMaxDenomDigits = ( aNumInfo.nMinDenomDigits ? aNumInfo.nMinDenomDigits : 1 ); + if ( aNumInfo.nMinNumerDigits >= 0 ) + if ( aNumInfo.nMaxNumerDigits < aNumInfo.nMinNumerDigits ) + aNumInfo.nMaxNumerDigits = ( aNumInfo.nMinNumerDigits ? aNumInfo.nMinNumerDigits : 1 ); + if ( bIsMaxDenominator && aNumInfo.nFracDenominator > 0 ) + { + aNumInfo.nMaxDenomDigits = floor( log10( aNumInfo.nFracDenominator ) ) + 1; + aNumInfo.nFracDenominator = -1; // Max denominator value only gives number of digits at denominator + } + if ( aNumInfo.nMaxDenomDigits > 0 ) + { + if ( aNumInfo.nMinDenomDigits < 0 ) + aNumInfo.nMinDenomDigits = 0; + else if ( aNumInfo.nMinDenomDigits > aNumInfo.nMaxDenomDigits ) + aNumInfo.nMinDenomDigits = aNumInfo.nMaxDenomDigits; + } if ( !aLanguageTagODF.isEmpty() ) { @@ -1206,9 +1246,12 @@ void SvXMLNumFmtElementContext::EndElement() //! build string and add at once sal_Int32 i; - for (i=0; i 0; i--) { - rParent.AddToCode( '?' ); + if ( i > aNumInfo.nMinNumerDigits ) + rParent.AddToCode( '#' ); + else + rParent.AddToCode( '?' ); } rParent.AddToCode( '/' ); if ( aNumInfo.nFracDenominator > 0 ) @@ -1217,9 +1260,12 @@ void SvXMLNumFmtElementContext::EndElement() } else { - for (i=0; i 0 ; i--) { - rParent.AddToCode( '?'); + if ( i > aNumInfo.nMinDenomDigits ) + rParent.AddToCode( '#' ); + else + rParent.AddToCode( '?' ); } } }