/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_sc.hxx" // INCLUDE --------------------------------------------------------------- #include #include "consoli.hxx" #include "document.hxx" #include "olinetab.hxx" #include "globstr.hrc" #include "subtotal.hxx" #include "formula/errorcodes.hxx" #include "cell.hxx" #include #include #define SC_CONS_NOTFOUND -1 // STATIC DATA ----------------------------------------------------------- /* Strings bei Gelegenheit ganz raus... static sal_uInt16 nFuncRes[] = { // Reihenfolge wie bei enum ScSubTotalFunc 0, // none STR_PIVOTFUNC_AVG, STR_PIVOTFUNC_COUNT, STR_PIVOTFUNC_COUNT2, STR_PIVOTFUNC_MAX, STR_PIVOTFUNC_MIN, STR_PIVOTFUNC_PROD, STR_PIVOTFUNC_STDDEV, STR_PIVOTFUNC_STDDEV2, STR_PIVOTFUNC_SUM, STR_PIVOTFUNC_VAR, STR_PIVOTFUNC_VAR2 }; */ static OpCode eOpCodeTable[] = { // Reihenfolge wie bei enum ScSubTotalFunc ocBad, // none ocAverage, ocCount, ocCount2, ocMax, ocMin, ocProduct, ocStDev, ocStDevP, ocSum, ocVar, ocVarP }; // ----------------------------------------------------------------------- void ScReferenceList::AddEntry( SCCOL nCol, SCROW nRow, SCTAB nTab ) { ScReferenceEntry* pOldData = pData; pData = new ScReferenceEntry[ nFullSize+1 ]; if (pOldData) { memmove( pData, pOldData, nCount * sizeof(ScReferenceEntry) ); delete[] pOldData; } while (nCount < nFullSize) { pData[nCount].nCol = SC_CONS_NOTFOUND; pData[nCount].nRow = SC_CONS_NOTFOUND; pData[nCount].nTab = SC_CONS_NOTFOUND; ++nCount; } pData[nCount].nCol = nCol; pData[nCount].nRow = nRow; pData[nCount].nTab = nTab; ++nCount; nFullSize = nCount; } template< typename T > void lcl_AddString( String**& pData, T& nCount, const String& rInsert ) { String** pOldData = pData; pData = new String*[ nCount+1 ]; if (pOldData) { memmove( pData, pOldData, nCount * sizeof(String*) ); delete[] pOldData; } pData[nCount] = new String(rInsert); ++nCount; } // ----------------------------------------------------------------------- ScConsData::ScConsData() : eFunction(SUBTOTAL_FUNC_SUM), bReference(sal_False), bColByName(sal_False), bRowByName(sal_False), bSubTitles(sal_False), nColCount(0), nRowCount(0), ppUsed(NULL), ppSum(NULL), ppCount(NULL), ppSumSqr(NULL), ppRefs(NULL), ppColHeaders(NULL), ppRowHeaders(NULL), nDataCount(0), nTitleCount(0), ppTitles(NULL), ppTitlePos(NULL), bCornerUsed(sal_False) { } ScConsData::~ScConsData() { DeleteData(); } #define DELETEARR(ppArray,nCount) \ { \ sal_uLong i; \ if (ppArray) \ for(i=0; i(nCols); nRowCount = static_cast(nRows); } void ScConsData::GetSize( SCCOL& rCols, SCROW& rRows ) const { rCols = static_cast(nColCount); rRows = static_cast(nRowCount); } void ScConsData::SetFlags( ScSubTotalFunc eFunc, sal_Bool bColName, sal_Bool bRowName, sal_Bool bRef ) { DeleteData(); bReference = bRef; bColByName = bColName; if (bColName) nColCount = 0; bRowByName = bRowName; if (bRowName) nRowCount = 0; eFunction = eFunc; } void ScConsData::AddFields( ScDocument* pSrcDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) { ++nDataCount; String aTitle; SCCOL nStartCol = nCol1; SCROW nStartRow = nRow1; if (bColByName) ++nStartRow; if (bRowByName) ++nStartCol; if (bColByName) { for (SCCOL nCol=nStartCol; nCol<=nCol2; nCol++) { pSrcDoc->GetString( nCol, nRow1, nTab, aTitle ); if (aTitle.Len()) { sal_Bool bFound = sal_False; for (SCSIZE i=0; iGetString( nCol1, nRow, nTab, aTitle ); if (aTitle.Len()) { sal_Bool bFound = sal_False; for (SCSIZE i=0; i Fehler aufgetreten void lcl_UpdateArray( ScSubTotalFunc eFunc, double& rCount, double& rSum, double& rSumSqr, double nVal ) { if (rCount < 0.0) return; switch (eFunc) { case SUBTOTAL_FUNC_SUM: if (!SubTotal::SafePlus(rSum, nVal)) rCount = -MAXDOUBLE; break; case SUBTOTAL_FUNC_PROD: if (!SubTotal::SafeMult(rSum, nVal)) rCount = -MAXDOUBLE; break; case SUBTOTAL_FUNC_CNT: case SUBTOTAL_FUNC_CNT2: rCount += 1.0; break; case SUBTOTAL_FUNC_AVE: if (!SubTotal::SafePlus(rSum, nVal)) rCount = -MAXDOUBLE; else rCount += 1.0; break; case SUBTOTAL_FUNC_MAX: if (nVal > rSum) rSum = nVal; break; case SUBTOTAL_FUNC_MIN: if (nVal < rSum) rSum = nVal; break; case SUBTOTAL_FUNC_STD: case SUBTOTAL_FUNC_STDP: case SUBTOTAL_FUNC_VAR: case SUBTOTAL_FUNC_VARP: { sal_Bool bOk = SubTotal::SafePlus(rSum, nVal); bOk = bOk && SubTotal::SafeMult(nVal, nVal); bOk = bOk && SubTotal::SafePlus(rSumSqr, nVal); if (!bOk) rCount = -MAXDOUBLE; else rCount += 1.0; break; } default: { // added to avoid warnings } } } void lcl_InitArray( ScSubTotalFunc eFunc, double& rCount, double& rSum, double& rSumSqr, double nVal ) { rCount = 1.0; switch (eFunc) { case SUBTOTAL_FUNC_SUM: case SUBTOTAL_FUNC_MAX: case SUBTOTAL_FUNC_MIN: case SUBTOTAL_FUNC_PROD: case SUBTOTAL_FUNC_AVE: rSum = nVal; break; case SUBTOTAL_FUNC_STD: case SUBTOTAL_FUNC_STDP: case SUBTOTAL_FUNC_VAR: case SUBTOTAL_FUNC_VARP: { rSum = nVal; sal_Bool bOk = SubTotal::SafeMult(nVal, nVal); if (bOk) rSumSqr = nVal; else rCount = -MAXDOUBLE; } break; default: break; } } double lcl_CalcData( ScSubTotalFunc eFunc, double fCount, double fSum, double fSumSqr) { if (fCount < 0.0) return 0.0; double fVal = 0.0; switch (eFunc) { case SUBTOTAL_FUNC_CNT: case SUBTOTAL_FUNC_CNT2: fVal = fCount; break; case SUBTOTAL_FUNC_SUM: case SUBTOTAL_FUNC_MAX: case SUBTOTAL_FUNC_MIN: case SUBTOTAL_FUNC_PROD: fVal = fSum; break; case SUBTOTAL_FUNC_AVE: if (fCount > 0.0) fVal = fSum / fCount; else fCount = -MAXDOUBLE; break; case SUBTOTAL_FUNC_STD: { if (fCount > 1 && SubTotal::SafeMult(fSum, fSum)) fVal = sqrt((fSumSqr - fSum/fCount)/(fCount-1.0)); else fCount = -MAXDOUBLE; } break; case SUBTOTAL_FUNC_STDP: { if (fCount > 0 && SubTotal::SafeMult(fSum, fSum)) fVal = sqrt((fSumSqr - fSum/fCount)/fCount); else fCount = -MAXDOUBLE; } break; case SUBTOTAL_FUNC_VAR: { if (fCount > 1 && SubTotal::SafeMult(fSum, fSum)) fVal = (fSumSqr - fSum/fCount)/(fCount-1.0); else fCount = -MAXDOUBLE; } break; case SUBTOTAL_FUNC_VARP: { if (fCount > 0 && SubTotal::SafeMult(fSum, fSum)) fVal = (fSumSqr - fSum/fCount)/fCount; else fCount = -MAXDOUBLE; } break; default: { DBG_ERROR("unbekannte Funktion bei Consoli::CalcData"); fCount = -MAXDOUBLE; } break; } return fVal; } void ScConsData::AddData( ScDocument* pSrcDoc, SCTAB nTab, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) { PutInOrder(nCol1,nCol2); PutInOrder(nRow1,nRow2); if ( nCol2 >= sal::static_int_cast(nCol1 + nColCount) && !bColByName ) { DBG_ASSERT(0,"Bereich zu gross"); nCol2 = sal::static_int_cast( nCol1 + nColCount - 1 ); } if ( nRow2 >= sal::static_int_cast(nRow1 + nRowCount) && !bRowByName ) { DBG_ASSERT(0,"Bereich zu gross"); nRow2 = sal::static_int_cast( nRow1 + nRowCount - 1 ); } SCCOL nCol; SCROW nRow; // Ecke links oben if ( bColByName && bRowByName ) { String aThisCorner; pSrcDoc->GetString(nCol1,nRow1,nTab,aThisCorner); if (bCornerUsed) { if (aCornerText != aThisCorner) aCornerText.Erase(); } else { aCornerText = aThisCorner; bCornerUsed = sal_True; } } // Titel suchen SCCOL nStartCol = nCol1; SCROW nStartRow = nRow1; if (bColByName) ++nStartRow; if (bRowByName) ++nStartCol; String aTitle; SCCOL* pDestCols = NULL; SCROW* pDestRows = NULL; if (bColByName) { pDestCols = new SCCOL[nCol2-nStartCol+1]; for (nCol=nStartCol; nCol<=nCol2; nCol++) { pSrcDoc->GetString(nCol,nRow1,nTab,aTitle); SCCOL nPos = SC_CONS_NOTFOUND; if (aTitle.Len()) { sal_Bool bFound = sal_False; for (SCSIZE i=0; i(i); bFound = sal_True; } DBG_ASSERT(bFound, "Spalte nicht gefunden"); } pDestCols[nCol-nStartCol] = nPos; } } if (bRowByName) { pDestRows = new SCROW[nRow2-nStartRow+1]; for (nRow=nStartRow; nRow<=nRow2; nRow++) { pSrcDoc->GetString(nCol1,nRow,nTab,aTitle); SCROW nPos = SC_CONS_NOTFOUND; if (aTitle.Len()) { sal_Bool bFound = sal_False; for (SCSIZE i=0; i(i); bFound = sal_True; } DBG_ASSERT(bFound, "Zeile nicht gefunden"); } pDestRows[nRow-nStartRow] = nPos; } } nCol1 = nStartCol; nRow1 = nStartRow; // Daten sal_Bool bAnyCell = ( eFunction == SUBTOTAL_FUNC_CNT2 ); for (nCol=nCol1; nCol<=nCol2; nCol++) { SCCOL nArrX = nCol-nCol1; if (bColByName) nArrX = pDestCols[nArrX]; if (nArrX != SC_CONS_NOTFOUND) { for (nRow=nRow1; nRow<=nRow2; nRow++) { SCROW nArrY = nRow-nRow1; if (bRowByName) nArrY = pDestRows[nArrY]; if ( nArrY != SC_CONS_NOTFOUND && ( bAnyCell ? pSrcDoc->HasData( nCol, nRow, nTab ) : pSrcDoc->HasValueData( nCol, nRow, nTab ) ) ) { if (bReference) { if (ppUsed[nArrX][nArrY]) ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab ); else { ppUsed[nArrX][nArrY] = sal_True; ppRefs[nArrX][nArrY].Init(); ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab ); } } else { double nVal; pSrcDoc->GetValue( nCol, nRow, nTab, nVal ); if (ppUsed[nArrX][nArrY]) lcl_UpdateArray( eFunction, ppCount[nArrX][nArrY], ppSum[nArrX][nArrY], ppSumSqr[nArrX][nArrY], nVal); else { ppUsed[nArrX][nArrY] = sal_True; lcl_InitArray( eFunction, ppCount[nArrX][nArrY], ppSum[nArrX][nArrY], ppSumSqr[nArrX][nArrY], nVal ); } } } } } } delete[] pDestCols; delete[] pDestRows; } // vorher testen, wieviele Zeilen eingefuegt werden (fuer Undo) SCROW ScConsData::GetInsertCount() const { SCROW nInsert = 0; SCSIZE nArrX; SCSIZE nArrY; if ( ppRefs && ppUsed ) { for (nArrY=0; nArrYSetString( nCol, nRow, nTab, aCornerText ); // Titel SCCOL nStartCol = nCol; SCROW nStartRow = nRow; if (bColByName) ++nStartRow; if (bRowByName) ++nStartCol; if (bColByName) for (SCSIZE i=0; iSetString( sal::static_int_cast(nStartCol+i), nRow, nTab, *ppColHeaders[i] ); if (bRowByName) for (SCSIZE j=0; jSetString( nCol, sal::static_int_cast(nStartRow+j), nTab, *ppRowHeaders[j] ); nCol = nStartCol; nRow = nStartRow; // Daten if ( ppCount && ppUsed ) // Werte direkt einfuegen { for (nArrX=0; nArrXSetError( sal::static_int_cast(nCol+nArrX), sal::static_int_cast(nRow+nArrY), nTab, errNoValue ); else pDestDoc->SetValue( sal::static_int_cast(nCol+nArrX), sal::static_int_cast(nRow+nArrY), nTab, fVal ); } } if ( ppRefs && ppUsed ) // Referenzen einfuegen { //! unterscheiden, ob nach Kategorien aufgeteilt String aString; ScSingleRefData aSRef; // Daten fuer Referenz-Formelzellen aSRef.InitFlags(); aSRef.SetFlag3D(sal_True); ScComplexRefData aCRef; // Daten fuer Summen-Zellen aCRef.InitFlags(); aCRef.Ref1.SetColRel(sal_True); aCRef.Ref1.SetRowRel(sal_True); aCRef.Ref1.SetTabRel(sal_True); aCRef.Ref2.SetColRel(sal_True); aCRef.Ref2.SetRowRel(sal_True); aCRef.Ref2.SetTabRel(sal_True); for (nArrY=0; nArrYInsertRow( 0,nTab, MAXCOL,nTab, nRow+nArrY, nNeeded ); for (nArrX=0; nArrX(nCol+nArrX), sal::static_int_cast(nRow+nArrY+nPos), nTab ); ScBaseCell* pCell = new ScFormulaCell( pDestDoc, aDest, &aRefArr ); pDestDoc->PutCell( aDest.Col(), aDest.Row(), aDest.Tab(), pCell ); } } // Summe einfuegen (relativ, nicht 3d) ScAddress aDest( sal::static_int_cast(nCol+nArrX), sal::static_int_cast(nRow+nArrY+nNeeded), nTab ); aCRef.Ref1.nTab = aCRef.Ref2.nTab = nTab; aCRef.Ref1.nCol = aCRef.Ref2.nCol = sal::static_int_cast( nCol+nArrX ); aCRef.Ref1.nRow = nRow+nArrY; aCRef.Ref2.nRow = nRow+nArrY+nNeeded-1; aCRef.CalcRelFromAbs( aDest ); ScTokenArray aArr; aArr.AddOpCode(eOpCode); // ausgewaehlte Funktion aArr.AddOpCode(ocOpen); aArr.AddDoubleReference(aCRef); aArr.AddOpCode(ocClose); aArr.AddOpCode(ocStop); ScBaseCell* pCell = new ScFormulaCell( pDestDoc, aDest, &aArr ); pDestDoc->PutCell( aDest.Col(), aDest.Row(), aDest.Tab(), pCell ); } } // Gliederung einfuegen ScOutlineArray* pOutArr = pDestDoc->GetOutlineTable( nTab, sal_True )->GetRowArray(); SCROW nOutStart = nRow+nArrY; SCROW nOutEnd = nRow+nArrY+nNeeded-1; sal_Bool bSize = sal_False; pOutArr->Insert( nOutStart, nOutEnd, bSize ); for (SCROW nOutRow=nOutStart; nOutRow<=nOutEnd; nOutRow++) pDestDoc->ShowRow( nOutRow, nTab, sal_False ); pDestDoc->UpdateOutlineRow( nOutStart, nOutEnd, nTab, sal_False ); // Zwischentitel if (ppTitlePos && ppTitles && ppRowHeaders) { String aDelim( RTL_CONSTASCII_USTRINGPARAM(" / ") ); for (SCSIZE nPos=0; nPosSetString( nCol-1, nRow+nArrY+nTPos, nTab, aString ); } } } nRow += nNeeded; } } } }