xref: /aoo41x/main/sc/source/core/tool/consoli.cxx (revision cdf0e10c)
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