xref: /AOO41X/main/sc/source/core/tool/consoli.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 
28 
29 // INCLUDE ---------------------------------------------------------------
30 
31 #include <tools/debug.hxx>
32 
33 #include "consoli.hxx"
34 #include "document.hxx"
35 #include "olinetab.hxx"
36 #include "globstr.hrc"
37 #include "subtotal.hxx"
38 #include "formula/errorcodes.hxx"
39 #include "cell.hxx"
40 
41 #include <math.h>
42 #include <string.h>
43 
44 #define SC_CONS_NOTFOUND    -1
45 
46 // STATIC DATA -----------------------------------------------------------
47 
48 /*  Strings bei Gelegenheit ganz raus...
49 static sal_uInt16 nFuncRes[] = {                //  Reihenfolge wie bei enum ScSubTotalFunc
50         0,                                  //  none
51         STR_PIVOTFUNC_AVG,
52         STR_PIVOTFUNC_COUNT,
53         STR_PIVOTFUNC_COUNT2,
54         STR_PIVOTFUNC_MAX,
55         STR_PIVOTFUNC_MIN,
56         STR_PIVOTFUNC_PROD,
57         STR_PIVOTFUNC_STDDEV,
58         STR_PIVOTFUNC_STDDEV2,
59         STR_PIVOTFUNC_SUM,
60         STR_PIVOTFUNC_VAR,
61         STR_PIVOTFUNC_VAR2 };
62 */
63 
64 static OpCode eOpCodeTable[] = {            //  Reihenfolge wie bei enum ScSubTotalFunc
65         ocBad,                              //  none
66         ocAverage,
67         ocCount,
68         ocCount2,
69         ocMax,
70         ocMin,
71         ocProduct,
72         ocStDev,
73         ocStDevP,
74         ocSum,
75         ocVar,
76         ocVarP };
77 
78 // -----------------------------------------------------------------------
79 
AddEntry(SCCOL nCol,SCROW nRow,SCTAB nTab)80 void ScReferenceList::AddEntry( SCCOL nCol, SCROW nRow, SCTAB nTab )
81 {
82     ScReferenceEntry* pOldData = pData;
83     pData = new ScReferenceEntry[ nFullSize+1 ];
84     if (pOldData)
85     {
86         memmove( pData, pOldData, nCount * sizeof(ScReferenceEntry) );
87         delete[] pOldData;
88     }
89     while (nCount < nFullSize)
90     {
91         pData[nCount].nCol = SC_CONS_NOTFOUND;
92         pData[nCount].nRow = SC_CONS_NOTFOUND;
93         pData[nCount].nTab = SC_CONS_NOTFOUND;
94         ++nCount;
95     }
96     pData[nCount].nCol = nCol;
97     pData[nCount].nRow = nRow;
98     pData[nCount].nTab = nTab;
99     ++nCount;
100     nFullSize = nCount;
101 }
102 
103 template< typename T >
lcl_AddString(String ** & pData,T & nCount,const String & rInsert)104 void lcl_AddString( String**& pData, T& nCount, const String& rInsert )
105 {
106     String** pOldData = pData;
107     pData = new String*[ nCount+1 ];
108     if (pOldData)
109     {
110         memmove( pData, pOldData, nCount * sizeof(String*) );
111         delete[] pOldData;
112     }
113     pData[nCount] = new String(rInsert);
114     ++nCount;
115 }
116 
117 // -----------------------------------------------------------------------
118 
ScConsData()119 ScConsData::ScConsData() :
120     eFunction(SUBTOTAL_FUNC_SUM),
121     bReference(sal_False),
122     bColByName(sal_False),
123     bRowByName(sal_False),
124     bSubTitles(sal_False),
125     nColCount(0),
126     nRowCount(0),
127     ppUsed(NULL),
128     ppSum(NULL),
129     ppCount(NULL),
130     ppSumSqr(NULL),
131     ppRefs(NULL),
132     ppColHeaders(NULL),
133     ppRowHeaders(NULL),
134     nDataCount(0),
135     nTitleCount(0),
136     ppTitles(NULL),
137     ppTitlePos(NULL),
138     bCornerUsed(sal_False)
139 {
140 }
141 
~ScConsData()142 ScConsData::~ScConsData()
143 {
144     DeleteData();
145 }
146 
147 
148 #define DELETEARR(ppArray,nCount)   \
149 {                                   \
150     sal_uLong i;                        \
151     if (ppArray)                    \
152         for(i=0; i<nCount; i++)     \
153             delete[] ppArray[i];    \
154     delete[] ppArray;               \
155     ppArray = NULL;                 \
156 }
157 
158 #define DELETESTR(ppArray,nCount)   \
159 {                                   \
160     sal_uLong i;                        \
161     if (ppArray)                    \
162         for(i=0; i<nCount; i++)     \
163             delete ppArray[i];      \
164     delete[] ppArray;               \
165     ppArray = NULL;                 \
166 }
167 
DeleteData()168 void ScConsData::DeleteData()
169 {
170     if (ppRefs)
171     {
172         for (SCSIZE i=0; i<nColCount; i++)
173         {
174             for (SCSIZE j=0; j<nRowCount; j++)
175                 if (ppUsed[i][j])
176                     ppRefs[i][j].Clear();
177             delete[] ppRefs[i];
178         }
179         delete[] ppRefs;
180         ppRefs = NULL;
181     }
182 
183 //  DELETEARR( ppData1, nColCount );
184 //  DELETEARR( ppData2, nColCount );
185     DELETEARR( ppCount, nColCount );
186     DELETEARR( ppSum,   nColCount );
187     DELETEARR( ppSumSqr,nColCount );
188     DELETEARR( ppUsed,  nColCount );                // erst nach ppRefs !!!
189     DELETEARR( ppTitlePos, nRowCount );
190     DELETESTR( ppColHeaders, nColCount );
191     DELETESTR( ppRowHeaders, nRowCount );
192     DELETESTR( ppTitles, nTitleCount );
193     nTitleCount = 0;
194     nDataCount = 0;
195 
196     if (bColByName) nColCount = 0;                  // sonst stimmt ppColHeaders nicht
197     if (bRowByName) nRowCount = 0;
198 
199     bCornerUsed = sal_False;
200     aCornerText.Erase();
201 }
202 
203 #undef DELETEARR
204 #undef DELETESTR
205 
InitData(sal_Bool bDelete)206 void ScConsData::InitData( sal_Bool bDelete )
207 {
208     if (bDelete)
209         DeleteData();
210 
211     if (bReference && nColCount && !ppRefs)
212     {
213         ppRefs = new ScReferenceList*[nColCount];
214         for (SCSIZE i=0; i<nColCount; i++)
215             ppRefs[i] = new ScReferenceList[nRowCount];
216     }
217     else if (nColCount && !ppCount)
218     {
219         ppCount  = new double*[nColCount];
220         ppSum    = new double*[nColCount];
221         ppSumSqr = new double*[nColCount];
222         for (SCSIZE i=0; i<nColCount; i++)
223         {
224             ppCount[i]  = new double[nRowCount];
225             ppSum[i]    = new double[nRowCount];
226             ppSumSqr[i] = new double[nRowCount];
227         }
228     }
229 
230     if (nColCount && !ppUsed)
231     {
232         ppUsed = new sal_Bool*[nColCount];
233         for (SCSIZE i=0; i<nColCount; i++)
234         {
235             ppUsed[i] = new sal_Bool[nRowCount];
236             memset( ppUsed[i], 0, nRowCount * sizeof(sal_Bool) );
237         }
238     }
239 
240     if (nRowCount && nDataCount && !ppTitlePos)
241     {
242         ppTitlePos = new SCSIZE*[nRowCount];
243         for (SCSIZE i=0; i<nRowCount; i++)
244         {
245             ppTitlePos[i] = new SCSIZE[nDataCount];
246             memset( ppTitlePos[i], 0, nDataCount * sizeof(SCSIZE) );    //! unnoetig ?
247         }
248     }
249 
250     //  CornerText: einzelner String
251 }
252 
DoneFields()253 void ScConsData::DoneFields()
254 {
255     InitData(sal_False);
256 }
257 
SetSize(SCCOL nCols,SCROW nRows)258 void ScConsData::SetSize( SCCOL nCols, SCROW nRows )
259 {
260     DeleteData();
261     nColCount = static_cast<SCSIZE>(nCols);
262     nRowCount = static_cast<SCSIZE>(nRows);
263 }
264 
GetSize(SCCOL & rCols,SCROW & rRows) const265 void ScConsData::GetSize( SCCOL& rCols, SCROW& rRows ) const
266 {
267     rCols = static_cast<SCCOL>(nColCount);
268     rRows = static_cast<SCROW>(nRowCount);
269 }
270 
SetFlags(ScSubTotalFunc eFunc,sal_Bool bColName,sal_Bool bRowName,sal_Bool bRef)271 void ScConsData::SetFlags( ScSubTotalFunc eFunc, sal_Bool bColName, sal_Bool bRowName, sal_Bool bRef )
272 {
273     DeleteData();
274     bReference = bRef;
275     bColByName = bColName;
276     if (bColName) nColCount = 0;
277     bRowByName = bRowName;
278     if (bRowName) nRowCount = 0;
279     eFunction = eFunc;
280 }
281 
AddFields(ScDocument * pSrcDoc,SCTAB nTab,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)282 void ScConsData::AddFields( ScDocument* pSrcDoc, SCTAB nTab,
283                             SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
284 {
285     ++nDataCount;
286 
287     String aTitle;
288 
289     SCCOL nStartCol = nCol1;
290     SCROW nStartRow = nRow1;
291     if (bColByName) ++nStartRow;
292     if (bRowByName) ++nStartCol;
293 
294     if (bColByName)
295     {
296         for (SCCOL nCol=nStartCol; nCol<=nCol2; nCol++)
297         {
298             pSrcDoc->GetString( nCol, nRow1, nTab, aTitle );
299             if (aTitle.Len())
300             {
301                 sal_Bool bFound = sal_False;
302                 for (SCSIZE i=0; i<nColCount && !bFound; i++)
303                     if ( *ppColHeaders[i] == aTitle )
304                         bFound = sal_True;
305                 if (!bFound)
306                     lcl_AddString( ppColHeaders, nColCount, aTitle );
307             }
308         }
309     }
310 
311     if (bRowByName)
312     {
313         for (SCROW nRow=nStartRow; nRow<=nRow2; nRow++)
314         {
315             pSrcDoc->GetString( nCol1, nRow, nTab, aTitle );
316             if (aTitle.Len())
317             {
318                 sal_Bool bFound = sal_False;
319                 for (SCSIZE i=0; i<nRowCount && !bFound; i++)
320                     if ( *ppRowHeaders[i] == aTitle )
321                         bFound = sal_True;
322                 if (!bFound)
323                     lcl_AddString( ppRowHeaders, nRowCount, aTitle );
324             }
325         }
326     }
327 }
328 
AddName(const String & rName)329 void ScConsData::AddName( const String& rName )
330 {
331     SCSIZE nArrX;
332     SCSIZE nArrY;
333 
334     if (bReference)
335     {
336         lcl_AddString( ppTitles, nTitleCount, rName );
337 
338         for (nArrY=0; nArrY<nRowCount; nArrY++)
339         {
340             //  Daten auf gleiche Laenge bringen
341 
342             SCSIZE nMax = 0;
343             for (nArrX=0; nArrX<nColCount; nArrX++)
344                 if (ppUsed[nArrX][nArrY])
345                     nMax = Max( nMax, ppRefs[nArrX][nArrY].GetCount() );
346 
347             for (nArrX=0; nArrX<nColCount; nArrX++)
348             {
349                 if (!ppUsed[nArrX][nArrY])
350                 {
351                     ppUsed[nArrX][nArrY] = sal_True;
352                     ppRefs[nArrX][nArrY].Init();
353                 }
354                 ppRefs[nArrX][nArrY].SetFullSize(nMax);
355             }
356 
357             //  Positionen eintragen
358 
359             if (ppTitlePos)
360                 if (nTitleCount < nDataCount)
361                     ppTitlePos[nArrY][nTitleCount] = nMax;
362         }
363     }
364 }
365 
366                                 // rCount < 0 <=> Fehler aufgetreten
367 
lcl_UpdateArray(ScSubTotalFunc eFunc,double & rCount,double & rSum,double & rSumSqr,double nVal)368 void lcl_UpdateArray( ScSubTotalFunc eFunc,
369                          double& rCount, double& rSum, double& rSumSqr, double nVal )
370 {
371     if (rCount < 0.0)
372         return;
373     switch (eFunc)
374     {
375         case SUBTOTAL_FUNC_SUM:
376             if (!SubTotal::SafePlus(rSum, nVal))
377                 rCount = -MAXDOUBLE;
378             break;
379         case SUBTOTAL_FUNC_PROD:
380             if (!SubTotal::SafeMult(rSum, nVal))
381                 rCount = -MAXDOUBLE;
382             break;
383         case SUBTOTAL_FUNC_CNT:
384         case SUBTOTAL_FUNC_CNT2:
385             rCount += 1.0;
386             break;
387         case SUBTOTAL_FUNC_AVE:
388             if (!SubTotal::SafePlus(rSum, nVal))
389                 rCount = -MAXDOUBLE;
390             else
391                 rCount += 1.0;
392             break;
393         case SUBTOTAL_FUNC_MAX:
394             if (nVal > rSum)
395                 rSum = nVal;
396             break;
397         case SUBTOTAL_FUNC_MIN:
398             if (nVal < rSum)
399                 rSum = nVal;
400             break;
401         case SUBTOTAL_FUNC_STD:
402         case SUBTOTAL_FUNC_STDP:
403         case SUBTOTAL_FUNC_VAR:
404         case SUBTOTAL_FUNC_VARP:
405         {
406             sal_Bool bOk = SubTotal::SafePlus(rSum, nVal);
407             bOk = bOk && SubTotal::SafeMult(nVal, nVal);
408             bOk = bOk && SubTotal::SafePlus(rSumSqr, nVal);
409             if (!bOk)
410                 rCount = -MAXDOUBLE;
411             else
412                 rCount += 1.0;
413             break;
414         }
415         default:
416         {
417             // added to avoid warnings
418         }
419     }
420 }
421 
lcl_InitArray(ScSubTotalFunc eFunc,double & rCount,double & rSum,double & rSumSqr,double nVal)422 void lcl_InitArray( ScSubTotalFunc eFunc,
423                        double& rCount, double& rSum, double& rSumSqr, double nVal )
424 {
425     rCount = 1.0;
426     switch (eFunc)
427     {
428         case SUBTOTAL_FUNC_SUM:
429         case SUBTOTAL_FUNC_MAX:
430         case SUBTOTAL_FUNC_MIN:
431         case SUBTOTAL_FUNC_PROD:
432         case SUBTOTAL_FUNC_AVE:
433             rSum = nVal;
434             break;
435         case SUBTOTAL_FUNC_STD:
436         case SUBTOTAL_FUNC_STDP:
437         case SUBTOTAL_FUNC_VAR:
438         case SUBTOTAL_FUNC_VARP:
439         {
440             rSum = nVal;
441             sal_Bool bOk = SubTotal::SafeMult(nVal, nVal);
442             if (bOk)
443                 rSumSqr = nVal;
444             else
445                 rCount = -MAXDOUBLE;
446         }
447             break;
448         default:
449             break;
450     }
451 }
452 
lcl_CalcData(ScSubTotalFunc eFunc,double fCount,double fSum,double fSumSqr)453 double lcl_CalcData( ScSubTotalFunc eFunc,
454                         double fCount, double fSum, double fSumSqr)
455 {
456     if (fCount < 0.0)
457         return 0.0;
458     double fVal = 0.0;
459     switch (eFunc)
460     {
461         case SUBTOTAL_FUNC_CNT:
462         case SUBTOTAL_FUNC_CNT2:
463             fVal = fCount;
464             break;
465         case SUBTOTAL_FUNC_SUM:
466         case SUBTOTAL_FUNC_MAX:
467         case SUBTOTAL_FUNC_MIN:
468         case SUBTOTAL_FUNC_PROD:
469             fVal = fSum;
470             break;
471         case SUBTOTAL_FUNC_AVE:
472             if (fCount > 0.0)
473                 fVal = fSum / fCount;
474             else
475                 fCount = -MAXDOUBLE;
476             break;
477         case SUBTOTAL_FUNC_STD:
478         {
479             if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
480                 fVal = sqrt((fSumSqr - fSum/fCount)/(fCount-1.0));
481             else
482                 fCount = -MAXDOUBLE;
483         }
484             break;
485         case SUBTOTAL_FUNC_STDP:
486         {
487             if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
488                 fVal = sqrt((fSumSqr - fSum/fCount)/fCount);
489             else
490                 fCount = -MAXDOUBLE;
491         }
492             break;
493         case SUBTOTAL_FUNC_VAR:
494         {
495             if (fCount > 1 && SubTotal::SafeMult(fSum, fSum))
496                 fVal = (fSumSqr - fSum/fCount)/(fCount-1.0);
497             else
498                 fCount = -MAXDOUBLE;
499         }
500             break;
501         case SUBTOTAL_FUNC_VARP:
502         {
503             if (fCount > 0 && SubTotal::SafeMult(fSum, fSum))
504                 fVal = (fSumSqr - fSum/fCount)/fCount;
505             else
506                 fCount = -MAXDOUBLE;
507         }
508             break;
509         default:
510         {
511             DBG_ERROR("unbekannte Funktion bei Consoli::CalcData");
512             fCount = -MAXDOUBLE;
513         }
514             break;
515     }
516     return fVal;
517 }
518 
AddData(ScDocument * pSrcDoc,SCTAB nTab,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)519 void ScConsData::AddData( ScDocument* pSrcDoc, SCTAB nTab,
520                             SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
521 {
522     PutInOrder(nCol1,nCol2);
523     PutInOrder(nRow1,nRow2);
524     if ( nCol2 >= sal::static_int_cast<SCCOL>(nCol1 + nColCount) && !bColByName )
525     {
526         DBG_ASSERT(0,"Bereich zu gross");
527         nCol2 = sal::static_int_cast<SCCOL>( nCol1 + nColCount - 1 );
528     }
529     if ( nRow2 >= sal::static_int_cast<SCROW>(nRow1 + nRowCount) && !bRowByName )
530     {
531         DBG_ASSERT(0,"Bereich zu gross");
532         nRow2 = sal::static_int_cast<SCROW>( nRow1 + nRowCount - 1 );
533     }
534 
535     SCCOL nCol;
536     SCROW nRow;
537 
538     //      Ecke links oben
539 
540     if ( bColByName && bRowByName )
541     {
542         String aThisCorner;
543         pSrcDoc->GetString(nCol1,nRow1,nTab,aThisCorner);
544         if (bCornerUsed)
545         {
546             if (aCornerText != aThisCorner)
547                 aCornerText.Erase();
548         }
549         else
550         {
551             aCornerText = aThisCorner;
552             bCornerUsed = sal_True;
553         }
554     }
555 
556     //      Titel suchen
557 
558     SCCOL nStartCol = nCol1;
559     SCROW nStartRow = nRow1;
560     if (bColByName) ++nStartRow;
561     if (bRowByName) ++nStartCol;
562     String aTitle;
563     SCCOL*  pDestCols = NULL;
564     SCROW*  pDestRows = NULL;
565     if (bColByName)
566     {
567         pDestCols = new SCCOL[nCol2-nStartCol+1];
568         for (nCol=nStartCol; nCol<=nCol2; nCol++)
569         {
570             pSrcDoc->GetString(nCol,nRow1,nTab,aTitle);
571             SCCOL nPos = SC_CONS_NOTFOUND;
572             if (aTitle.Len())
573             {
574                 sal_Bool bFound = sal_False;
575                 for (SCSIZE i=0; i<nColCount && !bFound; i++)
576                     if ( *ppColHeaders[i] == aTitle )
577                     {
578                         nPos = static_cast<SCCOL>(i);
579                         bFound = sal_True;
580                     }
581                 DBG_ASSERT(bFound, "Spalte nicht gefunden");
582             }
583             pDestCols[nCol-nStartCol] = nPos;
584         }
585     }
586     if (bRowByName)
587     {
588         pDestRows = new SCROW[nRow2-nStartRow+1];
589         for (nRow=nStartRow; nRow<=nRow2; nRow++)
590         {
591             pSrcDoc->GetString(nCol1,nRow,nTab,aTitle);
592             SCROW nPos = SC_CONS_NOTFOUND;
593             if (aTitle.Len())
594             {
595                 sal_Bool bFound = sal_False;
596                 for (SCSIZE i=0; i<nRowCount && !bFound; i++)
597                     if ( *ppRowHeaders[i] == aTitle )
598                     {
599                         nPos = static_cast<SCROW>(i);
600                         bFound = sal_True;
601                     }
602                 DBG_ASSERT(bFound, "Zeile nicht gefunden");
603             }
604             pDestRows[nRow-nStartRow] = nPos;
605         }
606     }
607     nCol1 = nStartCol;
608     nRow1 = nStartRow;
609 
610     //      Daten
611 
612     sal_Bool bAnyCell = ( eFunction == SUBTOTAL_FUNC_CNT2 );
613     for (nCol=nCol1; nCol<=nCol2; nCol++)
614     {
615         SCCOL nArrX = nCol-nCol1;
616         if (bColByName) nArrX = pDestCols[nArrX];
617         if (nArrX != SC_CONS_NOTFOUND)
618         {
619             for (nRow=nRow1; nRow<=nRow2; nRow++)
620             {
621                 SCROW nArrY = nRow-nRow1;
622                 if (bRowByName) nArrY = pDestRows[nArrY];
623                 if ( nArrY != SC_CONS_NOTFOUND && (
624                         bAnyCell ? pSrcDoc->HasData( nCol, nRow, nTab )
625                                  : pSrcDoc->HasValueData( nCol, nRow, nTab ) ) )
626                 {
627                     if (bReference)
628                     {
629                         if (ppUsed[nArrX][nArrY])
630                             ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab );
631                         else
632                         {
633                             ppUsed[nArrX][nArrY] = sal_True;
634                             ppRefs[nArrX][nArrY].Init();
635                             ppRefs[nArrX][nArrY].AddEntry( nCol, nRow, nTab );
636                         }
637                     }
638                     else
639                     {
640                         double nVal;
641                         pSrcDoc->GetValue( nCol, nRow, nTab, nVal );
642                         if (ppUsed[nArrX][nArrY])
643                             lcl_UpdateArray( eFunction, ppCount[nArrX][nArrY],
644                                          ppSum[nArrX][nArrY], ppSumSqr[nArrX][nArrY],
645                                          nVal);
646                         else
647                         {
648                             ppUsed[nArrX][nArrY] = sal_True;
649                             lcl_InitArray( eFunction, ppCount[nArrX][nArrY],
650                                                   ppSum[nArrX][nArrY],
651                                                   ppSumSqr[nArrX][nArrY], nVal );
652                         }
653                     }
654                 }
655             }
656         }
657     }
658 
659     delete[] pDestCols;
660     delete[] pDestRows;
661 }
662 
663 //  vorher testen, wieviele Zeilen eingefuegt werden (fuer Undo)
664 
GetInsertCount() const665 SCROW ScConsData::GetInsertCount() const
666 {
667     SCROW nInsert = 0;
668     SCSIZE nArrX;
669     SCSIZE nArrY;
670     if ( ppRefs && ppUsed )
671     {
672         for (nArrY=0; nArrY<nRowCount; nArrY++)
673         {
674             SCSIZE nNeeded = 0;
675             for (nArrX=0; nArrX<nColCount; nArrX++)
676                 if (ppUsed[nArrX][nArrY])
677                     nNeeded = Max( nNeeded, ppRefs[nArrX][nArrY].GetCount() );
678 
679             nInsert += nNeeded;
680         }
681     }
682     return nInsert;
683 }
684 
685 //  fertige Daten ins Dokument schreiben
686 //! optimieren nach Spalten?
687 
OutputToDocument(ScDocument * pDestDoc,SCCOL nCol,SCROW nRow,SCTAB nTab)688 void ScConsData::OutputToDocument( ScDocument* pDestDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
689 {
690     OpCode eOpCode = eOpCodeTable[eFunction];
691 
692     SCSIZE nArrX;
693     SCSIZE nArrY;
694 
695     //  Ecke links oben
696 
697     if ( bColByName && bRowByName && aCornerText.Len() )
698         pDestDoc->SetString( nCol, nRow, nTab, aCornerText );
699 
700     //  Titel
701 
702     SCCOL nStartCol = nCol;
703     SCROW nStartRow = nRow;
704     if (bColByName) ++nStartRow;
705     if (bRowByName) ++nStartCol;
706 
707     if (bColByName)
708         for (SCSIZE i=0; i<nColCount; i++)
709             pDestDoc->SetString( sal::static_int_cast<SCCOL>(nStartCol+i), nRow, nTab, *ppColHeaders[i] );
710     if (bRowByName)
711         for (SCSIZE j=0; j<nRowCount; j++)
712             pDestDoc->SetString( nCol, sal::static_int_cast<SCROW>(nStartRow+j), nTab, *ppRowHeaders[j] );
713 
714     nCol = nStartCol;
715     nRow = nStartRow;
716 
717     //  Daten
718 
719     if ( ppCount && ppUsed )                            // Werte direkt einfuegen
720     {
721         for (nArrX=0; nArrX<nColCount; nArrX++)
722             for (nArrY=0; nArrY<nRowCount; nArrY++)
723                 if (ppUsed[nArrX][nArrY])
724                 {
725                     double fVal = lcl_CalcData( eFunction, ppCount[nArrX][nArrY],
726                                                 ppSum[nArrX][nArrY],
727                                                 ppSumSqr[nArrX][nArrY]);
728                     if (ppCount[nArrX][nArrY] < 0.0)
729                         pDestDoc->SetError( sal::static_int_cast<SCCOL>(nCol+nArrX),
730                                             sal::static_int_cast<SCROW>(nRow+nArrY), nTab, errNoValue );
731                     else
732                         pDestDoc->SetValue( sal::static_int_cast<SCCOL>(nCol+nArrX),
733                                             sal::static_int_cast<SCROW>(nRow+nArrY), nTab, fVal );
734                 }
735     }
736 
737     if ( ppRefs && ppUsed )                             // Referenzen einfuegen
738     {
739                                 //! unterscheiden, ob nach Kategorien aufgeteilt
740         String aString;
741 
742         ScSingleRefData aSRef;      // Daten fuer Referenz-Formelzellen
743         aSRef.InitFlags();
744         aSRef.SetFlag3D(sal_True);
745 
746         ScComplexRefData aCRef;         // Daten fuer Summen-Zellen
747         aCRef.InitFlags();
748         aCRef.Ref1.SetColRel(sal_True); aCRef.Ref1.SetRowRel(sal_True); aCRef.Ref1.SetTabRel(sal_True);
749         aCRef.Ref2.SetColRel(sal_True); aCRef.Ref2.SetRowRel(sal_True); aCRef.Ref2.SetTabRel(sal_True);
750 
751         for (nArrY=0; nArrY<nRowCount; nArrY++)
752         {
753             SCSIZE nNeeded = 0;
754             for (nArrX=0; nArrX<nColCount; nArrX++)
755                 if (ppUsed[nArrX][nArrY])
756                     nNeeded = Max( nNeeded, ppRefs[nArrX][nArrY].GetCount() );
757 
758             if (nNeeded)
759             {
760                 pDestDoc->InsertRow( 0,nTab, MAXCOL,nTab, nRow+nArrY, nNeeded );
761 
762                 for (nArrX=0; nArrX<nColCount; nArrX++)
763                     if (ppUsed[nArrX][nArrY])
764                     {
765                         ScReferenceList& rList = ppRefs[nArrX][nArrY];
766                         SCSIZE nCount = rList.GetCount();
767                         if (nCount)
768                         {
769                             for (SCSIZE nPos=0; nPos<nCount; nPos++)
770                             {
771                                 ScReferenceEntry aRef = rList.GetEntry(nPos);
772                                 if (aRef.nTab != SC_CONS_NOTFOUND)
773                                 {
774                                     //  Referenz einfuegen (absolut, 3d)
775 
776                                     aSRef.nCol = aRef.nCol;
777                                     aSRef.nRow = aRef.nRow;
778                                     aSRef.nTab = aRef.nTab;
779 
780                                     ScTokenArray aRefArr;
781                                     aRefArr.AddSingleReference(aSRef);
782                                     aRefArr.AddOpCode(ocStop);
783                                     ScAddress aDest( sal::static_int_cast<SCCOL>(nCol+nArrX),
784                                                      sal::static_int_cast<SCROW>(nRow+nArrY+nPos), nTab );
785                                     ScBaseCell* pCell = new ScFormulaCell( pDestDoc, aDest, &aRefArr );
786                                     pDestDoc->PutCell( aDest.Col(), aDest.Row(), aDest.Tab(), pCell );
787                                 }
788                             }
789 
790                             //  Summe einfuegen (relativ, nicht 3d)
791 
792                             ScAddress aDest( sal::static_int_cast<SCCOL>(nCol+nArrX),
793                                              sal::static_int_cast<SCROW>(nRow+nArrY+nNeeded), nTab );
794 
795                             aCRef.Ref1.nTab = aCRef.Ref2.nTab = nTab;
796                             aCRef.Ref1.nCol = aCRef.Ref2.nCol = sal::static_int_cast<SCsCOL>( nCol+nArrX );
797                             aCRef.Ref1.nRow = nRow+nArrY;
798                             aCRef.Ref2.nRow = nRow+nArrY+nNeeded-1;
799                             aCRef.CalcRelFromAbs( aDest );
800 
801                             ScTokenArray aArr;
802                             aArr.AddOpCode(eOpCode);            // ausgewaehlte Funktion
803                             aArr.AddOpCode(ocOpen);
804                             aArr.AddDoubleReference(aCRef);
805                             aArr.AddOpCode(ocClose);
806                             aArr.AddOpCode(ocStop);
807                             ScBaseCell* pCell = new ScFormulaCell( pDestDoc, aDest, &aArr );
808                             pDestDoc->PutCell( aDest.Col(), aDest.Row(), aDest.Tab(), pCell );
809                         }
810                     }
811 
812                 //  Gliederung einfuegen
813 
814                 ScOutlineArray* pOutArr = pDestDoc->GetOutlineTable( nTab, sal_True )->GetRowArray();
815                 SCROW nOutStart = nRow+nArrY;
816                 SCROW nOutEnd = nRow+nArrY+nNeeded-1;
817                 sal_Bool bSize = sal_False;
818                 pOutArr->Insert( nOutStart, nOutEnd, bSize );
819                 for (SCROW nOutRow=nOutStart; nOutRow<=nOutEnd; nOutRow++)
820                     pDestDoc->ShowRow( nOutRow, nTab, sal_False );
821                 pDestDoc->UpdateOutlineRow( nOutStart, nOutEnd, nTab, sal_False );
822 
823                 //  Zwischentitel
824 
825                 if (ppTitlePos && ppTitles && ppRowHeaders)
826                 {
827                     String aDelim( RTL_CONSTASCII_USTRINGPARAM(" / ") );
828                     for (SCSIZE nPos=0; nPos<nDataCount; nPos++)
829                     {
830                         SCSIZE nTPos = ppTitlePos[nArrY][nPos];
831                         sal_Bool bDo = sal_True;
832                         if (nPos+1<nDataCount)
833                             if (ppTitlePos[nArrY][nPos+1] == nTPos)
834                                 bDo = sal_False;                                    // leer
835                         if ( bDo && nTPos < nNeeded )
836                         {
837                             aString =  *ppRowHeaders[nArrY];
838                             aString += aDelim;
839                             aString += *ppTitles[nPos];
840                             pDestDoc->SetString( nCol-1, nRow+nArrY+nTPos, nTab, aString );
841                         }
842                     }
843                 }
844 
845                 nRow += nNeeded;
846             }
847         }
848     }
849 }
850 
851 
852 
853 
854 
855