diff options
author | Eike Rathke <erack@redhat.com> | 2014-03-31 19:28:31 +0200 |
---|---|---|
committer | Andras Timar <andras.timar@collabora.com> | 2014-04-13 12:16:05 +0200 |
commit | 47ac8726523a75eac3f119a7dae4a831c33a5c02 (patch) | |
tree | 3846a4205431302b242c21e4d3614294951a8d76 /sc/source/core/data/column3.cxx | |
parent | 53c0160e3b57157f55a170f32332add6877ab184 (diff) |
re-enabled user-defined numeric fields for dBase export
Since commit f59e350d1733125055f1144f8b3b1b0a46f6d1ca it was impossible
to define a numeric field with a precision of less than 2 decimals, even
if all values were integers. It was also impossible to define a field
width larger than needed for any values in that column. Furthermore, the
integer part was shortened if the overall column's values resulted in
more precision than defined, but the overall length did not reach the
predefined length.
This does not change the behavior of the original intention of
f59e350d1733125055f1144f8b3b1b0a46f6d1ca to give the precision of number
formats precedence over precision defined in the column header, which is
debatable though because conflicts may silently change the field
definition.
(cherry picked from commit e65141e93a540fc9fb4343ee65a5a7da7e3b1769)
Plus comment translation.
Conflicts:
sc/source/core/data/column3.cxx
sc/source/ui/docshell/docsh8.cxx
Backported.
Change-Id: I234c4bceaa1a6aadbd259cb8d9b6cb6f16bf91c2
Reviewed-on: https://gerrit.libreoffice.org/8809
Reviewed-by: Kohei Yoshida <libreoffice@kohei.us>
Tested-by: Kohei Yoshida <libreoffice@kohei.us>
Diffstat (limited to 'sc/source/core/data/column3.cxx')
-rw-r--r-- | sc/source/core/data/column3.cxx | 100 |
1 files changed, 85 insertions, 15 deletions
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx index 4bd6a5a99d43..3630be3e2239 100644 --- a/sc/source/core/data/column3.cxx +++ b/sc/source/core/data/column3.cxx @@ -1906,15 +1906,19 @@ xub_StrLen ScColumn::GetMaxNumberStringLen( sal_uInt16& nPrecision, SCROW nRowStart, SCROW nRowEnd ) const { xub_StrLen nStringLen = 0; - nPrecision = pDocument->GetDocOptions().GetStdPrecision(); - if ( nPrecision == SvNumberFormatter::UNLIMITED_PRECISION ) - // In case of unlimited precision, use 2 instead. - nPrecision = 2; + nPrecision = 0; if ( !maItems.empty() ) { OUString aString; + String aSep; SvNumberFormatter* pNumFmt = pDocument->GetFormatTable(); + sal_uInt16 nMaxGeneralPrecision = pDocument->GetDocOptions().GetStdPrecision(); + // Limit the decimals passed to doubleToUString(). + // Also, the dBaseIII maximum precision is 15. + if (nMaxGeneralPrecision > 15) + nMaxGeneralPrecision = 15; + bool bHaveSigned = false; SCSIZE nIndex; SCROW nRow; Search( nRowStart, nIndex ); @@ -1926,16 +1930,33 @@ xub_StrLen ScColumn::GetMaxNumberStringLen( if ( eType == CELLTYPE_VALUE || (eType == CELLTYPE_FORMULA && aCell.mpFormula->IsValue()) ) { - sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr( - nRow, ATTR_VALUE_FORMAT ))->GetValue(); - ScCellFormat::GetInputString(aCell, nFormat, aString, *pNumFmt, pDocument); - xub_StrLen nLen = aString.getLength(); - if ( nLen ) + do { - if ( nFormat ) + sal_uInt16 nCellPrecision = nMaxGeneralPrecision; + if (eType == CELLTYPE_FORMULA) { + // Limit unformatted formula cell precision to precision + // encountered so far, if any, otherwise we'd end up with 15 just + // because of =1/3 ... If no precision yet then arbitrarily limit + // to a maximum of 4 unless a maximum general precision is set. + if (nPrecision) + nCellPrecision = nPrecision; + else + nCellPrecision = (nMaxGeneralPrecision >= 15) ? 4 : nMaxGeneralPrecision; + } + + double fVal = aCell.getValue(); + if (!bHaveSigned && fVal < 0.0) + bHaveSigned = true; + + sal_uInt16 nPrec; + sal_uLong nFormat = (sal_uLong) ((SfxUInt32Item*) GetAttr( + nRow, ATTR_VALUE_FORMAT ))->GetValue(); + if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) + { + aSep = pNumFmt->GetFormatDecimalSep(nFormat); + ScCellFormat::GetInputString(aCell, nFormat, aString, *pNumFmt, pDocument); const SvNumberformat* pEntry = pNumFmt->GetEntry( nFormat ); - sal_uInt16 nPrec; if (pEntry) { bool bThousand, bNegRed; @@ -1944,14 +1965,54 @@ xub_StrLen ScColumn::GetMaxNumberStringLen( } else nPrec = pNumFmt->GetFormatPrecision( nFormat ); + } + else + { + if (nPrecision >= nMaxGeneralPrecision) + break; // early bail out for nothing changes here + + if (!fVal) + { + // 0 doesn't change precision, but set a maximum length if none yet. + if (!nStringLen) + nStringLen = 1; + break; + } + + // Simple number string with at most 15 decimals and trailing + // decimal zeros eliminated. + aSep = "."; + aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true); + nPrec = SvNumberFormatter::UNLIMITED_PRECISION; + } + + sal_Int32 nLen = aString.getLength(); + if (nLen <= 0) + // Ignore empty string. + break; + + if (nPrec == SvNumberFormatter::UNLIMITED_PRECISION && nPrecision < nMaxGeneralPrecision) + { + if (nFormat % SV_COUNTRY_LANGUAGE_OFFSET) + { + // For some reason we couldn't obtain a precision from the + // format, retry with simple number string. + aSep = "."; + aString = rtl::math::doubleToUString( fVal, rtl_math_StringFormat_F, nCellPrecision, '.', true); + nLen = aString.getLength(); + } + sal_Int32 nSep = aString.indexOf( aSep); + if (nSep != -1) + nPrec = aString.getLength() - nSep - 1; - if ( nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > nPrecision ) - nPrecision = nPrec; } + + if (nPrec != SvNumberFormatter::UNLIMITED_PRECISION && nPrec > nPrecision) + nPrecision = nPrec; + if ( nPrecision ) { // less than nPrecision in string => widen it // more => shorten it - String aSep = pNumFmt->GetFormatDecimalSep( nFormat ); sal_Int32 nTmp = aString.indexOf( aSep ); if ( nTmp == -1 ) nLen += nPrecision + aSep.Len(); @@ -1964,9 +2025,18 @@ xub_StrLen ScColumn::GetMaxNumberStringLen( // nPrecision < nTmp : nLen - Diff } } + + // Enlarge for sign if necessary. Bear in mind that + // GetMaxNumberStringLen() is for determining dBase decimal field width + // and precision where the overall field width must include the sign. + // Fitting -1 into "#.##" (width 4, 2 decimals) does not work. + if (bHaveSigned && fVal >= 0.0) + ++nLen; + if ( nStringLen < nLen ) nStringLen = nLen; - } + + } while (0); } nIndex++; } |