/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * 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 . */ #include "consoli.hxx" #include "document.hxx" #include "olinetab.hxx" #include "globstr.hrc" #include "subtotal.hxx" #include #include "formulacell.hxx" #include "tokenarray.hxx" #include #include #include #define SC_CONS_NOTFOUND -1 // STATIC DATA static const 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) { memcpy( 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 > static void lcl_AddString( ::std::vector& rData, T& nCount, const OUString& rInsert ) { rData.push_back( rInsert); ++nCount; } ScConsData::ScConsData() : eFunction(SUBTOTAL_FUNC_SUM), bReference(false), bColByName(false), bRowByName(false), nColCount(0), nRowCount(0), ppUsed(NULL), ppSum(NULL), ppCount(NULL), ppSumSqr(NULL), ppRefs(NULL), nDataCount(0), ppTitlePos(NULL), bCornerUsed(false) { } ScConsData::~ScConsData() { DeleteData(); } #define DELETEARR(ppArray,nCount) \ { \ sal_uLong i; \ if (ppArray) \ for(i=0; i().swap( maColHeaders); ::std::vector().swap( maRowHeaders); ::std::vector().swap( maTitles); nDataCount = 0; if (bColByName) nColCount = 0; // sonst stimmt maColHeaders nicht if (bRowByName) nRowCount = 0; bCornerUsed = false; aCornerText = ""; } #undef DELETEARR #undef DELETESTR void ScConsData::InitData() { if (bReference && nColCount && !ppRefs) { ppRefs = new ScReferenceList*[nColCount]; for (SCSIZE 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, bool bColName, bool bRowName, 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; OUString aTitle; SCCOL nStartCol = nCol1; SCROW nStartRow = nRow1; if (bColByName) ++nStartRow; if (bRowByName) ++nStartCol; if (bColByName) { for (SCCOL nCol=nStartCol; nCol<=nCol2; nCol++) { aTitle = pSrcDoc->GetString(nCol, nRow1, nTab); if (!aTitle.isEmpty()) { bool bFound = false; for (SCSIZE i=0; iGetString(nCol1, nRow, nTab); if (!aTitle.isEmpty()) { bool bFound = false; for (SCSIZE i=0; i Fehler aufgetreten static 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: { 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 } } } static 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; bool bOk = SubTotal::SafeMult(nVal, nVal); if (bOk) rSumSqr = nVal; else rCount = -MAXDOUBLE; } break; default: break; } } static 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: { OSL_FAIL("Consoli::CalcData: unknown function"); 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 ) { OSL_FAIL("range too big"); nCol2 = sal::static_int_cast( nCol1 + nColCount - 1 ); } if ( nRow2 >= sal::static_int_cast(nRow1 + nRowCount) && !bRowByName ) { OSL_FAIL("range too big"); nRow2 = sal::static_int_cast( nRow1 + nRowCount - 1 ); } SCCOL nCol; SCROW nRow; // Ecke links oben if ( bColByName && bRowByName ) { OUString aThisCorner = pSrcDoc->GetString(nCol1, nRow1, nTab); if (bCornerUsed) { if (aCornerText != aThisCorner) aCornerText = ""; } else { aCornerText = aThisCorner; bCornerUsed = true; } } // Titel suchen SCCOL nStartCol = nCol1; SCROW nStartRow = nRow1; if (bColByName) ++nStartRow; if (bRowByName) ++nStartCol; OUString aTitle; boost::scoped_array pDestCols; boost::scoped_array pDestRows; if (bColByName) { pDestCols.reset(new SCCOL[nCol2-nStartCol+1]); for (nCol=nStartCol; nCol<=nCol2; nCol++) { aTitle = pSrcDoc->GetString(nCol, nRow1, nTab); SCCOL nPos = SC_CONS_NOTFOUND; if (!aTitle.isEmpty()) { bool bFound = false; for (SCSIZE i=0; i(i); bFound = true; } OSL_ENSURE(bFound, "column not found"); } pDestCols[nCol-nStartCol] = nPos; } } if (bRowByName) { pDestRows.reset(new SCROW[nRow2-nStartRow+1]); for (nRow=nStartRow; nRow<=nRow2; nRow++) { aTitle = pSrcDoc->GetString(nCol1, nRow, nTab); SCROW nPos = SC_CONS_NOTFOUND; if (!aTitle.isEmpty()) { bool bFound = false; for (SCSIZE i=0; i(i); bFound = true; } OSL_ENSURE(bFound, "row not found"); } pDestRows[nRow-nStartRow] = nPos; } } nCol1 = nStartCol; nRow1 = nStartRow; // Daten 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] = 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] = true; lcl_InitArray( eFunction, ppCount[nArrX][nArrY], ppSum[nArrX][nArrY], ppSumSqr[nArrX][nArrY], nVal ); } } } } } } } // 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, maColHeaders[i] ); if (bRowByName) for (SCSIZE j=0; jSetString( nCol, sal::static_int_cast(nStartRow+j), nTab, maRowHeaders[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 OUString aString; ScSingleRefData aSRef; // Daten fuer Referenz-Formelzellen aSRef.InitFlags(); // This reference is absolute at all times. aSRef.SetFlag3D(true); ScComplexRefData aCRef; // Daten fuer Summen-Zellen aCRef.InitFlags(); aCRef.Ref1.SetColRel(true); aCRef.Ref1.SetRowRel(true); aCRef.Ref1.SetTabRel(true); aCRef.Ref2.SetColRel(true); aCRef.Ref2.SetRowRel(true); aCRef.Ref2.SetTabRel(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 ); ScFormulaCell* pCell = new ScFormulaCell(pDestDoc, aDest, aRefArr); pDestDoc->SetFormulaCell(aDest, pCell); } } // Summe einfuegen (relativ, nicht 3d) ScAddress aDest( sal::static_int_cast(nCol+nArrX), sal::static_int_cast(nRow+nArrY+nNeeded), nTab ); ScRange aRange(sal::static_int_cast(nCol+nArrX), nRow+nArrY, nTab); aRange.aEnd.SetRow(nRow+nArrY+nNeeded-1); aCRef.SetRange(aRange, aDest); ScTokenArray aArr; aArr.AddOpCode(eOpCode); // ausgewaehlte Funktion aArr.AddOpCode(ocOpen); aArr.AddDoubleReference(aCRef); aArr.AddOpCode(ocClose); aArr.AddOpCode(ocStop); ScFormulaCell* pCell = new ScFormulaCell(pDestDoc, aDest, aArr); pDestDoc->SetFormulaCell(aDest, pCell); } } // Gliederung einfuegen ScOutlineArray& rOutArr = pDestDoc->GetOutlineTable( nTab, true )->GetRowArray(); SCROW nOutStart = nRow+nArrY; SCROW nOutEnd = nRow+nArrY+nNeeded-1; bool bSize = false; rOutArr.Insert( nOutStart, nOutEnd, bSize ); for (SCROW nOutRow=nOutStart; nOutRow<=nOutEnd; nOutRow++) pDestDoc->ShowRow( nOutRow, nTab, false ); pDestDoc->SetDrawPageSize(nTab); pDestDoc->UpdateOutlineRow( nOutStart, nOutEnd, nTab, false ); // Zwischentitel if (ppTitlePos && !maTitles.empty() && !maRowHeaders.empty()) { OUString aDelim( " / " ); for (SCSIZE nPos=0; nPosSetString( nCol-1, nRow+nArrY+nTPos, nTab, aString ); } } } nRow += nNeeded; } } } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */