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