Index: sc/source/core/data/global.cxx =================================================================== --- sc/source/core/data/global.cxx (revision 277206) +++ sc/source/core/data/global.cxx (working copy) @@ -2008,3 +2008,22 @@ return pLocale; } + +namespace sc +{ + + FillSeriesData::FillSeriesData() + : eDir(FILL_TO_BOTTOM) + , eCmd(FILL_LINEAR) + , eDateCmd(FILL_DAY) + , fStart(MAXDOUBLE) + , aStart() + , fStep(1.0) + , fMax(MAXDOUBLE) + , aMax() + , bUseString(false) + { + } + +} + Index: sc/source/core/data/table2.cxx =================================================================== --- sc/source/core/data/table2.cxx (revision 277206) +++ sc/source/core/data/table2.cxx (working copy) @@ -890,7 +890,7 @@ } -double ScTable::GetValue( SCCOL nCol, SCROW nRow ) +double ScTable::GetValue( SCCOL nCol, SCROW nRow ) const { if (ValidColRow( nCol, nRow )) return aCol[nCol].GetValue( nRow ); Index: sc/source/core/data/table4.cxx =================================================================== --- sc/source/core/data/table4.cxx (revision 277206) +++ sc/source/core/data/table4.cxx (working copy) @@ -64,7 +64,6 @@ #include #include #include -#include #include "attrib.hxx" #include "patattr.hxx" @@ -81,6 +80,7 @@ #include "rangenam.hxx" #include "docpool.hxx" #include "progress.hxx" +#include "sc/valuestringparser.hxx" #include @@ -92,61 +92,6 @@ // ----------------------------------------------------------------------- -short lcl_DecompValueString( String& aValue, sal_Int32& nVal, USHORT* pMinDigits = NULL ) -{ - if ( !aValue.Len() ) - { - nVal = 0; - return 0; - } - const sal_Unicode* p = aValue.GetBuffer(); - xub_StrLen nNeg = 0; - xub_StrLen nNum = 0; - if ( p[nNum] == '-' ) - nNum = nNeg = 1; - while ( p[nNum] && CharClass::isAsciiNumeric( p[nNum] ) ) - nNum++; - - sal_Unicode cNext = p[nNum]; // 0 if at the end - sal_Unicode cLast = p[aValue.Len()-1]; - - // #i5550# If there are numbers at the beginning and the end, - // prefer the one at the beginning only if it's followed by a space. - // Otherwise, use the number at the end, to enable things like IP addresses. - if ( nNum > nNeg && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(cLast) ) ) - { // number at the beginning - nVal = aValue.Copy( 0, nNum ).ToInt32(); - // #60893# any number with a leading zero sets the minimum number of digits - if ( p[nNeg] == '0' && pMinDigits && ( nNum - nNeg > *pMinDigits ) ) - *pMinDigits = nNum - nNeg; - aValue.Erase( 0, nNum ); - return -1; - } - else - { - nNeg = 0; - xub_StrLen nEnd = nNum = aValue.Len() - 1; - while ( nNum && CharClass::isAsciiNumeric( p[nNum] ) ) - nNum--; - if ( p[nNum] == '-' ) - { - nNum--; - nNeg = 1; - } - if ( nNum < nEnd - nNeg ) - { // number at the end - nVal = aValue.Copy( nNum + 1 ).ToInt32(); - // #60893# any number with a leading zero sets the minimum number of digits - if ( p[nNum+1+nNeg] == '0' && pMinDigits && ( nEnd - nNum - nNeg > *pMinDigits ) ) - *pMinDigits = nEnd - nNum - nNeg; - aValue.Erase( nNum + 1 ); - return 1; - } - } - nVal = 0; - return 0; -} - String lcl_ValueString( sal_Int32 nValue, USHORT nMinDigits ) { if ( nMinDigits <= 1 ) @@ -197,6 +142,7 @@ { DBG_ASSERT( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: falscher Bereich" ); + using sc::ValueStringParser; rInc = 0.0; rMinDigits = 0; rListData = NULL; @@ -362,19 +308,22 @@ } else if ( nCount > 1 ) { - // pass rMinDigits to all DecompValueString calls - // -> longest number defines rMinDigits + // rMinDigits is the maximum of all MinDigits values that has + // been got from analyzed cells - sal_Int32 nVal1; - short nFlag1 = lcl_DecompValueString( aStr, nVal1, &rMinDigits ); - if ( nFlag1 ) + const ValueStringParser aValueString1(aStr); + sal_Int32 nVal1(aValueString1.GetValue()); + rMinDigits = sal::static_int_cast(aValueString1.GetMinDigits()); + if (aValueString1.HasValue()) { - sal_Int32 nVal2; GetString( nCol+nAddX, nRow+nAddY, aStr ); - short nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits ); - if ( nFlag1 == nFlag2 ) + const ValueStringParser aValueString2(aStr); + sal_Int32 nVal2(aValueString2.GetValue()); + rMinDigits = std::max(rMinDigits, + sal::static_int_cast(aValueString2.GetMinDigits())); + if (CanBeOrdered(aValueString1, aValueString2)) { - rInc = (double)nVal2 - (double)nVal1; + rInc = static_cast(nVal2) - static_cast(nVal1); nCol = sal::static_int_cast( nCol + nAddX ); nRow = sal::static_int_cast( nRow + nAddY ); BOOL bVal = TRUE; @@ -388,10 +337,13 @@ ((ScStringCell*)pCell)->GetString( aStr ); else ((ScEditCell*)pCell)->GetString( aStr ); - nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits ); - if ( nFlag1 == nFlag2 ) + const ValueStringParser aValueString(aStr); + nVal2 = aValueString.GetValue(); + rMinDigits = std::max(rMinDigits, + sal::static_int_cast(aValueString.GetMinDigits())); + if (CanBeOrdered(aValueString1, aValueString)) { - double nDiff = (double)nVal2 - (double)nVal1; + double nDiff = static_cast(nVal2) - static_cast(nVal1); if ( !::rtl::math::approxEqual( nDiff, rInc ) ) bVal = FALSE; nVal1 = nVal2; @@ -411,9 +363,9 @@ } else { - // call DecompValueString to set rMinDigits - sal_Int32 nDummy; - lcl_DecompValueString( aStr, nDummy, &rMinDigits ); + // just set rMinDigits + const ValueStringParser aValueString(aStr); + rMinDigits = aValueString.GetMinDigits(); } } } @@ -747,7 +699,8 @@ BOOL bFirst = TRUE; BOOL bGetCell = TRUE; USHORT nCellDigits = 0; - short nHeadNoneTail = 0; + bool bIsValue(false); + bool bIsPrefix(false); sal_Int32 nStringValue = 0; String aValue; ScBaseCell* pSrcCell = NULL; @@ -780,10 +733,13 @@ ((ScEditCell*)pSrcCell)->GetString( aValue ); if ( !(nScFillModeMouseModifier & KEY_MOD1) ) { - nCellDigits = 0; // look at each source cell individually - nHeadNoneTail = lcl_DecompValueString( - aValue, nStringValue, &nCellDigits ); - + // look at each source cell individually + const sc::ValueStringParser aValueString(aValue); + bIsValue = aValueString.HasValue(); + nCellDigits = aValueString.GetMinDigits(); + aValue = aValueString.GetBaseSubstring(); + nStringValue = aValueString.GetValue(); + bIsPrefix = aValueString.IsPrefix(); bIsOrdinalSuffix = aValue.Equals( ScGlobal::GetOrdinalSuffix( nStringValue)); } @@ -804,7 +760,7 @@ break; case CELLTYPE_STRING: case CELLTYPE_EDIT: - if ( nHeadNoneTail ) + if (bIsValue) { // #i48009# with the "nStringValue+(long)nDelta" expression within the // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3), @@ -812,7 +768,7 @@ sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta; String aStr; - if ( nHeadNoneTail < 0 ) + if (bIsPrefix) { aCol[nCol].Insert( static_cast(nRow), lcl_getSuffixCell( pDocument, @@ -902,16 +858,20 @@ if (!bPositive) nInc = -nInc; double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE; + sc::FillSeriesData aFillData; + aFillData.eDir = eFillDir; + aFillData.eCmd = eFillCmd; + aFillData.eDateCmd = eDateCmd; + aFillData.fStep = nInc; + aFillData.fMax = nEndVal; if (bVertical) FillSeries( static_cast(nCol), nRow1, - static_cast(nCol), nRow2, nFillCount, eFillDir, - eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, FALSE, - rProgress ); + static_cast(nCol), nRow2, nFillCount, aFillData, + nMinDigits, FALSE, rProgress ); else FillSeries( nCol1, static_cast(nRow), nCol2, - static_cast(nRow), nFillCount, eFillDir, - eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, FALSE, - rProgress ); + static_cast(nRow), nFillCount, aFillData, + nMinDigits, FALSE, rProgress ); nProgress = rProgress.GetState(); } @@ -1013,19 +973,27 @@ ((ScEditCell*)pCell)->GetString( aValue ); if ( !(nScFillModeMouseModifier & KEY_MOD1) ) { - sal_Int32 nVal; - USHORT nCellDigits = 0; // look at each source cell individually - short nFlag = lcl_DecompValueString( aValue, nVal, &nCellDigits ); - if ( nFlag < 0 ) + // look at each source cell individually + const sc::ValueStringParser aValueString(aValue); + sal_Int32 nVal(aValueString.GetValue()); + USHORT nCellDigits(sal::static_int_cast( + aValueString.GetMinDigits())); + aValue = aValueString.GetBaseSubstring(); + if (aValueString.HasValue()) { - if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal))) - aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta); + if (aValueString.IsPrefix()) + { + if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal))) + aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta); - aValue.Insert( lcl_ValueString( nVal + nDelta, nCellDigits ), 0 ); + aValue.Insert( lcl_ValueString( nVal + nDelta, nCellDigits ), 0 ); + } + else + { + aValue += lcl_ValueString( nVal + nDelta, nCellDigits ); + } } - else if ( nFlag > 0 ) - aValue += lcl_ValueString( nVal + nDelta, nCellDigits ); - } + } } break; case CELLTYPE_VALUE: @@ -1054,7 +1022,8 @@ BOOL bValueOk; double nStart; sal_Int32 nVal = 0; - short nHeadNoneTail = 0; + bool bHasValue(false); + bool bIsPrefix(false); ScBaseCell* pCell = GetCell( nCol1, nRow1 ); if ( pCell ) { @@ -1068,8 +1037,14 @@ ((ScStringCell*)pCell)->GetString( aValue ); else ((ScEditCell*)pCell)->GetString( aValue ); - nHeadNoneTail = lcl_DecompValueString( aValue, nVal ); - if ( nHeadNoneTail ) + { + const sc::ValueStringParser aValueString(aValue); + aValue = aValueString.GetBaseSubstring(); + bHasValue = aValueString.HasValue(); + bIsPrefix = aValueString.IsPrefix(); + nVal = aValueString.GetValue(); + } + if (bHasValue) nStart = (double)nVal; else nStart = 0.0; @@ -1108,9 +1083,9 @@ if (bValueOk) { - if ( nHeadNoneTail ) + if (bHasValue) { - if ( nHeadNoneTail < 0 ) + if (bIsPrefix) { if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal))) aValue = ScGlobal::GetOrdinalSuffix( (sal_Int32)nStart ); @@ -1239,17 +1214,18 @@ rVal = aDate - aNullDate; } -void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, - ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, - double nStepValue, double nMaxValue, USHORT nArgMinDigits, - BOOL bAttribs, ScProgress& rProgress ) + +void +ScTable::FillSeries(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + ULONG nFillCount, const sc::FillSeriesData& rFillData, + USHORT nArgMinDigits, bool bAttribs, ScProgress& rProgress) { // // Richtung auswerten // - BOOL bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP); - BOOL bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT); + BOOL bVertical = (rFillData.eDir == FILL_TO_BOTTOM || rFillData.eDir == FILL_TO_TOP); + BOOL bPositive = (rFillData.eDir == FILL_TO_BOTTOM || rFillData.eDir == FILL_TO_RIGHT); ULONG nCol = 0; ULONG nRow = 0; @@ -1340,9 +1316,10 @@ if (pSrcCell) { + double fMaxValue(rFillData.fMax); CellType eCellType = pSrcCell->GetCellType(); - if (eFillCmd == FILL_SIMPLE) // kopieren + if (rFillData.eCmd == FILL_SIMPLE) // kopieren { if (eCellType == CELLTYPE_FORMULA) { @@ -1385,48 +1362,47 @@ { if (!bError && !bOverflow) { - switch (eFillCmd) + switch (rFillData.eCmd) { case FILL_LINEAR: { // #86365# use multiplication instead of repeated addition // to avoid accumulating rounding errors nVal = nStartVal; - double nAdd = nStepValue; + double nAdd = rFillData.fStep; if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) || !SubTotal::SafePlus( nVal, nAdd ) ) bError = TRUE; } break; case FILL_GROWTH: - if (!SubTotal::SafeMult(nVal, nStepValue)) + if (!SubTotal::SafeMult(nVal, rFillData.fStep)) bError = TRUE; break; case FILL_DATE: if (fabs(nVal) > _D_MAX_LONG_) bError = TRUE; else - IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd); - break; + IncDate(nVal, nDayOfMonth, rFillData.fStep, rFillData.eDateCmd); break; default: { // added to avoid warnings } } - if (nStepValue >= 0) + if (rFillData.fStep >= 0) { - if (nVal > nMaxValue) // Zielwert erreicht? + if (nVal > fMaxValue) // Zielwert erreicht? { - nVal = nMaxValue; + nVal = fMaxValue; bOverflow = TRUE; } } else { - if (nVal < nMaxValue) + if (nVal < fMaxValue) { - nVal = nMaxValue; + nVal = fMaxValue; bOverflow = TRUE; } } @@ -1445,27 +1421,40 @@ } else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT) { - if ( nStepValue >= 0 ) + if (rFillData.fStep >= 0) { - if ( nMaxValue >= (double)LONG_MAX ) - nMaxValue = (double)LONG_MAX - 1; + if (fMaxValue >= static_cast(LONG_MAX)) + fMaxValue = static_cast(LONG_MAX) - 1; } else { - if ( nMaxValue <= (double)LONG_MIN ) - nMaxValue = (double)LONG_MIN + 1; + if (fMaxValue <= static_cast(LONG_MIN)) + fMaxValue = static_cast(LONG_MIN) + 1; } String aValue; if (eCellType == CELLTYPE_STRING) ((ScStringCell*)pSrcCell)->GetString( aValue ); else ((ScEditCell*)pSrcCell)->GetString( aValue ); - sal_Int32 nStringValue; - USHORT nMinDigits = nArgMinDigits; - short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits ); - if ( nHeadNoneTail ) + const sc::ValueStringParser aValueString(aValue); + sal_Int32 nStringValue(aValueString.GetValue()); + USHORT nMinDigits(0); + if (nArgMinDigits == 0 && rFillData.bUseString) + { + const sc::ValueStringParser aStart(rFillData.aStart); + const sc::ValueStringParser aMax(rFillData.aMax); + nMinDigits = std::max(aStart.GetMinDigits(), aMax.GetMinDigits()); + } + else + { + nMinDigits = std::max( + nArgMinDigits, + sal::static_int_cast(aValueString.GetMinDigits())); + } + aValue = aValueString.GetBaseSubstring(); + if (aValueString.HasValue()) { - double nStartVal = (double)nStringValue; + double nStartVal = static_cast(nStringValue); double nVal = nStartVal; long nIndex = 0; BOOL bError = FALSE; @@ -1479,21 +1468,21 @@ { if (!bError && !bOverflow) { - switch (eFillCmd) + switch (rFillData.eCmd) { case FILL_LINEAR: { // #86365# use multiplication instead of repeated addition // to avoid accumulating rounding errors nVal = nStartVal; - double nAdd = nStepValue; + double nAdd = rFillData.fStep; if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) || !SubTotal::SafePlus( nVal, nAdd ) ) bError = TRUE; } break; case FILL_GROWTH: - if (!SubTotal::SafeMult(nVal, nStepValue)) + if (!SubTotal::SafeMult(nVal, rFillData.fStep)) bError = TRUE; break; default: @@ -1502,19 +1491,19 @@ } } - if (nStepValue >= 0) + if (rFillData.fStep >= 0) { - if (nVal > nMaxValue) // Zielwert erreicht? + if (nVal > fMaxValue) // Zielwert erreicht? { - nVal = nMaxValue; + nVal = fMaxValue; bOverflow = TRUE; } } else { - if (nVal < nMaxValue) + if (nVal < fMaxValue) { - nVal = nMaxValue; + nVal = fMaxValue; bOverflow = TRUE; } } @@ -1524,9 +1513,9 @@ aCol[nCol].SetError(static_cast(nRow), errNoValue); else if (!bOverflow) { - nStringValue = (sal_Int32)nVal; + nStringValue = static_cast(nVal); String aStr; - if ( nHeadNoneTail < 0 ) + if (aValueString.IsPrefix()) { aCol[nCol].Insert( static_cast(nRow), lcl_getSuffixCell( pDocument, @@ -1563,8 +1552,21 @@ ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, double nStepValue, double nMaxValue) { + sc::FillSeriesData aFillData; + aFillData.eDir = eFillDir; + aFillData.eCmd = eFillCmd; + aFillData.eDateCmd = eFillDateCmd; + aFillData.fStep = nStepValue; + aFillData.fMax = nMaxValue; + Fill(nCol1, nRow1, nCol2, nRow2, nFillCount, aFillData); +} + + +void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + ULONG nFillCount, const sc::FillSeriesData& rFillData) +{ ULONG nProgCount; - if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP) + if (rFillData.eDir == FILL_TO_BOTTOM || rFillData.eDir == FILL_TO_TOP) nProgCount = nCol2 - nCol1 + 1; else nProgCount = nRow2 - nRow1 + 1; @@ -1574,11 +1576,10 @@ bSharedNameInserted = FALSE; - if (eFillCmd == FILL_AUTO) - FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, aProgress); + if (rFillData.eCmd == FILL_AUTO) + FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, rFillData.eDir, aProgress); else - FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, - eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, TRUE, aProgress); + FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, rFillData, 0, true, aProgress); if (bSharedNameInserted) // Wurde Shared-Name eingefuegt? pDocument->GetRangeName()->SetSharedMaxIndex( @@ -1985,9 +1986,3 @@ { for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileColRowNameFormula(); } - - - - - - Index: sc/source/core/data/documen3.cxx =================================================================== --- sc/source/core/data/documen3.cxx (revision 277206) +++ sc/source/core/data/documen3.cxx (working copy) @@ -905,17 +905,30 @@ } void ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScMarkData& rMark, - ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, - double nStepValue, double nMaxValue) + ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, + double nStepValue, double nMaxValue) { + sc::FillSeriesData aFillData; + aFillData.eDir = eFillDir; + aFillData.eCmd = eFillCmd; + aFillData.eDateCmd = eFillDateCmd; + aFillData.fStep = nStepValue; + aFillData.fMax = nMaxValue; + Fill(nCol1, nRow1, nCol2, nRow2, rMark, nFillCount, aFillData); +} + + +void +ScDocument::Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + const ScMarkData& rMark, ULONG nFillCount, + const sc::FillSeriesData& rFillData) +{ PutInOrder( nCol1, nCol2 ); PutInOrder( nRow1, nRow2 ); for (SCTAB i=0; i <= MAXTAB; i++) if (pTab[i]) if (rMark.GetTableSelect(i)) - pTab[i]->Fill(nCol1, nRow1, nCol2, nRow2, - nFillCount, eFillDir, eFillCmd, eFillDateCmd, - nStepValue, nMaxValue); + pTab[i]->Fill(nCol1, nRow1, nCol2, nRow2, nFillCount, rFillData); } String ScDocument::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY ) Index: sc/source/core/data/makefile.mk =================================================================== --- sc/source/core/data/makefile.mk (revision 277206) +++ sc/source/core/data/makefile.mk (working copy) @@ -112,6 +112,7 @@ $(SLO)$/tabprotection.obj \ $(SLO)$/userdat.obj \ $(SLO)$/validat.obj \ + $(SLO)$/valuestringparser.obj \ $(SLO)$/postit.obj EXCEPTIONSFILES= \ Index: sc/source/core/data/valuestringparser.cxx =================================================================== --- sc/source/core/data/valuestringparser.cxx (revision 0) +++ sc/source/core/data/valuestringparser.cxx (revision 0) @@ -0,0 +1,217 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: $ + * $Revision: $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "precompiled_sc.hxx" + +#include + +#include "global.hxx" +#include "sc/valuestringparser.hxx" + + +namespace sc +{ + + namespace + { + + short lcl_DecompValueString( String& aValue, sal_Int32& nVal, USHORT* pMinDigits = NULL ) + { + if ( !aValue.Len() ) + { + nVal = 0; + return 0; + } + const sal_Unicode* p = aValue.GetBuffer(); + xub_StrLen nNeg = 0; + xub_StrLen nNum = 0; + if ( p[nNum] == '-' ) + nNum = nNeg = 1; + while ( p[nNum] && CharClass::isAsciiNumeric( p[nNum] ) ) + nNum++; + + sal_Unicode cNext = p[nNum]; // 0 if at the end + sal_Unicode cLast = p[aValue.Len()-1]; + + // #i5550# If there are numbers at the beginning and the end, + // prefer the one at the beginning only if it's followed by a space. + // Otherwise, use the number at the end, to enable things like IP addresses. + if ( nNum > nNeg && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(cLast) ) ) + { // number at the beginning + nVal = aValue.Copy( 0, nNum ).ToInt32(); + // #60893# any number with a leading zero sets the minimum number of digits + if ( p[nNeg] == '0' && pMinDigits && ( nNum - nNeg > *pMinDigits ) ) + *pMinDigits = nNum - nNeg; + aValue.Erase( 0, nNum ); + return -1; + } + else + { + nNeg = 0; + xub_StrLen nEnd = nNum = aValue.Len() - 1; + while ( nNum && CharClass::isAsciiNumeric( p[nNum] ) ) + nNum--; + if ( p[nNum] == '-' ) + { + nNum--; + nNeg = 1; + } + if ( nNum < nEnd - nNeg ) + { // number at the end + nVal = aValue.Copy( nNum + 1 ).ToInt32(); + // #60893# any number with a leading zero sets the minimum number of digits + if ( p[nNum+1+nNeg] == '0' && pMinDigits && ( nEnd - nNum - nNeg > *pMinDigits ) ) + *pMinDigits = nEnd - nNum - nNeg; + aValue.Erase( nNum + 1 ); + return 1; + } + } + nVal = 0; + return 0; + } + + } + + + ValueStringParser::ValueStringParser(const String& rString) + : m_aString(rString) + , m_aNumericSubstring() + , m_aBaseSubstring() + , m_nValue(0) + , m_nMinDigits(0) + , m_bHasValue(false) + , m_bIsPrefix(false) + { + impl_DecompValueString(); + } + + + bool + ValueStringParser::HasValue() const + { + return m_bHasValue; + } + + + sal_Int32 + ValueStringParser::GetValue() const + { + return m_nValue; + } + + + sal_Int16 + ValueStringParser::GetMinDigits() const + { + return m_nMinDigits; + } + + + const String& + ValueStringParser::GetNumericSubstring() const + { + if (m_bHasValue && m_aNumericSubstring.Len() == 0) + { + if (m_bIsPrefix) + { + m_aNumericSubstring = m_aString.Copy(0, + m_aString.Len() - m_aBaseSubstring.Len()); + } + else + { + m_aNumericSubstring = m_aString.Copy(m_aBaseSubstring.Len()); + } + } + + return m_aNumericSubstring; + } + + + const String& + ValueStringParser::GetBaseSubstring() const + { + return m_aBaseSubstring; + } + + + bool + ValueStringParser::IsPrefix() const + { + return m_bIsPrefix; + } + + + void + ValueStringParser::impl_DecompValueString() + { + String aString(m_aString); + sal_Int32 nValue(0); + USHORT nMinDigits(0); + const short nResult(lcl_DecompValueString(aString, nValue, &nMinDigits)); + m_aBaseSubstring = aString; + if (nResult != 0) + { + m_bHasValue = true; + m_nValue = nValue; + m_nMinDigits = nMinDigits; + m_bIsPrefix = nResult < 0; + } + } + + + bool + CanBeOrdered( + const ValueStringParser& rValueString1, + const ValueStringParser& rValueString2) + { + if (rValueString1.HasValue() && rValueString2.HasValue() + && rValueString1.IsPrefix() == rValueString2.IsPrefix()) + { + if (rValueString1.IsPrefix()) + { + // check if both base substrings are ordinal suffixes + const String aSuffix1(ScGlobal::GetOrdinalSuffix(rValueString1.GetValue())); + const String aSuffix2(ScGlobal::GetOrdinalSuffix(rValueString2.GetValue())); + if (rValueString1.GetBaseSubstring() == aSuffix1 + && rValueString2.GetBaseSubstring() == aSuffix2) + { + return true; + } + // if they are not, just continue and check, if they are + // the same + } + return rValueString1.GetBaseSubstring() == rValueString2.GetBaseSubstring(); + } + return false; + } + +} + +// vim: set sts=4 sw=4 et: Index: sc/source/ui/unoobj/cellsuno.cxx =================================================================== --- sc/source/ui/unoobj/cellsuno.cxx (revision 277206) +++ sc/source/ui/unoobj/cellsuno.cxx (working copy) @@ -5424,8 +5424,14 @@ if (!bError) { ScDocFunc aFunc(*pDocSh); - aFunc.FillSeries( aRange, NULL, eDir, eCmd, eDateCmd, - MAXDOUBLE, fStep, fEndValue, TRUE, TRUE ); + sc::FillSeriesData aFillData; + aFillData.eDir = eDir; + aFillData.eCmd = eCmd; + aFillData.eDateCmd = eDateCmd; + aFillData.fStart = MAXDOUBLE; + aFillData.fStep = fStep; + aFillData.fMax = fEndValue; + aFunc.FillSeries( aRange, NULL, aFillData, TRUE, TRUE ); } } } Index: sc/source/ui/docshell/docfunc.cxx =================================================================== --- sc/source/ui/docshell/docfunc.cxx (revision 277206) +++ sc/source/ui/docshell/docfunc.cxx (working copy) @@ -3775,16 +3775,24 @@ pDoc->CopyToDocument( aCopyRange, IDF_AUTOFILL, FALSE, pUndoDoc, &aMark ); } + sc::FillSeriesData aFillData; + aFillData.eDir = eDir; + aFillData.eCmd = FILL_SIMPLE; + aFillData.eDateCmd = FILL_DAY; + aFillData.fStart = MAXDOUBLE; + aFillData.fStep = 1.0; + aFillData.fMax = 1e307; + pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark, - nCount, eDir, FILL_SIMPLE ); + nCount, aFillData ); AdjustRowHeight(rRange); if ( bRecord ) // Draw-Undo erst jetzt verfuegbar { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, - eDir, FILL_SIMPLE, FILL_DAY, MAXDOUBLE, 1.0, 1e307, + aFillData, pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); } @@ -3800,10 +3808,11 @@ return bSuccess; } -BOOL ScDocFunc::FillSeries( const ScRange& rRange, const ScMarkData* pTabMark, - FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, - double fStart, double fStep, double fMax, - BOOL bRecord, BOOL bApi ) + +bool +ScDocFunc::FillSeries( + const ScRange& rRange, const ScMarkData* pTabMark, + const sc::FillSeriesData& rFillData, bool bRecord, bool bApi) { ScDocShellModificator aModificator( rDocShell ); @@ -3839,16 +3848,16 @@ SCSIZE nCount = pDoc->GetEmptyLinesInBlock( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aStart.Tab(), aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aSourceArea.aEnd.Tab(), - DirFromFillDir(eDir) ); + DirFromFillDir(rFillData.eDir) ); // #27665# mindestens eine Zeile/Spalte als Quellbereich behalten: - SCSIZE nTotLines = ( eDir == FILL_TO_BOTTOM || eDir == FILL_TO_TOP ) ? + SCSIZE nTotLines = ( rFillData.eDir == FILL_TO_BOTTOM || rFillData.eDir == FILL_TO_TOP ) ? static_cast( aSourceArea.aEnd.Row() - aSourceArea.aStart.Row() + 1 ) : static_cast( aSourceArea.aEnd.Col() - aSourceArea.aStart.Col() + 1 ); if ( nCount >= nTotLines ) nCount = nTotLines - 1; - switch (eDir) + switch (rFillData.eDir) { case FILL_TO_BOTTOM: aSourceArea.aEnd.SetRow( sal::static_int_cast( aSourceArea.aEnd.Row() - nCount ) ); @@ -3885,16 +3894,26 @@ if (aDestArea.aStart.Col() <= aDestArea.aEnd.Col() && aDestArea.aStart.Row() <= aDestArea.aEnd.Row()) { - if ( fStart != MAXDOUBLE ) + if (rFillData.fStart != MAXDOUBLE) { - SCCOL nValX = (eDir == FILL_TO_LEFT) ? aDestArea.aEnd.Col() : aDestArea.aStart.Col(); - SCROW nValY = (eDir == FILL_TO_TOP ) ? aDestArea.aEnd.Row() : aDestArea.aStart.Row(); + SCCOL nValX = (rFillData.eDir == FILL_TO_LEFT) + ? aDestArea.aEnd.Col() : aDestArea.aStart.Col(); + SCROW nValY = (rFillData.eDir == FILL_TO_TOP ) + ? aDestArea.aEnd.Row() : aDestArea.aStart.Row(); SCTAB nTab = aDestArea.aStart.Tab(); - pDoc->SetValue( nValX, nValY, nTab, fStart ); + if (rFillData.bUseString) + { + OSL_ENSURE(rFillData.aStart.Len() != 0, "there is no starting string"); + pDoc->SetString(nValX, nValY, nTab, rFillData.aStart); + } + else + { + pDoc->SetValue(nValX, nValY, nTab, rFillData.fStart); + } } pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark, - nCount, eDir, eCmd, eDateCmd, fStep, fMax ); + nCount, rFillData ); AdjustRowHeight(rRange); rDocShell.PostPaintGridAll(); @@ -3906,7 +3925,7 @@ { rDocShell.GetUndoManager()->AddUndoAction( new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, - eDir, eCmd, eDateCmd, fStart, fStep, fMax, + rFillData, pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); } @@ -4021,20 +4040,30 @@ IDF_AUTOFILL, FALSE, pUndoDoc, &aMark ); } - pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), - aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark, - nCount, eDir, eCmd, eDateCmd, fStep, fMax ); + { + sc::FillSeriesData aFillData; + aFillData.eDir = eDir; + aFillData.eCmd = eCmd; + aFillData.eDateCmd = eDateCmd; + aFillData.fStep = fStep; + aFillData.fMax = fMax; - AdjustRowHeight(aDestArea); + pDoc->Fill( aSourceArea.aStart.Col(), aSourceArea.aStart.Row(), + aSourceArea.aEnd.Col(), aSourceArea.aEnd.Row(), aMark, + nCount, aFillData ); - if ( bRecord ) // Draw-Undo erst jetzt verfuegbar - { - rDocShell.GetUndoManager()->AddUndoAction( - new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, - eDir, eCmd, eDateCmd, MAXDOUBLE, fStep, fMax, - pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); - } + AdjustRowHeight(aDestArea); + if ( bRecord ) // Draw-Undo erst jetzt verfuegbar + { + aFillData.fStart = MAXDOUBLE; + rDocShell.GetUndoManager()->AddUndoAction( + new ScUndoAutoFill( &rDocShell, aDestArea, aSourceArea, pUndoDoc, aMark, + aFillData, + pDoc->GetRangeName()->GetSharedMaxIndex()+1 ) ); + } + } + rDocShell.PostPaintGridAll(); // rDocShell.PostPaintDataChanged(); aModificator.SetDocumentModified(); Index: sc/source/ui/attrdlg/scdlgfact.hxx =================================================================== --- sc/source/ui/attrdlg/scdlgfact.hxx (revision 277206) +++ sc/source/ui/attrdlg/scdlgfact.hxx (working copy) @@ -181,6 +181,7 @@ virtual double GetStep() const; virtual double GetMax() const; virtual String GetStartStr() const; + virtual String GetMaxStr() const; virtual void SetEdStartValEnabled(BOOL bFlag=FALSE); }; Index: sc/source/ui/attrdlg/scdlgfact.cxx =================================================================== --- sc/source/ui/attrdlg/scdlgfact.cxx (revision 277206) +++ sc/source/ui/attrdlg/scdlgfact.cxx (working copy) @@ -326,6 +326,10 @@ { return pDlg->GetStartStr(); } +String AbstractScFillSeriesDlg_Impl::GetMaxStr() const +{ + return pDlg->GetMaxStr(); +} void AbstractScFillSeriesDlg_Impl::SetEdStartValEnabled(BOOL bFlag) { pDlg->SetEdStartValEnabled(bFlag); Index: sc/source/ui/miscdlgs/filldlg.cxx =================================================================== --- sc/source/ui/miscdlgs/filldlg.cxx (revision 277206) +++ sc/source/ui/miscdlgs/filldlg.cxx (working copy) @@ -45,9 +45,8 @@ #include "document.hxx" #include "miscdlgs.hrc" -#define _FILLDLG_CXX #include "filldlg.hxx" -#undef _FILLDLG_CXX +#include "sc/valuestringparser.hxx" @@ -247,6 +246,16 @@ else bValOk = rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fStartVal ); + if (!bValOk) + { + sc::ValueStringParser aValueString(aStr); + bValOk = aValueString.HasValue(); + if (bValOk) + { + fStartVal = aValueString.GetValue(); + } + } + return bValOk; } @@ -278,10 +287,45 @@ else bValOk = rDoc.GetFormatTable()->IsNumberFormat( aStr, nKey, fEndVal ); + if (!bValOk) + { + sc::ValueStringParser aValueString(aStr); + bValOk = aValueString.HasValue(); + if (bValOk) + { + fEndVal = aValueString.GetValue(); + } + } + return bValOk; } +namespace +{ + + bool + lcl_CheckStartEndString(const String& rStart, const String& rEnd) + { + const sc::ValueStringParser aStartValueString(rStart); + const sc::ValueStringParser aEndValueString(rEnd); + const bool bStartEmpty(rStart.Len() == 0); + const bool bEndEmpty(rEnd.Len() == 0); + const bool bStartIsValue(aStartValueString.HasValue()); + const bool bEndIsValue(aEndValueString.HasValue()); + bool bValOk((bStartEmpty || bStartIsValue) && (bEndEmpty || bEndIsValue)); + if (bValOk) + { + if (bStartIsValue && bEndIsValue) + { + bValOk = CanBeOrdered(aStartValueString, aEndValueString); + } + } + return bValOk; + } + +} + //---------------------------------------------------------------------------- // Handler: //---------------------------------------------------------------------------- @@ -359,6 +403,11 @@ bAllOk = FALSE; pEdWrong = &aEdEndVal; } + else if (!lcl_CheckStartEndString(aEdStartVal.GetText(), aEdEndVal.GetText())) + { + bAllOk = FALSE; + pEdWrong = &aEdEndVal; + } if ( bAllOk ) EndDialog( RET_OK ); else @@ -372,7 +421,3 @@ return 0; } - - - - Index: sc/source/ui/undo/undoblk3.cxx =================================================================== --- sc/source/ui/undo/undoblk3.cxx (revision 277206) +++ sc/source/ui/undo/undoblk3.cxx (working copy) @@ -578,21 +578,16 @@ ScUndoAutoFill::ScUndoAutoFill( ScDocShell* pNewDocShell, const ScRange& rRange, const ScRange& rSourceArea, ScDocument* pNewUndoDoc, const ScMarkData& rMark, - FillDir eNewFillDir, FillCmd eNewFillCmd, FillDateCmd eNewFillDateCmd, - double fNewStartValue, double fNewStepValue, double fNewMaxValue, - USHORT nMaxShIndex ) + const sc::FillSeriesData& rFillData, USHORT nMaxShIndex ) // : ScBlockUndo( pNewDocShell, rRange, SC_UNDO_AUTOHEIGHT ), // aSource ( rSourceArea ), aMarkData ( rMark ), pUndoDoc ( pNewUndoDoc ), - eFillDir ( eNewFillDir ), - eFillCmd ( eNewFillCmd ), - eFillDateCmd ( eNewFillDateCmd ), - fStartValue ( fNewStartValue ), - fStepValue ( fNewStepValue ), - fMaxValue ( fNewMaxValue ), + m_aFillData(rFillData), + nStartChangeAction(0L), + nEndChangeAction(0L), nMaxSharedIndex ( nMaxShIndex) { SetChangeTrack(); @@ -702,7 +697,7 @@ //! Tabellen selektieren SCCOLROW nCount = 0; - switch (eFillDir) + switch (m_aFillData.eDir) { case FILL_TO_BOTTOM: nCount = aBlockRange.aEnd.Row() - aSource.aEnd.Row(); @@ -719,18 +714,27 @@ } ScDocument* pDoc = pDocShell->GetDocument(); - if ( fStartValue != MAXDOUBLE ) + if (m_aFillData.fStart != MAXDOUBLE) { - SCCOL nValX = (eFillDir == FILL_TO_LEFT) ? aSource.aEnd.Col() : aSource.aStart.Col(); - SCROW nValY = (eFillDir == FILL_TO_TOP ) ? aSource.aEnd.Row() : aSource.aStart.Row(); + SCCOL nValX = (m_aFillData.eDir == FILL_TO_LEFT) + ? aSource.aEnd.Col() : aSource.aStart.Col(); + SCROW nValY = (m_aFillData.eDir == FILL_TO_TOP ) + ? aSource.aEnd.Row() : aSource.aStart.Row(); SCTAB nTab = aSource.aStart.Tab(); - pDoc->SetValue( nValX, nValY, nTab, fStartValue ); + if (m_aFillData.bUseString) + { + OSL_ENSURE(rFillData.aStart.Len() != 0, "there is no starting string"); + pDoc->SetString(nValX, nValY, nTab, m_aFillData.aStart); + } + else + { + pDoc->SetValue(nValX, nValY, nTab, m_aFillData.fStart); + } } - pDoc->Fill( aSource.aStart.Col(), aSource.aStart.Row(), + pDoc->Fill(aSource.aStart.Col(), aSource.aStart.Row(), aSource.aEnd.Col(), aSource.aEnd.Row(), - aMarkData, nCount, - eFillDir, eFillCmd, eFillDateCmd, - fStepValue, fMaxValue ); + aMarkData, nCount, m_aFillData) + ; SetChangeTrack(); @@ -751,11 +755,10 @@ if (rTarget.ISA(ScTabViewTarget)) { ScTabViewShell& rViewShell = *((ScTabViewTarget&)rTarget).GetViewShell(); - if (eFillCmd==FILL_SIMPLE) - rViewShell.FillSimple( eFillDir, TRUE ); + if (m_aFillData.eCmd==FILL_SIMPLE) + rViewShell.FillSimple(m_aFillData.eDir, TRUE); else - rViewShell.FillSeries( eFillDir, eFillCmd, eFillDateCmd, - fStartValue, fStepValue, fMaxValue, TRUE ); + rViewShell.FillSeries(m_aFillData, true); } } Index: sc/source/ui/inc/undoblk.hxx =================================================================== --- sc/source/ui/inc/undoblk.hxx (revision 277206) +++ sc/source/ui/inc/undoblk.hxx (working copy) @@ -48,6 +48,11 @@ class SvxSearchItem; class SdrUndoAction; +// namespace sc +// { + // struct FillSeriesData; +// } + //---------------------------------------------------------------------------- class ScUndoInsertCells: public ScMoveUndo @@ -413,9 +418,7 @@ ScUndoAutoFill( ScDocShell* pNewDocShell, const ScRange& rRange, const ScRange& rSourceArea, ScDocument* pNewUndoDoc, const ScMarkData& rMark, - FillDir eNewFillDir, - FillCmd eNewFillCmd, FillDateCmd eNewFillDateCmd, - double fNewStartValue, double fNewStepValue, double fNewMaxValue, + const sc::FillSeriesData& rFillData, USHORT nMaxShIndex ); virtual ~ScUndoAutoFill(); @@ -430,12 +433,7 @@ ScRange aSource; ScMarkData aMarkData; ScDocument* pUndoDoc; - FillDir eFillDir; - FillCmd eFillCmd; - FillDateCmd eFillDateCmd; - double fStartValue; - double fStepValue; - double fMaxValue; + sc::FillSeriesData m_aFillData; ULONG nStartChangeAction; ULONG nEndChangeAction; USHORT nMaxSharedIndex; Index: sc/source/ui/inc/viewfunc.hxx =================================================================== --- sc/source/ui/inc/viewfunc.hxx (revision 277206) +++ sc/source/ui/inc/viewfunc.hxx (working copy) @@ -244,10 +244,11 @@ BOOL RemoveMerge( BOOL bRecord = TRUE ); void FillSimple( FillDir eDir, BOOL bRecord = TRUE ); - void FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, - double fStart, double fStep, double fMax, BOOL bRecord = TRUE ); - void FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow, - SCCOL nEndCol, SCROW nEndRow, ULONG nCount, BOOL bRecord = TRUE ); + void FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, + double fStart, double fStep, double fMax, BOOL bRecord = TRUE ); + void FillSeries(const sc::FillSeriesData& rFillData, bool bRecord = true); + void FillAuto( FillDir eDir, SCCOL nStartCol, SCROW nStartRow, + SCCOL nEndCol, SCROW nEndRow, ULONG nCount, BOOL bRecord = TRUE ); void FillCrossDblClick(); void TransliterateText( sal_Int32 nType ); Index: sc/source/ui/inc/filldlg.hxx =================================================================== --- sc/source/ui/inc/filldlg.hxx (revision 277206) +++ sc/source/ui/inc/filldlg.hxx (working copy) @@ -78,6 +78,10 @@ double GetMax() const { return fEndVal; } String GetStartStr() const { return aEdStartVal.GetText(); } + String GetMaxStr() const + { + return aEdEndVal.GetText(); + } void SetEdStartValEnabled(BOOL bFlag=FALSE); @@ -129,7 +133,6 @@ double fIncrement; double fEndVal; -#ifdef _FILLDLG_CXX private: void Init( USHORT nPossDir ); BOOL CheckStartVal(); @@ -138,10 +141,8 @@ DECL_LINK( OKHdl, void * ); DECL_LINK( DisableHdl, Button * ); -#endif }; - #endif // SC_FILLDLG_HXX Index: sc/source/ui/inc/docfunc.hxx =================================================================== --- sc/source/ui/inc/docfunc.hxx (revision 277206) +++ sc/source/ui/inc/docfunc.hxx (working copy) @@ -154,15 +154,13 @@ BOOL TabOp( const ScRange& rRange, const ScMarkData* pTabMark, const ScTabOpParam& rParam, BOOL bRecord, BOOL bApi ); - BOOL FillSimple( const ScRange& rRange, const ScMarkData* pTabMark, - FillDir eDir, BOOL bRecord, BOOL bApi ); - BOOL FillSeries( const ScRange& rRange, const ScMarkData* pTabMark, - FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, - double fStart, double fStep, double fMax, - BOOL bRecord, BOOL bApi ); + BOOL FillSimple( const ScRange& rRange, const ScMarkData* pTabMark, + FillDir eDir, BOOL bRecord, BOOL bApi ); + bool FillSeries(const ScRange& rRange, const ScMarkData* pTabMark, + const sc::FillSeriesData& rFillData, bool bRecord, bool bApi); // FillAuto: rRange wird von Source-Range auf Dest-Range angepasst - BOOL FillAuto( ScRange& rRange, const ScMarkData* pTabMark, - FillDir eDir, ULONG nCount, BOOL bRecord, BOOL bApi ); + BOOL FillAuto( ScRange& rRange, const ScMarkData* pTabMark, + FillDir eDir, ULONG nCount, BOOL bRecord, BOOL bApi ); BOOL ResizeMatrix( const ScRange& rOldRange, const ScAddress& rNewEnd, BOOL bApi ); Index: sc/source/ui/view/viewfun2.cxx =================================================================== --- sc/source/ui/view/viewfun2.cxx (revision 277206) +++ sc/source/ui/view/viewfun2.cxx (working copy) @@ -1232,16 +1232,29 @@ //---------------------------------------------------------------------------- void ScViewFunc::FillSeries( FillDir eDir, FillCmd eCmd, FillDateCmd eDateCmd, - double fStart, double fStep, double fMax, BOOL bRecord ) + double fStart, double fStep, double fMax, BOOL bRecord ) { + sc::FillSeriesData aFillData; + aFillData.eDir = eDir; + aFillData.eCmd = eCmd; + aFillData.eDateCmd = eDateCmd; + aFillData.fStart = fStart; + aFillData.fStep = fStep; + aFillData.fMax = fMax; + FillSeries(aFillData, bRecord); +} + + +void +ScViewFunc::FillSeries(const sc::FillSeriesData& rFillData, bool bRecord) +{ ScRange aRange; if (GetViewData()->GetSimpleArea(aRange) == SC_MARK_SIMPLE) { ScDocShell* pDocSh = GetViewData()->GetDocShell(); const ScMarkData& rMark = GetViewData()->GetMarkData(); BOOL bSuccess = pDocSh->GetDocFunc(). - FillSeries( aRange, &rMark, eDir, eCmd, eDateCmd, - fStart, fStep, fMax, bRecord, FALSE ); + FillSeries(aRange, &rMark, rFillData, bRecord, FALSE); if (bSuccess) { pDocSh->UpdateOle(GetViewData()); Index: sc/source/ui/view/cellsh1.cxx =================================================================== --- sc/source/ui/view/cellsh1.cxx (revision 277206) +++ sc/source/ui/view/cellsh1.cxx (working copy) @@ -111,6 +111,8 @@ #include //CHINA001 #include //CHINA001 #include "scabstdlg.hxx" //CHINA001 +#include "sc/valuestringparser.hxx" + #define IS_AVAILABLE(WhichId,ppItem) \ (pReqArgs->GetItemState((WhichId), TRUE, ppItem ) == SFX_ITEM_SET) @@ -126,6 +128,48 @@ using namespace ::com::sun::star::beans; using namespace ::com::sun::star::uno; + +namespace +{ + + sc::FillSeriesData + lcl_CreateFillSeriesData(const AbstractScFillSeriesDlg& rFillDlg) + { + sc::FillSeriesData aFillData; + aFillData.eDir = rFillDlg.GetFillDir(); + aFillData.eCmd = rFillDlg.GetFillCmd(); + aFillData.eDateCmd = rFillDlg.GetFillDateCmd(); + { + const sc::ValueStringParser aValueString(rFillDlg.GetStartStr()); + aFillData.bUseString = aValueString.GetBaseSubstring().Len() != 0; + if (aFillData.bUseString) + { + aFillData.aStart = rFillDlg.GetStartStr(); + aFillData.aMax = rFillDlg.GetMaxStr(); + } + } + aFillData.fStart = rFillDlg.GetStart(); + aFillData.fMax = rFillDlg.GetMax(); + aFillData.fStep = rFillDlg.GetStep(); + + return aFillData; + } + + + double + lcl_GetNumericValue(const String& rStr) + { + double fResult(0.0); + sc::ValueStringParser aValueString(rStr); + if (aValueString.HasValue()) + { + fResult = aValueString.GetValue(); + } + return fResult; + } + +} + //------------------------------------------------------------------ void ScCellShell::ExecuteEdit( SfxRequest& rReq ) { @@ -561,12 +605,7 @@ SCROW nEndRow; SCTAB nEndTab; USHORT nPossDir = FDS_OPT_NONE; - FillDir eFillDir = FILL_TO_BOTTOM; - FillCmd eFillCmd = FILL_LINEAR; - FillDateCmd eFillDateCmd = FILL_DAY; - double fStartVal = MAXDOUBLE; - double fIncVal = 1; - double fMaxVal = MAXDOUBLE; + sc::FillSeriesData aFillData; BOOL bDoIt = FALSE; GetViewData()->GetSimpleArea( nStartCol, nStartRow, nStartTab, @@ -575,13 +614,13 @@ if( nStartCol!=nEndCol ) { nPossDir |= FDS_OPT_HORZ; - eFillDir=FILL_TO_RIGHT; + aFillData.eDir = FILL_TO_RIGHT; } if( nStartRow!=nEndRow ) { nPossDir |= FDS_OPT_VERT; - eFillDir=FILL_TO_BOTTOM; + aFillData.eDir = FILL_TO_BOTTOM; } ScDocument* pDoc = GetViewData()->GetDocument(); @@ -613,42 +652,42 @@ if( aFillDir.Len() ) switch( aFillDir.GetChar(0) ) { - case 'B': case 'b': eFillDir=FILL_TO_BOTTOM; break; - case 'R': case 'r': eFillDir=FILL_TO_RIGHT; break; - case 'T': case 't': eFillDir=FILL_TO_TOP; break; - case 'L': case 'l': eFillDir=FILL_TO_LEFT; break; + case 'B': case 'b': aFillData.eDir = FILL_TO_BOTTOM; break; + case 'R': case 'r': aFillData.eDir = FILL_TO_RIGHT; break; + case 'T': case 't': aFillData.eDir = FILL_TO_TOP; break; + case 'L': case 'l': aFillData.eDir = FILL_TO_LEFT; break; } if( aFillCmd.Len() ) switch( aFillCmd.GetChar(0) ) { - case 'S': case 's': eFillCmd=FILL_SIMPLE; break; - case 'L': case 'l': eFillCmd=FILL_LINEAR; break; - case 'G': case 'g': eFillCmd=FILL_GROWTH; break; - case 'D': case 'd': eFillCmd=FILL_DATE; break; - case 'A': case 'a': eFillCmd=FILL_AUTO; break; + case 'S': case 's': aFillData.eCmd = FILL_SIMPLE; break; + case 'L': case 'l': aFillData.eCmd = FILL_LINEAR; break; + case 'G': case 'g': aFillData.eCmd = FILL_GROWTH; break; + case 'D': case 'd': aFillData.eCmd = FILL_DATE; break; + case 'A': case 'a': aFillData.eCmd = FILL_AUTO; break; } if( aFillDateCmd.Len() ) switch( aFillDateCmd.GetChar(0) ) { - case 'D': case 'd': eFillDateCmd=FILL_DAY; break; - case 'W': case 'w': eFillDateCmd=FILL_WEEKDAY; break; - case 'M': case 'm': eFillDateCmd=FILL_MONTH; break; - case 'Y': case 'y': eFillDateCmd=FILL_YEAR; break; + case 'D': case 'd': aFillData.eDateCmd = FILL_DAY; break; + case 'W': case 'w': aFillData.eDateCmd = FILL_WEEKDAY; break; + case 'M': case 'm': aFillData.eDateCmd = FILL_MONTH; break; + case 'Y': case 'y': aFillData.eDateCmd = FILL_YEAR; break; } nKey = 0; if( pFormatter->IsNumberFormat( aFillStart, nKey, fTmpVal )) - fStartVal = fTmpVal; + aFillData.fStart = fTmpVal; nKey = 0; if( pFormatter->IsNumberFormat( aFillStep, nKey, fTmpVal )) - fIncVal = fTmpVal; + aFillData.fStep = fTmpVal; nKey = 0; if( pFormatter->IsNumberFormat( aFillMax, nKey, fTmpVal )) - fMaxVal = fTmpVal; + aFillData.fMax = fTmpVal; bDoIt = TRUE; @@ -670,11 +709,11 @@ short nPrivType = pPrivEntry->GetType(); if ( ( nPrivType & NUMBERFORMAT_DATE)>0) { - eFillCmd=FILL_DATE; + aFillData.eCmd = FILL_DATE; } else if(eCellType==CELLTYPE_STRING) { - eFillCmd=FILL_AUTO; + aFillData.eCmd = FILL_AUTO; } } @@ -688,16 +727,16 @@ String aEndStr; pDoc->GetInputString( nStartCol, nStartRow, nStartTab, aStartStr); - pDoc->GetValue( nStartCol, nStartRow, nStartTab, fStartVal ); + aFillData.fStart = lcl_GetNumericValue(aStartStr); - if(eFillDir==FILL_TO_BOTTOM && nStartRow < nEndRow ) + if(aFillData.eDir == FILL_TO_BOTTOM && nStartRow < nEndRow ) { pDoc->GetInputString( nStartCol, nStartRow+1, nStartTab, aEndStr); if(aEndStr.Len()>0) { - pDoc->GetValue( nStartCol, nStartRow+1, nStartTab, fInputEndVal); - fIncVal=fInputEndVal-fStartVal; + fInputEndVal = lcl_GetNumericValue(aEndStr); + aFillData.fStep = fInputEndVal - aFillData.fStart; } } else @@ -707,50 +746,50 @@ pDoc->GetInputString( nStartCol+1, nStartRow, nStartTab, aEndStr); if(aEndStr.Len()>0) { - pDoc->GetValue( nStartCol+1, nStartRow, nStartTab, fInputEndVal); - fIncVal=fInputEndVal-fStartVal; + fInputEndVal = lcl_GetNumericValue(aEndStr); + aFillData.fStep = fInputEndVal - aFillData.fStart; } } } - if(eFillCmd==FILL_DATE) + if (aFillData.eCmd == FILL_DATE) { Date aNullDate = *pDoc->GetFormatTable()->GetNullDate(); Date aStartDate = aNullDate; - aStartDate+= (long)fStartVal; + aStartDate += static_cast(aFillData.fStart); Date aEndDate = aNullDate; - aEndDate+= (long)fInputEndVal; + aEndDate += static_cast(fInputEndVal); double fTempDate=0; if(aStartDate.GetYear()!=aEndDate.GetYear()) { - eFillDateCmd = FILL_YEAR; + aFillData.eDateCmd = FILL_YEAR; fTempDate=aEndDate.GetYear()-aStartDate.GetYear(); } if(aStartDate.GetMonth()!=aEndDate.GetMonth()) { - eFillDateCmd = FILL_MONTH; + aFillData.eDateCmd = FILL_MONTH; fTempDate=fTempDate*12+aEndDate.GetMonth()-aStartDate.GetMonth(); } if(aStartDate.GetDay()==aEndDate.GetDay()) { - fIncVal=fTempDate; + aFillData.fStep = fTempDate; } } } //CHINA001 ScFillSeriesDlg* pDlg = new ScFillSeriesDlg( //CHINA001 pTabViewShell->GetDialogParent(), *pDoc, -//CHINA001 eFillDir, eFillCmd, eFillDateCmd, +//CHINA001 eDir, eCmd, eDateCmd, //CHINA001 aStartStr, fIncVal, fMaxVal, //CHINA001 nPossDir); ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create(); DBG_ASSERT(pFact, "ScAbstractFactory create fail!");//CHINA001 - AbstractScFillSeriesDlg* pDlg = pFact->CreateScFillSeriesDlg( pTabViewShell->GetDialogParent(), - *pDoc, - eFillDir, eFillCmd, eFillDateCmd, - aStartStr, fIncVal, fMaxVal, - nPossDir, - RID_SCDLG_FILLSERIES); + AbstractScFillSeriesDlg* pDlg = pFact->CreateScFillSeriesDlg( + pTabViewShell->GetDialogParent(), *pDoc, + aFillData.eDir, aFillData.eCmd, aFillData.eDateCmd, + aStartStr, aFillData.fStep, aFillData.fMax, + nPossDir, RID_SCDLG_FILLSERIES) + ; DBG_ASSERT(pDlg, "Dialog create fail!");//CHINA001 if ( nStartCol != nEndCol && nStartRow != nEndRow ) @@ -760,20 +799,14 @@ if ( pDlg->Execute() == RET_OK ) { - eFillDir = pDlg->GetFillDir(); - eFillCmd = pDlg->GetFillCmd(); - eFillDateCmd = pDlg->GetFillDateCmd(); - - if(eFillCmd==FILL_AUTO) + aFillData = lcl_CreateFillSeriesData(*pDlg); + aFillData.bUseString = true; + if (aFillData.eCmd == FILL_AUTO) { - String aStr=pDlg->GetStartStr(); - if(aStr.Len()>0) - pTabViewShell->EnterData( nStartCol, nStartRow, nStartTab, aStr ); + if (aFillData.aStart.Len() > 0) + pTabViewShell->EnterData(nStartCol, nStartRow, nStartTab, aFillData.aStart); } - fStartVal = pDlg->GetStart(); - fIncVal = pDlg->GetStep(); - fMaxVal = pDlg->GetMax(); - bDoIt = TRUE; + bDoIt = TRUE; } delete pDlg; } @@ -781,14 +814,14 @@ if( bDoIt ) { //nScFillModeMouseModifier = 0; // kein Ctrl/Copy - pTabViewShell->FillSeries( eFillDir, eFillCmd, eFillDateCmd, fStartVal, fIncVal, fMaxVal ); + pTabViewShell->FillSeries(aFillData); if( ! rReq.IsAPI() ) { String aPara; Color* pColor=0; - switch( eFillDir ) + switch( aFillData.eDir ) { case FILL_TO_BOTTOM: aPara = 'B'; break; case FILL_TO_RIGHT: aPara = 'R'; break; @@ -798,7 +831,7 @@ } rReq.AppendItem( SfxStringItem( FID_FILL_SERIES, aPara ) ); - switch( eFillCmd ) + switch( aFillData.eCmd ) { case FILL_SIMPLE: aPara = 'S'; break; case FILL_LINEAR: aPara = 'L'; break; @@ -809,7 +842,7 @@ } rReq.AppendItem( SfxStringItem( FN_PARAM_1, aPara ) ); - switch( eFillDateCmd ) + switch( aFillData.eDateCmd ) { case FILL_DAY: aPara = 'D'; break; case FILL_WEEKDAY: aPara = 'W'; break; @@ -822,13 +855,13 @@ ULONG nFormatKey = pFormatter->GetStandardFormat(NUMBERFORMAT_NUMBER, ScGlobal::eLnge ); - pFormatter->GetOutputString( fIncVal, nFormatKey, aPara, &pColor ); + pFormatter->GetOutputString(aFillData.fStep, nFormatKey, aPara, &pColor); rReq.AppendItem( SfxStringItem( FN_PARAM_3, aPara ) ); - pFormatter->GetOutputString( fStartVal, nFormatKey, aPara, &pColor ); + pFormatter->GetOutputString(aFillData.fStart, nFormatKey, aPara, &pColor); rReq.AppendItem( SfxStringItem( FN_PARAM_4, aPara ) ); - pFormatter->GetOutputString( fMaxVal, nFormatKey, aPara, &pColor ); + pFormatter->GetOutputString(aFillData.fMax, nFormatKey, aPara, &pColor); rReq.AppendItem( SfxStringItem( FN_PARAM_5, aPara ) ); rReq.Done(); Index: sc/inc/scabstdlg.hxx =================================================================== --- sc/inc/scabstdlg.hxx (revision 277206) +++ sc/inc/scabstdlg.hxx (working copy) @@ -128,6 +128,7 @@ virtual double GetStep() const = 0; virtual double GetMax() const = 0; virtual String GetStartStr() const = 0; + virtual String GetMaxStr() const = 0; virtual void SetEdStartValEnabled(BOOL bFlag=FALSE) = 0; }; Index: sc/inc/table.hxx =================================================================== --- sc/inc/table.hxx (revision 277206) +++ sc/inc/table.hxx (working copy) @@ -275,7 +275,7 @@ aCol[rPos.Col()].GetValue( rPos.Row() ) : 0.0; } - double GetValue( SCCOL nCol, SCROW nRow ); + double GetValue( SCCOL nCol, SCROW nRow ) const; void GetFormula( SCCOL nCol, SCROW nRow, String& rFormula, BOOL bAsciiExport = FALSE ); @@ -441,9 +441,11 @@ std::set& rIndexes) const; void ReplaceRangeNamesInUse(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, const ScRangeData::IndexMap& rMap ); + void Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, + double nStepValue, double nMaxValue); void Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, - ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd, - double nStepValue, double nMaxValue); + ULONG nFillCount, const sc::FillSeriesData& rFillData); String GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY ); void UpdateSelectionFunction( ScFunctionData& rData, @@ -664,11 +666,9 @@ void DestroySortCollator(); private: - void FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, - ULONG nFillCount, FillDir eFillDir, FillCmd eFillCmd, - FillDateCmd eFillDateCmd, - double nStepValue, double nMaxValue, USHORT nMinDigits, - BOOL bAttribs, ScProgress& rProgress ); + void FillSeries(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + ULONG nFillCount, const sc::FillSeriesData& rFillData, + USHORT nMinDigits, bool bAttribs, ScProgress& rProgress); void FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, FillCmd& rCmd, FillDateCmd& rDateCmd, double& rInc, USHORT& rMinDigits, @@ -752,6 +752,8 @@ // also invalidates script type, broadcasts for "calc as shown" void InvalidateTextWidth( const ScAddress* pAdrFrom, const ScAddress* pAdrTo, BOOL bNumFormatChanged, BOOL bBroadcast ); + + bool impl_getNumericValue(const SCCOL nCol, const SCROW nRow, double& rValue) const; }; Index: sc/inc/sc/valuestringparser.hxx =================================================================== --- sc/inc/sc/valuestringparser.hxx (revision 0) +++ sc/inc/sc/valuestringparser.hxx (revision 0) @@ -0,0 +1,110 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: $ + * $Revision: $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef SC_VALUESTRINGPARSER_HXX_INCLUDED +#define SC_VALUESTRINGPARSER_HXX_INCLUDED + +#include + +#include "scdllapi.h" + + +namespace sc +{ + + /** Extract numeric value from a string and supply more info about it. + Only integer numbers staying at the beginning or at the end of the + string are recognized. + + The only function usable when there is no numeric value (i.e. when + HasValue() returns false) is GetBaseSubstring(), returning the + original string. The other functions return default values of their + respective types. + */ + class SC_DLLPUBLIC ValueStringParser + { + public: + /** Examine rString for possible numeric value. + */ + SC_DLLPUBLIC ValueStringParser(const String& rString); + + /** Tell if the string contains (recognizable) numeric value. + */ + SC_DLLPUBLIC bool HasValue() const; + + /** Get the found numeric value. + */ + SC_DLLPUBLIC sal_Int32 GetValue() const; + + /** Get the minimum number of digits required for representation + of the number. Value 0 means there is no requirement. + */ + SC_DLLPUBLIC sal_Int16 GetMinDigits() const; + + /** Get the numeric substring (if any). This function returns + nonempty string iff HasValue() == true. + */ + SC_DLLPUBLIC const String& GetNumericSubstring() const; + + /** Get the base (i.e. non-numeric substring. + */ + SC_DLLPUBLIC const String& GetBaseSubstring() const; + + /** Tell if the number is prefix of the base substring. + */ + SC_DLLPUBLIC bool IsPrefix() const; + + private: + void impl_DecompValueString(); + + private: + String m_aString; + mutable String m_aNumericSubstring; + String m_aBaseSubstring; + sal_Int32 m_nValue; + sal_Int16 m_nMinDigits; + bool m_bHasValue; + bool m_bIsPrefix; + }; + + /** Test if the two parsed strings can be ordered. They can be iff + they both have numeric value and either share a common prefix/suffix + or their suffix makes valid ordinal numbers from both of them. + */ + SC_DLLPUBLIC bool + CanBeOrdered( + const ValueStringParser& rValueString1, + const ValueStringParser& rValueString2); + +} + +#endif + +// vim: set sts=4 sw=4 et: Index: sc/inc/global.hxx =================================================================== --- sc/inc/global.hxx (revision 277206) +++ sc/inc/global.hxx (working copy) @@ -965,4 +965,24 @@ extern ::utl::TransliterationWrapper* GetScGlobalpTransliteration();//CHINA001 extern const LocaleDataWrapper* GetScGlobalpLocaleData(); +namespace sc +{ + + struct FillSeriesData + { + FillDir eDir; + FillCmd eCmd; + FillDateCmd eDateCmd; + double fStart; + String aStart; + double fStep; + double fMax; + String aMax; + bool bUseString; + + FillSeriesData(); + }; + +} + #endif Index: sc/inc/document.hxx =================================================================== --- sc/inc/document.hxx (revision 277206) +++ sc/inc/document.hxx (working copy) @@ -740,6 +740,7 @@ SC_DLLPUBLIC void GetInputString( SCCOL nCol, SCROW nRow, SCTAB nTab, String& rString ); SC_DLLPUBLIC double GetValue( const ScAddress& ); SC_DLLPUBLIC void GetValue( SCCOL nCol, SCROW nRow, SCTAB nTab, double& rValue ); + SC_DLLPUBLIC double RoundValueAsShown( double fVal, ULONG nFormat ); SC_DLLPUBLIC void GetNumberFormat( SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt32& rFormat ); @@ -1070,11 +1071,14 @@ void UpdateGrow( const ScRange& rArea, SCCOL nGrowX, SCROW nGrowY ); - void Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, - const ScMarkData& rMark, - ULONG nFillCount, FillDir eFillDir = FILL_TO_BOTTOM, - FillCmd eFillCmd = FILL_LINEAR, FillDateCmd eFillDateCmd = FILL_DAY, - double nStepValue = 1.0, double nMaxValue = 1E307); + void Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + const ScMarkData& rMark, + ULONG nFillCount, FillDir eFillDir = FILL_TO_BOTTOM, + FillCmd eFillCmd = FILL_LINEAR, FillDateCmd eFillDateCmd = FILL_DAY, + double nStepValue = 1.0, double nMaxValue = 1E307); + void Fill(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, + const ScMarkData& rMark, ULONG nFillCount, + const sc::FillSeriesData& rFillData); String GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY ); BOOL GetSelectionFunction( ScSubTotalFunc eFunc,