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